Commit 16438ad2 authored by Douwe Maan's avatar Douwe Maan

Merge branch 'master' into dbalexandre/gitlab-ce-fix-personal-snippet-access-workflow

parents 8434e78b df0110ba
...@@ -37,8 +37,10 @@ nohup.out ...@@ -37,8 +37,10 @@ nohup.out
public/assets/ public/assets/
public/uploads.* public/uploads.*
public/uploads/ public/uploads/
shared/artifacts/
rails_best_practices_output.html rails_best_practices_output.html
/tags /tags
tmp/ tmp/
vendor/bundle/* vendor/bundle/*
builds/* builds/*
shared/*
...@@ -73,3 +73,18 @@ brakeman: ...@@ -73,3 +73,18 @@ brakeman:
tags: tags:
- ruby - ruby
- mysql - mysql
flog:
script:
- bundle exec rake flog
tags:
- ruby
- mysql
flay:
script:
- bundle exec rake flay
tags:
- ruby
- mysql
allow_failure: true
Please view this file on the master branch, on stable branches it's out of date. Please view this file on the master branch, on stable branches it's out of date.
v 8.2.0 (unreleased) v 8.2.0 (unreleased)
- 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) - 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) - Upgrade gitlab_git to 7.2.20 and rugged to 0.23.3 (Stan Hu)
- Fix bug where manually merged branches in a MR would end up with an empty diff (Stan Hu)
- Force update refs/merge-requests/X/head upon a push to the source branch of a merge request (Stan Hu)
- Improved performance of finding users by one of their Email addresses - 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 - Improved performance of replacing references in comments
- Show last project commit to default branch on project home page - Show last project commit to default branch on project home page
- Highlight comment based on anchor in URL - Highlight comment based on anchor in URL
...@@ -16,24 +18,41 @@ v 8.2.0 (unreleased) ...@@ -16,24 +18,41 @@ v 8.2.0 (unreleased)
- Fix: Inability to reply to code comments in the MR view, if the MR comes from a fork - 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 - Use git follow flag for commits page when retrieve history for file or directory
- Show merge request CI status on merge requests index page - 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 - Extend yml syntax for only and except to support specifying repository path
- Enable shared runners to all new projects - 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) - Fix: 500 error returned if destroy request without HTTP referer (Kazuki Shimizu)
- Remove deprecated CI events from project settings page - Remove deprecated CI events from project settings page
- Use issue editor as cross reference comment author when issue is edited with a new mention. - Use issue editor as cross reference comment author when issue is edited with a new mention.
- Improve personal snippet access workflow - Improve personal snippet access workflow
- [API] Add ability to fetch the commit ID of the last commit that actually touched a file - [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 - Add "New file" link to dropdown on project page
- Include commit logs in project search - Include commit logs in project search
- Add "added", "modified" and "removed" properties to commit object in webhook - 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 - 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 - Allow groups to appear in the search results if the group owner allows it
- New design for project graphs page - New design for project graphs page
- Remove deprecated dumped yaml file generated from previous job definitions
- Fix incoming email config defaults - 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 v 8.1.4
- Fix bug where manually merged branches in a MR would end up with an empty diff (Stan Hu) - 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 - 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 v 8.1.3
- Force update refs/merge-requests/X/head upon a push to the source branch of a merge request (Stan Hu) - Force update refs/merge-requests/X/head upon a push to the source branch of a merge request (Stan Hu)
...@@ -41,7 +60,7 @@ v 8.1.3 ...@@ -41,7 +60,7 @@ v 8.1.3
- Use issue editor as cross reference comment author when issue is edited with a new mention - Use issue editor as cross reference comment author when issue is edited with a new mention
- Add Facebook authentication - Add Facebook authentication
v 8.1.1 v 8.1.2
- Fix cloning Wiki repositories via HTTP (Stan Hu) - Fix cloning Wiki repositories via HTTP (Stan Hu)
- Add migration to remove satellites directory - Add migration to remove satellites directory
- Fix specific runners visibility - Fix specific runners visibility
...@@ -51,14 +70,15 @@ v 8.1.1 ...@@ -51,14 +70,15 @@ v 8.1.1
- Fix CI badge - Fix CI badge
- Allow developer to manage builds - Allow developer to manage builds
v 8.1.1
- Removed, see 8.1.2
v 8.1.0 v 8.1.0
- Ensure MySQL CI limits DB migrations occur after the fields have been created (Stan Hu) - Ensure MySQL CI limits DB migrations occur after the fields have been created (Stan Hu)
- Fix duplicate repositories in GitHub import page (Stan Hu) - Fix duplicate repositories in GitHub import page (Stan Hu)
- Redirect to a default path if HTTP_REFERER is not set (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) - Adds ability to create directories using the web editor (Ben Ford)
- Cleanup stuck CI builds - Cleanup stuck CI builds
v 8.1.0 (unreleased)
- Send an email to admin email when a user is reported for spam (Jonathan Rochkind) - 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) - 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. - Fix bug preventing mentioned issued from being closed when MR is merged using fast-forward merge.
...@@ -96,6 +116,7 @@ v 8.1.0 (unreleased) ...@@ -96,6 +116,7 @@ v 8.1.0 (unreleased)
- Show CI status on Your projects page and Starred projects page - Show CI status on Your projects page and Starred projects page
- Remove "Continuous Integration" page from dashboard - Remove "Continuous Integration" page from dashboard
- Add notes and SSL verification entries to hook APIs (Ben Boeckel) - 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. - Fix grammar in admin area "labels" .nothing-here-block when no labels exist.
- Move CI runners page to project settings area - Move CI runners page to project settings area
- Move CI variables 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 ...@@ -10,7 +10,7 @@ By submitting code as an individual you agree to the [individual contributor lic
## Security vulnerability disclosure ## 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 ## 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 ...@@ -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. 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 ### Issue tracker guidelines
...@@ -72,7 +72,7 @@ If you can, please submit a merge request with the fix or improvements including ...@@ -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. Write [tests](https://gitlab.com/gitlab-org/gitlab-development-kit#running-the-tests) and code
1. Add your changes to the [CHANGELOG](CHANGELOG) 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 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. Push the commit to your fork
1. Submit a merge request (MR) to the master branch 1. Submit a merge request (MR) to the master branch
1. The MR title should describe the change you want to make 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 ...@@ -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 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/)
...@@ -54,7 +54,7 @@ gem 'gollum-lib', '~> 4.0.2' ...@@ -54,7 +54,7 @@ gem 'gollum-lib', '~> 4.0.2'
gem "github-linguist", "~> 4.7.0", require: "linguist" gem "github-linguist", "~> 4.7.0", require: "linguist"
# API # API
gem 'grape', '~> 0.6.1' gem 'grape', '~> 0.13.0'
gem 'grape-entity', '~> 0.4.2' gem 'grape-entity', '~> 0.4.2'
gem 'rack-cors', '~> 0.4.0', require: 'rack/cors' gem 'rack-cors', '~> 0.4.0', require: 'rack/cors'
...@@ -109,7 +109,7 @@ group :unicorn do ...@@ -109,7 +109,7 @@ group :unicorn do
end end
# State machine # State machine
gem "state_machine", '~> 1.2.0' gem "state_machines-activerecord", '~> 0.3.0'
# Run events after state machine commits # Run events after state machine commits
gem 'after_commit_queue' gem 'after_commit_queue'
...@@ -259,6 +259,8 @@ group :development, :test do ...@@ -259,6 +259,8 @@ group :development, :test do
gem 'rubocop', '~> 0.28.0', require: false gem 'rubocop', '~> 0.28.0', require: false
gem 'coveralls', '~> 0.8.2', require: false gem 'coveralls', '~> 0.8.2', require: false
gem 'simplecov', '~> 0.10.0', require: false gem 'simplecov', '~> 0.10.0', require: false
gem 'flog', require: false
gem 'flay', require: false
gem 'benchmark-ips', require: false gem 'benchmark-ips', require: false
end end
......
...@@ -107,7 +107,7 @@ GEM ...@@ -107,7 +107,7 @@ GEM
json (>= 1.7) json (>= 1.7)
celluloid (0.16.0) celluloid (0.16.0)
timers (~> 4.0.0) timers (~> 4.0.0)
charlock_holmes (0.6.9.4) charlock_holmes (0.7.3)
chunky_png (1.3.4) chunky_png (1.3.4)
cliver (0.3.2) cliver (0.3.2)
coderay (1.1.0) coderay (1.1.0)
...@@ -194,6 +194,12 @@ GEM ...@@ -194,6 +194,12 @@ GEM
ffi (1.9.10) ffi (1.9.10)
fission (0.5.0) fission (0.5.0)
CFPropertyList (~> 2.2) 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) flowdock (0.7.0)
httparty (~> 0.7) httparty (~> 0.7)
multi_json multi_json
...@@ -306,10 +312,10 @@ GEM ...@@ -306,10 +312,10 @@ GEM
gon (5.0.4) gon (5.0.4)
actionpack (>= 2.3.0) actionpack (>= 2.3.0)
json json
grape (0.6.1) grape (0.13.0)
activesupport activesupport
builder builder
hashie (>= 1.2.0) hashie (>= 2.1.0)
multi_json (>= 1.3.2) multi_json (>= 1.3.2)
multi_xml (>= 0.5.2) multi_xml (>= 0.5.2)
rack (>= 1.3.0) rack (>= 1.3.0)
...@@ -611,7 +617,7 @@ GEM ...@@ -611,7 +617,7 @@ GEM
sexp_processor (~> 4.1) sexp_processor (~> 4.1)
rubyntlm (0.5.2) rubyntlm (0.5.2)
rubypants (0.2.0) rubypants (0.2.0)
rugged (0.22.2) rugged (0.23.3)
safe_yaml (1.0.4) safe_yaml (1.0.4)
sanitize (2.1.0) sanitize (2.1.0)
nokogiri (>= 1.4.4) nokogiri (>= 1.4.4)
...@@ -686,7 +692,13 @@ GEM ...@@ -686,7 +692,13 @@ GEM
activesupport (>= 3.0) activesupport (>= 3.0)
sprockets (>= 2.8, < 4.0) sprockets (>= 2.8, < 4.0)
stamp (0.6.0) stamp (0.6.0)
state_machine (1.2.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) stringex (2.5.2)
systemu (2.6.5) systemu (2.6.5)
task_list (1.0.2) task_list (1.0.2)
...@@ -815,6 +827,8 @@ DEPENDENCIES ...@@ -815,6 +827,8 @@ DEPENDENCIES
enumerize (~> 0.7.0) enumerize (~> 0.7.0)
factory_girl_rails (~> 4.3.0) factory_girl_rails (~> 4.3.0)
ffaker (~> 2.0.0) ffaker (~> 2.0.0)
flay
flog
fog (~> 1.25.0) fog (~> 1.25.0)
font-awesome-rails (~> 4.2) font-awesome-rails (~> 4.2)
foreman foreman
...@@ -829,7 +843,7 @@ DEPENDENCIES ...@@ -829,7 +843,7 @@ DEPENDENCIES
gitlab_omniauth-ldap (~> 1.2.1) gitlab_omniauth-ldap (~> 1.2.1)
gollum-lib (~> 4.0.2) gollum-lib (~> 4.0.2)
gon (~> 5.0.0) gon (~> 5.0.0)
grape (~> 0.6.1) grape (~> 0.13.0)
grape-entity (~> 0.4.2) grape-entity (~> 0.4.2)
haml-rails (~> 0.9.0) haml-rails (~> 0.9.0)
hipchat (~> 1.5.0) hipchat (~> 1.5.0)
...@@ -905,7 +919,7 @@ DEPENDENCIES ...@@ -905,7 +919,7 @@ DEPENDENCIES
spring-commands-teaspoon (~> 0.0.2) spring-commands-teaspoon (~> 0.0.2)
sprockets (~> 2.12.3) sprockets (~> 2.12.3)
stamp (~> 0.6.0) stamp (~> 0.6.0)
state_machine (~> 1.2.0) state_machines-activerecord (~> 0.3.0)
task_list (~> 1.0.2) task_list (~> 1.0.2)
teaspoon (~> 1.0.0) teaspoon (~> 1.0.0)
teaspoon-jasmine (~> 2.2.0) teaspoon-jasmine (~> 2.2.0)
......
...@@ -28,6 +28,8 @@ class Dispatcher ...@@ -28,6 +28,8 @@ class Dispatcher
when 'projects:milestones:new', 'projects:milestones:edit' when 'projects:milestones:new', 'projects:milestones:edit'
new ZenMode() new ZenMode()
new DropzoneInput($('.milestone-form')) new DropzoneInput($('.milestone-form'))
when 'groups:milestones:new'
new ZenMode()
when 'projects:compare:show' when 'projects:compare:show'
new Diff() new Diff()
when 'projects:issues:new','projects:issues:edit' when 'projects:issues:new','projects:issues:edit'
...@@ -39,6 +41,12 @@ class Dispatcher ...@@ -39,6 +41,12 @@ class Dispatcher
shortcut_handler = new ShortcutsNavigation() shortcut_handler = new ShortcutsNavigation()
new DropzoneInput($('.merge-request-form')) new DropzoneInput($('.merge-request-form'))
new IssuableForm($('.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' when 'projects:merge_requests:show'
new Diff() new Diff()
shortcut_handler = new ShortcutsIssuable() shortcut_handler = new ShortcutsIssuable()
......
...@@ -9,9 +9,9 @@ ...@@ -9,9 +9,9 @@
.bs-callout { .bs-callout {
margin: 20px 0; margin: 20px 0;
padding: 20px; padding: 20px;
border-left: 3px solid #eee; border-left: 3px solid $border-color;
color: #666; color: $text-color;
background: #f9f9f9; background: $background-color;
} }
.bs-callout h4 { .bs-callout h4 {
margin-top: 0; margin-top: 0;
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
.append-bottom-10 { margin-bottom:10px } .append-bottom-10 { margin-bottom:10px }
.append-bottom-15 { margin-bottom:15px } .append-bottom-15 { margin-bottom:15px }
.append-bottom-20 { margin-bottom:20px } .append-bottom-20 { margin-bottom:20px }
.append-bottom-default { margin-bottom: $gl-padding; }
.inline { display: inline-block } .inline { display: inline-block }
.center { text-align: center } .center { text-align: center }
......
...@@ -118,6 +118,10 @@ header { ...@@ -118,6 +118,10 @@ header {
} }
} }
} }
.impersonation i {
color: $red-normal;
}
} }
@mixin collapsed-header { @mixin collapsed-header {
......
...@@ -5,7 +5,6 @@ html { ...@@ -5,7 +5,6 @@ html {
body { body {
padding-top: $header-height; padding-top: $header-height;
text-rendering: geometricPrecision;
} }
} }
......
...@@ -117,7 +117,7 @@ ul.content-list { ...@@ -117,7 +117,7 @@ ul.content-list {
} }
.controls { .controls {
padding-top: 4px; padding-top: 1px;
float: right; float: right;
.btn { .btn {
......
...@@ -72,9 +72,10 @@ ...@@ -72,9 +72,10 @@
list-style: none; list-style: none;
> li { > li {
@include clearfix;
padding: 10px 0; padding: 10px 0;
border-bottom: 1px solid #EEE; border-bottom: 1px solid #EEE;
overflow: hidden;
display: block; display: block;
margin: 0px; margin: 0px;
......
...@@ -173,7 +173,6 @@ ...@@ -173,7 +173,6 @@
* *
*/ */
body { body {
text-rendering:optimizeLegibility;
-webkit-text-shadow: rgba(255,255,255,0.01) 0 0 1px; -webkit-text-shadow: rgba(255,255,255,0.01) 0 0 1px;
} }
......
...@@ -115,3 +115,10 @@ li.commit { ...@@ -115,3 +115,10 @@ li.commit {
} }
} }
} }
.branch-commit {
color: $gl-gray;
.commit-id, .commit-row-message {
color: $gl-gray;
}
}
...@@ -8,4 +8,10 @@ class Admin::ApplicationController < ApplicationController ...@@ -8,4 +8,10 @@ class Admin::ApplicationController < ApplicationController
def authenticate_admin! def authenticate_admin!
return render_404 unless current_user.is_admin? return render_404 unless current_user.is_admin?
end end
def authorize_impersonator!
if session[:impersonator_id]
User.find_by!(username: session[:impersonator_id]).admin?
end
end
end end
...@@ -58,6 +58,7 @@ class Admin::ApplicationSettingsController < Admin::ApplicationController ...@@ -58,6 +58,7 @@ class Admin::ApplicationSettingsController < Admin::ApplicationController
:admin_notification_email, :admin_notification_email,
:user_oauth_applications, :user_oauth_applications,
:shared_runners_enabled, :shared_runners_enabled,
:max_artifacts_size,
restricted_visibility_levels: [], restricted_visibility_levels: [],
import_sources: [] 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 ...@@ -63,12 +63,6 @@ class Admin::UsersController < Admin::ApplicationController
end end
end end
def login_as
sign_in(user)
flash[:alert] = "Logged in as #{user.username}"
redirect_to root_path
end
def disable_two_factor def disable_two_factor
user.disable_two_factor! user.disable_two_factor!
redirect_to admin_user_path(user), redirect_to admin_user_path(user),
......
...@@ -26,10 +26,6 @@ module Ci ...@@ -26,10 +26,6 @@ module Ci
redirect_to namespace_project_runners_path(project.gl_project.namespace, project.gl_project) redirect_to namespace_project_runners_path(project.gl_project.namespace, project.gl_project)
end end
def dumped_yaml
send_data @project.generated_yaml_config, filename: '.gitlab-ci.yml'
end
protected protected
def project 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 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 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 end
def show def show
project_milestones = Milestone.where(project_id: @projects).order("due_date ASC")
@dashboard_milestone = Milestones::GroupService.new(project_milestones).milestone(title)
end end
private private
def load_projects def projects
@projects = current_user.authorized_projects.sorted_by_activity.non_archived @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")
end end
end end
class DashboardController < Dashboard::ApplicationController class DashboardController < Dashboard::ApplicationController
before_action :event_filter, only: :activity before_action :event_filter, only: :activity
before_action :projects, only: [:issues, :merge_requests]
respond_to :html respond_to :html
...@@ -47,4 +48,8 @@ class DashboardController < Dashboard::ApplicationController ...@@ -47,4 +48,8 @@ class DashboardController < Dashboard::ApplicationController
@events = @event_filter.apply_filter(@events).with_associations @events = @event_filter.apply_filter(@events).with_associations
@events = @events.limit(20).offset(params[:offset] || 0) @events = @events.limit(20).offset(params[:offset] || 0)
end end
def projects
@projects ||= current_user.authorized_projects.sorted_by_activity.non_archived
end
end end
class Groups::ApplicationController < ApplicationController class Groups::ApplicationController < ApplicationController
layout 'group' layout 'group'
before_action :group
private private
def group
@group ||= Group.find_by(path: params[:group_id])
end
def authorize_read_group! def authorize_read_group!
unless @group and can?(current_user, :read_group, @group) unless @group and can?(current_user, :read_group, @group)
if current_user.nil? if current_user.nil?
...@@ -12,13 +17,13 @@ class Groups::ApplicationController < ApplicationController ...@@ -12,13 +17,13 @@ class Groups::ApplicationController < ApplicationController
end end
end end
end end
def authorize_admin_group! def authorize_admin_group!
unless can?(current_user, :admin_group, group) unless can?(current_user, :admin_group, group)
return render_404 return render_404
end end
end end
def authorize_admin_group_member! def authorize_admin_group_member!
unless can?(current_user, :admin_group_member, group) unless can?(current_user, :admin_group_member, group)
return render_403 return render_403
......
class Groups::AvatarsController < ApplicationController class Groups::AvatarsController < Groups::ApplicationController
def destroy def destroy
@group = Group.find_by(path: params[:group_id])
@group.remove_avatar! @group.remove_avatar!
@group.save @group.save
redirect_to edit_group_path(@group) redirect_to edit_group_path(@group)
......
class Groups::GroupMembersController < Groups::ApplicationController class Groups::GroupMembersController < Groups::ApplicationController
skip_before_action :authenticate_user!, only: [:index] skip_before_action :authenticate_user!, only: [:index]
before_action :group
# Authorize # Authorize
before_action :authorize_read_group! before_action :authorize_read_group!
...@@ -80,10 +79,6 @@ class Groups::GroupMembersController < Groups::ApplicationController ...@@ -80,10 +79,6 @@ class Groups::GroupMembersController < Groups::ApplicationController
protected protected
def group
@group ||= Group.find_by(path: params[:group_id])
end
def member_params def member_params
params.require(:group_member).permit(:access_level, :user_id) params.require(:group_member).permit(:access_level, :user_id)
end end
......
class Groups::MilestonesController < Groups::ApplicationController 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 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 end
def show def new
project_milestones = Milestone.where(project_id: group.projects).order("due_date ASC") @milestone = Milestone.new
@group_milestone = Milestones::GroupService.new(project_milestones).milestone(title)
end end
def update def create
project_milestones = Milestone.where(project_id: group.projects).order("due_date ASC") project_ids = params[:milestone][:project_ids]
@group_milestones = Milestones::GroupService.new(project_milestones).milestone(title) title = milestone_params[:title]
@group_milestones.milestones.each do |milestone| @group.projects.where(id: project_ids).each do |project|
Milestones::UpdateService.new(milestone.project, current_user, params[:milestone]).execute(milestone) Milestones::CreateService.new(project, current_user, milestone_params).execute
end end
respond_to do |format| redirect_to milestone_path(title)
format.js end
format.html do
redirect_to group_milestones_path(group) def show
end end
def update
@milestone.milestones.each do |milestone|
Milestones::UpdateService.new(milestone.project, current_user, milestone_params).execute(milestone)
end end
redirect_back_or_default(default: milestone_path(@milestone.title))
end end
private private
def group def authorize_group_milestone!
@group ||= Group.find_by(path: params[:group_id]) return render_404 unless can?(current_user, :admin_milestones, group)
end end
def title def milestone_params
params[:title] params.require(:milestone).permit(:title, :description, :due_date, :state_event)
end end
def state(state = nil) def milestone_path(title)
conditions = { project_id: group.projects } group_milestone_path(@group, title.parameterize, title: title)
conditions.reverse_merge!(state: state) if state
Milestone.where(conditions).order("title ASC")
end end
def authorize_group_milestone! def projects
return render_404 unless can?(current_user, :admin_group, group) @projects ||= @group.projects
end end
end end
...@@ -29,7 +29,7 @@ class Projects::ApplicationController < ApplicationController ...@@ -29,7 +29,7 @@ class Projects::ApplicationController < ApplicationController
private private
def ci_enabled def ci_enabled
return render_404 unless @project.gitlab_ci? return render_404 unless @project.builds_enabled?
end end
def ci_project def ci_project
......
...@@ -3,6 +3,7 @@ class Projects::BuildsController < Projects::ApplicationController ...@@ -3,6 +3,7 @@ class Projects::BuildsController < Projects::ApplicationController
before_action :build, except: [:index, :cancel_all] before_action :build, except: [:index, :cancel_all]
before_action :authorize_manage_builds!, except: [:index, :show, :status] before_action :authorize_manage_builds!, except: [:index, :show, :status]
before_action :authorize_download_build_artifacts!, only: [:download]
layout "project" layout "project"
...@@ -51,6 +52,18 @@ class Projects::BuildsController < Projects::ApplicationController ...@@ -51,6 +52,18 @@ class Projects::BuildsController < Projects::ApplicationController
redirect_to build_path(build) redirect_to build_path(build)
end 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 def status
render json: @build.to_json(only: [:status, :id, :sha, :coverage], methods: :sha) render json: @build.to_json(only: [:status, :id, :sha, :coverage], methods: :sha)
end end
...@@ -67,6 +80,10 @@ class Projects::BuildsController < Projects::ApplicationController ...@@ -67,6 +80,10 @@ class Projects::BuildsController < Projects::ApplicationController
@build ||= ci_project.builds.unscoped.find_by!(id: params[:id]) @build ||= ci_project.builds.unscoped.find_by!(id: params[:id])
end end
def artifacts_file
build.artifacts_file
end
def build_path(build) def build_path(build)
namespace_project_build_path(build.gl_project.namespace, build.gl_project, build) namespace_project_build_path(build.gl_project.namespace, build.gl_project, build)
end end
...@@ -76,4 +93,14 @@ class Projects::BuildsController < Projects::ApplicationController ...@@ -76,4 +93,14 @@ class Projects::BuildsController < Projects::ApplicationController
return page_404 return page_404
end end
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 end
...@@ -12,9 +12,10 @@ class Projects::CompareController < Projects::ApplicationController ...@@ -12,9 +12,10 @@ class Projects::CompareController < Projects::ApplicationController
def show def show
base_ref = Addressable::URI.unescape(params[:from]) base_ref = Addressable::URI.unescape(params[:from])
@ref = head_ref = Addressable::URI.unescape(params[:to]) @ref = head_ref = Addressable::URI.unescape(params[:to])
diff_options = { ignore_whitespace_change: true } if params[:w] == '1'
compare_result = CompareService.new. compare_result = CompareService.new.
execute(@project, head_ref, @project, base_ref) execute(@project, head_ref, @project, base_ref, diff_options)
if compare_result if compare_result
@commits = Commit.decorate(compare_result.commits, @project) @commits = Commit.decorate(compare_result.commits, @project)
......
...@@ -158,10 +158,12 @@ class Projects::IssuesController < Projects::ApplicationController ...@@ -158,10 +158,12 @@ class Projects::IssuesController < Projects::ApplicationController
end end
def issue_params def issue_params
params.require(:issue).permit( permitted = params.require(:issue).permit(
:title, :assignee_id, :position, :description, :title, :assignee_id, :position, :description,
:milestone_id, :state_event, :task_num, label_ids: [] :milestone_id, :state_event, :task_num, label_ids: []
) )
params[:issue][:title].strip! if params[:issue][:title]
permitted
end end
def bulk_update_params def bulk_update_params
......
...@@ -31,6 +31,7 @@ class Projects::MergeRequestsController < Projects::ApplicationController ...@@ -31,6 +31,7 @@ class Projects::MergeRequestsController < Projects::ApplicationController
end end
@merge_requests = @merge_requests.page(params[:page]).per(PER_PAGE) @merge_requests = @merge_requests.page(params[:page]).per(PER_PAGE)
@merge_requests = @merge_requests.preload(:target_project)
respond_to do |format| respond_to do |format|
format.html format.html
...@@ -275,11 +276,13 @@ class Projects::MergeRequestsController < Projects::ApplicationController ...@@ -275,11 +276,13 @@ class Projects::MergeRequestsController < Projects::ApplicationController
end end
def merge_request_params def merge_request_params
params.require(:merge_request).permit( permitted = params.require(:merge_request).permit(
:title, :assignee_id, :source_project_id, :source_branch, :title, :assignee_id, :source_project_id, :source_branch,
:target_project_id, :target_branch, :milestone_id, :target_project_id, :target_branch, :milestone_id,
:state_event, :description, :task_num, label_ids: [] :state_event, :description, :task_num, label_ids: []
) )
params[:merge_request][:title].strip! if params[:merge_request][:title]
permitted
end end
# Make sure merge requests created before 8.0 # Make sure merge requests created before 8.0
......
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 ...@@ -8,15 +8,23 @@ class Projects::TagsController < Projects::ApplicationController
def index def index
sorted = VersionSorter.rsort(@repository.tag_names) sorted = VersionSorter.rsort(@repository.tag_names)
@tags = Kaminari.paginate_array(sorted).page(params[:page]).per(PER_PAGE) @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 end
def create def create
result = CreateTagService.new(@project, current_user). 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 if result[:status] == :success
@tag = result[:tag] @tag = result[:tag]
redirect_to namespace_project_tags_path(@project.namespace, @project)
redirect_to namespace_project_tag_path(@project.namespace, @project, @tag.name)
else else
@error = result[:message] @error = result[:message]
render action: 'new' render action: 'new'
...@@ -26,12 +34,6 @@ class Projects::TagsController < Projects::ApplicationController ...@@ -26,12 +34,6 @@ class Projects::TagsController < Projects::ApplicationController
def destroy def destroy
DeleteTagService.new(project, current_user).execute(params[:id]) DeleteTagService.new(project, current_user).execute(params[:id])
respond_to do |format| redirect_to namespace_project_tags_path(@project.namespace, @project)
format.html do
redirect_to namespace_project_tags_path(@project.namespace,
@project)
end
format.js
end
end end
end end
...@@ -72,8 +72,7 @@ class ProjectsController < ApplicationController ...@@ -72,8 +72,7 @@ class ProjectsController < ApplicationController
def remove_fork def remove_fork
return access_denied! unless can?(current_user, :remove_fork_project, @project) return access_denied! unless can?(current_user, :remove_fork_project, @project)
if @project.forked? if @project.unlink_fork
@project.forked_project_link.destroy
flash[:notice] = 'The fork relationship has been removed.' flash[:notice] = 'The fork relationship has been removed.'
end end
end end
...@@ -213,7 +212,8 @@ class ProjectsController < ApplicationController ...@@ -213,7 +212,8 @@ class ProjectsController < ApplicationController
params.require(:project).permit( params.require(:project).permit(
:name, :path, :description, :issues_tracker, :tag_list, :name, :path, :description, :issues_tracker, :tag_list,
:issues_enabled, :merge_requests_enabled, :snippets_enabled, :issues_tracker_id, :default_branch, :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 end
...@@ -242,7 +242,7 @@ class ProjectsController < ApplicationController ...@@ -242,7 +242,7 @@ class ProjectsController < ApplicationController
project.repository_exists? && !project.empty_repo? project.repository_exists? && !project.empty_repo?
end end
# Override get_id from ExtractsPath, which returns the branch and file path # Override get_id from ExtractsPath, which returns the branch and file path
# for the blob/tree, which in this case is just the root of the default branch. # for the blob/tree, which in this case is just the root of the default branch.
def get_id def get_id
project.repository.root_ref project.repository.root_ref
......
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
...@@ -108,19 +108,23 @@ module EventsHelper ...@@ -108,19 +108,23 @@ module EventsHelper
end end
end end
elsif event.push? elsif event.push?
if event.push_with_commits? && event.md_ref? push_event_feed_url(event)
if event.commits_count > 1 end
namespace_project_compare_url(event.project.namespace, event.project, end
from: event.commit_from, to:
event.commit_to) def push_event_feed_url(event)
else if event.push_with_commits? && event.md_ref?
namespace_project_commit_url(event.project.namespace, event.project, if event.commits_count > 1
id: event.commit_to) namespace_project_compare_url(event.project.namespace, event.project,
end from: event.commit_from, to:
event.commit_to)
else else
namespace_project_commits_url(event.project.namespace, event.project, namespace_project_commit_url(event.project.namespace, event.project,
event.ref_name) id: event.commit_to)
end end
else
namespace_project_commits_url(event.project.namespace, event.project,
event.ref_name)
end end
end end
...@@ -198,7 +202,7 @@ module EventsHelper ...@@ -198,7 +202,7 @@ module EventsHelper
xml.link href: event_link xml.link href: event_link
xml.title truncate(event_title, length: 80) xml.title truncate(event_title, length: 80)
xml.updated event.created_at.xmlschema 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.author do |author|
xml.name event.author_name xml.name event.author_name
xml.email event.author_email xml.email event.author_email
......
...@@ -74,7 +74,7 @@ module IssuesHelper ...@@ -74,7 +74,7 @@ module IssuesHelper
issue.project, issue) issue.project, issue)
xml.title truncate(issue.title, length: 80) xml.title truncate(issue.title, length: 80)
xml.updated issue.created_at.strftime("%Y-%m-%dT%H:%M:%SZ") 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.author do |author|
xml.name issue.author_name xml.name issue.author_name
xml.email issue.author_email xml.email issue.author_email
......
...@@ -100,7 +100,7 @@ module LabelsHelper ...@@ -100,7 +100,7 @@ module LabelsHelper
Label.where(project_id: @projects) Label.where(project_id: @projects)
end end
grouped_labels = Labels::GroupService.new(labels).execute grouped_labels = GlobalLabel.build_collection(labels)
grouped_labels.unshift(Label::None) grouped_labels.unshift(Label::None)
grouped_labels.unshift(Label::Any) grouped_labels.unshift(Label::Any)
......
...@@ -28,7 +28,7 @@ module MilestonesHelper ...@@ -28,7 +28,7 @@ module MilestonesHelper
Milestone.where(project_id: @projects) Milestone.where(project_id: @projects)
end.active end.active
grouped_milestones = Milestones::GroupService.new(milestones).execute grouped_milestones = GlobalMilestone.build_collection(milestones)
grouped_milestones.unshift(Milestone::None) grouped_milestones.unshift(Milestone::None)
grouped_milestones.unshift(Milestone::Any) grouped_milestones.unshift(Milestone::Any)
......
...@@ -16,40 +16,28 @@ module NotificationsHelper ...@@ -16,40 +16,28 @@ module NotificationsHelper
def notification_list_item(notification_level, user_membership) def notification_list_item(notification_level, user_membership)
case notification_level case notification_level
when Notification::N_DISABLED when Notification::N_DISABLED
content_tag(:li, class: active_level_for(user_membership, Notification::N_DISABLED)) do update_notification_link(Notification::N_DISABLED, user_membership, 'Disabled', 'microphone-slash')
link_to '#', class: 'update-notification', data: { notification_level: Notification::N_DISABLED } do
icon('microphone-slash fw', text: 'Disabled')
end
end
when Notification::N_PARTICIPATING when Notification::N_PARTICIPATING
content_tag(:li, class: active_level_for(user_membership, Notification::N_PARTICIPATING)) do update_notification_link(Notification::N_PARTICIPATING, user_membership, 'Participate', 'volume-up')
link_to '#', class: 'update-notification', data: { notification_level: Notification::N_PARTICIPATING } do
icon('volume-up fw', text: 'Participate')
end
end
when Notification::N_WATCH when Notification::N_WATCH
content_tag(:li, class: active_level_for(user_membership, Notification::N_WATCH)) do update_notification_link(Notification::N_WATCH, user_membership, 'Watch', 'eye')
link_to '#', class: 'update-notification', data: { notification_level: Notification::N_WATCH } do
icon('eye fw', text: 'Watch')
end
end
when Notification::N_MENTION when Notification::N_MENTION
content_tag(:li, class: active_level_for(user_membership, Notification::N_MENTION)) do update_notification_link(Notification::N_MENTION, user_membership, 'On mention', 'at')
link_to '#', class: 'update-notification', data: { notification_level: Notification::N_MENTION } do
icon('at fw', text: 'On mention')
end
end
when Notification::N_GLOBAL when Notification::N_GLOBAL
content_tag(:li, class: active_level_for(user_membership, Notification::N_GLOBAL)) do update_notification_link(Notification::N_GLOBAL, user_membership, 'Global', 'globe')
link_to '#', class: 'update-notification', data: { notification_level: Notification::N_GLOBAL } do
icon('globe fw', text: 'Global')
end
end
else else
# do nothing # do nothing
end end
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) def notification_label(user_membership)
Notification.new(user_membership).to_s Notification.new(user_membership).to_s
end end
......
...@@ -117,7 +117,7 @@ module ProjectsHelper ...@@ -117,7 +117,7 @@ module ProjectsHelper
nav_tabs << :merge_requests nav_tabs << :merge_requests
end end
if project.gitlab_ci? && can?(current_user, :read_build, project) if project.builds_enabled? && can?(current_user, :read_build, project)
nav_tabs << :builds nav_tabs << :builds
end end
......
...@@ -169,6 +169,7 @@ class Ability ...@@ -169,6 +169,7 @@ class Ability
:create_merge_request, :create_merge_request,
:create_wiki, :create_wiki,
:manage_builds, :manage_builds,
:download_build_artifacts,
:push_code :push_code
] ]
end end
...@@ -247,6 +248,7 @@ class Ability ...@@ -247,6 +248,7 @@ class Ability
if group.has_master?(user) || group.has_owner?(user) || user.admin? if group.has_master?(user) || group.has_owner?(user) || user.admin?
rules.push(*[ rules.push(*[
:create_projects, :create_projects,
:admin_milestones
]) ])
end end
......
...@@ -23,6 +23,10 @@ ...@@ -23,6 +23,10 @@
# after_sign_out_path :string(255) # after_sign_out_path :string(255)
# session_expire_delay :integer default(10080), not null # session_expire_delay :integer default(10080), not null
# import_sources :text # 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 class ApplicationSetting < ActiveRecord::Base
...@@ -68,8 +72,14 @@ class ApplicationSetting < ActiveRecord::Base ...@@ -68,8 +72,14 @@ class ApplicationSetting < ActiveRecord::Base
end end
end end
after_commit do
Rails.cache.write('application_setting.last', self)
end
def self.current def self.current
ApplicationSetting.last Rails.cache.fetch('application_setting.last') do
ApplicationSetting.last
end
end end
def self.create_from_defaults def self.create_from_defaults
...@@ -89,6 +99,7 @@ class ApplicationSetting < ActiveRecord::Base ...@@ -89,6 +99,7 @@ class ApplicationSetting < ActiveRecord::Base
restricted_signup_domains: Settings.gitlab['restricted_signup_domains'], 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'], shared_runners_enabled: Settings.gitlab_ci['shared_runners_enabled'],
max_artifacts_size: Settings.gitlab_ci['max_artifacts_size'],
) )
end end
......
# == Schema Information # == Schema Information
# #
# Table name: application_settings # Table name: ci_application_settings
# #
# id :integer not null, primary key # id :integer not null, primary key
# all_broken_builds :boolean # all_broken_builds :boolean
...@@ -12,9 +12,15 @@ ...@@ -12,9 +12,15 @@
module Ci module Ci
class ApplicationSetting < ActiveRecord::Base class ApplicationSetting < ActiveRecord::Base
extend Ci::Model extend Ci::Model
after_commit do
Rails.cache.write('ci_application_setting.last', self)
end
def self.current def self.current
Ci::ApplicationSetting.last Rails.cache.fetch('ci_application_setting.last') do
Ci::ApplicationSetting.last
end
end end
def self.create_from_defaults def self.create_from_defaults
......
# == Schema Information # == Schema Information
# #
# Table name: builds # Table name: ci_builds
# #
# id :integer not null, primary key # id :integer not null, primary key
# project_id :integer # project_id :integer
...@@ -11,16 +11,24 @@ ...@@ -11,16 +11,24 @@
# updated_at :datetime # updated_at :datetime
# started_at :datetime # started_at :datetime
# runner_id :integer # runner_id :integer
# commit_id :integer
# coverage :float # coverage :float
# commit_id :integer
# commands :text # commands :text
# job_id :integer # job_id :integer
# name :string(255) # name :string(255)
# deploy :boolean default(FALSE)
# options :text # options :text
# allow_failure :boolean default(FALSE), not null # allow_failure :boolean default(FALSE), not null
# stage :string(255) # stage :string(255)
# deploy :boolean default(FALSE)
# trigger_request_id :integer # 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 module Ci
...@@ -39,6 +47,8 @@ module Ci ...@@ -39,6 +47,8 @@ module Ci
scope :ignore_failures, ->() { where(allow_failure: false) } scope :ignore_failures, ->() { where(allow_failure: false) }
scope :similar, ->(build) { where(ref: build.ref, tag: build.tag, trigger_request_id: build.trigger_request_id) } 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 acts_as_taggable
# To prevent db load megabytes of data from trace # To prevent db load megabytes of data from trace
...@@ -217,6 +227,14 @@ module Ci ...@@ -217,6 +227,14 @@ module Ci
"#{dir_to_trace}/#{id}.log" "#{dir_to_trace}/#{id}.log"
end end
def token
project.token
end
def valid_token? token
project.valid_token? token
end
def target_url def target_url
Gitlab::Application.routes.url_helpers. Gitlab::Application.routes.url_helpers.
namespace_project_build_url(gl_project.namespace, gl_project, self) namespace_project_build_url(gl_project.namespace, gl_project, self)
...@@ -248,6 +266,13 @@ module Ci ...@@ -248,6 +266,13 @@ module Ci
pending? && !any_runners_online? pending? && !any_runners_online?
end 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 private
def yaml_variables def yaml_variables
......
# == Schema Information # == Schema Information
# #
# Table name: commits # Table name: ci_commits
# #
# id :integer not null, primary key # id :integer not null, primary key
# project_id :integer # project_id :integer
# ref :string(255) # ref :string(255)
# sha :string(255) # sha :string(255)
# before_sha :string(255) # before_sha :string(255)
# push_data :text # push_data :text
# created_at :datetime # created_at :datetime
# updated_at :datetime # updated_at :datetime
# tag :boolean default(FALSE) # tag :boolean default(FALSE)
# yaml_errors :text # yaml_errors :text
# committed_at :datetime # committed_at :datetime
# gl_project_id :integer
# #
module Ci module Ci
......
# == Schema Information # == Schema Information
# #
# Table name: events # Table name: ci_events
# #
# id :integer not null, primary key # id :integer not null, primary key
# project_id :integer # project_id :integer
......
# == Schema Information # == Schema Information
# #
# Table name: projects # Table name: ci_projects
# #
# id :integer not null, primary key # id :integer not null, primary key
# name :string(255) not null # name :string(255)
# timeout :integer default(3600), not null # timeout :integer default(3600), not null
# created_at :datetime # created_at :datetime
# updated_at :datetime # updated_at :datetime
...@@ -66,30 +66,6 @@ module Ci ...@@ -66,30 +66,6 @@ module Ci
class << self class << self
include Ci::CurrentSettings 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) def unassigned(runner)
joins("LEFT JOIN #{Ci::RunnerProject.table_name} ON #{Ci::RunnerProject.table_name}.project_id = #{Ci::Project.table_name}.id " \ 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}"). "AND #{Ci::RunnerProject.table_name}.runner_id = #{runner.id}").
......
# == Schema Information # == Schema Information
# #
# Table name: runners # Table name: ci_runners
# #
# id :integer not null, primary key # id :integer not null, primary key
# token :string(255) # token :string(255)
......
# == Schema Information # == Schema Information
# #
# Table name: runner_projects # Table name: ci_runner_projects
# #
# id :integer not null, primary key # id :integer not null, primary key
# runner_id :integer not null # runner_id :integer not null
......
# == Schema Information # == Schema Information
# #
# Table name: services # Table name: ci_services
# #
# id :integer not null, primary key # id :integer not null, primary key
# type :string(255) # type :string(255)
......
# == Schema Information # == Schema Information
# #
# Table name: triggers # Table name: ci_triggers
# #
# id :integer not null, primary key # id :integer not null, primary key
# token :string(255) # token :string(255)
......
# == Schema Information # == Schema Information
# #
# Table name: trigger_requests # Table name: ci_trigger_requests
# #
# id :integer not null, primary key # id :integer not null, primary key
# trigger_id :integer not null # trigger_id :integer not null
......
# == Schema Information # == Schema Information
# #
# Table name: variables # Table name: ci_variables
# #
# id :integer not null, primary key # id :integer not null, primary key
# project_id :integer not null # project_id :integer not null
......
# == Schema Information # == Schema Information
# #
# Table name: web_hooks # Table name: ci_web_hooks
# #
# id :integer not null, primary key # id :integer not null, primary key
# url :string(255) not null # 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 class CommitStatus < ActiveRecord::Base
self.table_name = 'ci_builds' self.table_name = 'ci_builds'
...@@ -92,4 +125,8 @@ class CommitStatus < ActiveRecord::Base ...@@ -92,4 +125,8 @@ class CommitStatus < ActiveRecord::Base
def show_warning? def show_warning?
false false
end end
def download_url
nil
end
end end
...@@ -24,7 +24,7 @@ module Issuable ...@@ -24,7 +24,7 @@ module Issuable
scope :authored, ->(user) { where(author_id: user) } scope :authored, ->(user) { where(author_id: user) }
scope :assigned_to, ->(u) { where(assignee_id: u.id)} 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 :assigned, -> { where("assignee_id IS NOT NULL") }
scope :unassigned, -> { where("assignee_id IS NULL") } scope :unassigned, -> { where("assignee_id IS NULL") }
scope :of_projects, ->(ids) { where(project_id: ids) } scope :of_projects, ->(ids) { where(project_id: ids) }
......
...@@ -45,7 +45,7 @@ class Event < ActiveRecord::Base ...@@ -45,7 +45,7 @@ class Event < ActiveRecord::Base
after_create :reset_project_activity after_create :reset_project_activity
# Scopes # Scopes
scope :recent, -> { order(created_at: :desc) } scope :recent, -> { reorder(id: :desc) }
scope :code_push, -> { where(action: PUSHED) } scope :code_push, -> { where(action: PUSHED) }
scope :in_projects, ->(project_ids) { where(project_id: project_ids).recent } scope :in_projects, ->(project_ids) { where(project_id: project_ids).recent }
scope :with_associations, -> { includes(project: :namespace) } 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 class GenericCommitStatus < CommitStatus
before_validation :set_default_values before_validation :set_default_values
......
class GroupLabel class GlobalLabel
attr_accessor :title, :labels attr_accessor :title, :labels
alias_attribute :name, :title alias_attribute :name, :title
def self.build_collection(labels)
labels = labels.group_by(&:title)
labels.map do |title, label|
new(title, label)
end
end
def initialize(title, labels) def initialize(title, labels)
@title = title @title = title
@labels = labels @labels = labels
......
class GroupMilestone class GlobalMilestone
attr_accessor :title, :milestones attr_accessor :title, :milestones
alias_attribute :name, :title alias_attribute :name, :title
def self.build_collection(milestones)
milestones = milestones.group_by(&:title)
milestones.map do |title, milestones|
new(title, milestones)
end
end
def initialize(title, milestones) def initialize(title, milestones)
@title = title @title = title
@milestones = milestones @milestones = milestones
...@@ -10,7 +18,7 @@ class GroupMilestone ...@@ -10,7 +18,7 @@ class GroupMilestone
def safe_title def safe_title
@title.parameterize @title.parameterize
end end
def projects def projects
milestones.map { |milestone| milestone.project } milestones.map { |milestone| milestone.project }
end end
...@@ -60,15 +68,15 @@ class GroupMilestone ...@@ -60,15 +68,15 @@ class GroupMilestone
end end
def issues def issues
@group_issues ||= milestones.map(&:issues).flatten.group_by(&:state) @issues ||= milestones.map(&:issues).flatten.group_by(&:state)
end end
def merge_requests def merge_requests
@group_merge_requests ||= milestones.map(&:merge_requests).flatten.group_by(&:state) @merge_requests ||= milestones.map(&:merge_requests).flatten.group_by(&:state)
end end
def participants def participants
@group_participants ||= milestones.map(&:participants).flatten.compact.uniq @participants ||= milestones.map(&:participants).flatten.compact.uniq
end end
def opened_issues def opened_issues
...@@ -86,4 +94,8 @@ class GroupMilestone ...@@ -86,4 +94,8 @@ class GroupMilestone
def closed_merge_requests def closed_merge_requests
merge_requests.values_at("closed", "merged", "locked").compact.flatten merge_requests.values_at("closed", "merged", "locked").compact.flatten
end end
def complete?
total_items_count == closed_items_count
end
end end
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
# type :string(255) # type :string(255)
# description :string(255) default(""), not null # description :string(255) default(""), not null
# avatar :string(255) # avatar :string(255)
# public :boolean default(FALSE)
# #
require 'carrierwave/orm/activerecord' require 'carrierwave/orm/activerecord'
......
...@@ -2,18 +2,19 @@ ...@@ -2,18 +2,19 @@
# #
# Table name: web_hooks # Table name: web_hooks
# #
# id :integer not null, primary key # id :integer not null, primary key
# url :string(255) # url :string(255)
# project_id :integer # project_id :integer
# created_at :datetime # created_at :datetime
# updated_at :datetime # updated_at :datetime
# type :string(255) default("ProjectHook") # type :string(255) default("ProjectHook")
# service_id :integer # service_id :integer
# push_events :boolean default(TRUE), not null # push_events :boolean default(TRUE), not null
# issues_events :boolean default(FALSE), not null # issues_events :boolean default(FALSE), not null
# merge_requests_events :boolean default(FALSE), not null # merge_requests_events :boolean default(FALSE), not null
# tag_push_events :boolean default(FALSE) # tag_push_events :boolean default(FALSE)
# note_events :boolean default(FALSE), not null # note_events :boolean default(FALSE), not null
# enable_ssl_verification :boolean default(TRUE)
# #
class ProjectHook < WebHook class ProjectHook < WebHook
......
...@@ -2,18 +2,19 @@ ...@@ -2,18 +2,19 @@
# #
# Table name: web_hooks # Table name: web_hooks
# #
# id :integer not null, primary key # id :integer not null, primary key
# url :string(255) # url :string(255)
# project_id :integer # project_id :integer
# created_at :datetime # created_at :datetime
# updated_at :datetime # updated_at :datetime
# type :string(255) default("ProjectHook") # type :string(255) default("ProjectHook")
# service_id :integer # service_id :integer
# push_events :boolean default(TRUE), not null # push_events :boolean default(TRUE), not null
# issues_events :boolean default(FALSE), not null # issues_events :boolean default(FALSE), not null
# merge_requests_events :boolean default(FALSE), not null # merge_requests_events :boolean default(FALSE), not null
# tag_push_events :boolean default(FALSE) # tag_push_events :boolean default(FALSE)
# note_events :boolean default(FALSE), not null # note_events :boolean default(FALSE), not null
# enable_ssl_verification :boolean default(TRUE)
# #
class ServiceHook < WebHook class ServiceHook < WebHook
......
...@@ -2,18 +2,19 @@ ...@@ -2,18 +2,19 @@
# #
# Table name: web_hooks # Table name: web_hooks
# #
# id :integer not null, primary key # id :integer not null, primary key
# url :string(255) # url :string(255)
# project_id :integer # project_id :integer
# created_at :datetime # created_at :datetime
# updated_at :datetime # updated_at :datetime
# type :string(255) default("ProjectHook") # type :string(255) default("ProjectHook")
# service_id :integer # service_id :integer
# push_events :boolean default(TRUE), not null # push_events :boolean default(TRUE), not null
# issues_events :boolean default(FALSE), not null # issues_events :boolean default(FALSE), not null
# merge_requests_events :boolean default(FALSE), not null # merge_requests_events :boolean default(FALSE), not null
# tag_push_events :boolean default(FALSE) # tag_push_events :boolean default(FALSE)
# note_events :boolean default(FALSE), not null # note_events :boolean default(FALSE), not null
# enable_ssl_verification :boolean default(TRUE)
# #
class SystemHook < WebHook class SystemHook < WebHook
......
...@@ -2,18 +2,19 @@ ...@@ -2,18 +2,19 @@
# #
# Table name: web_hooks # Table name: web_hooks
# #
# id :integer not null, primary key # id :integer not null, primary key
# url :string(255) # url :string(255)
# project_id :integer # project_id :integer
# created_at :datetime # created_at :datetime
# updated_at :datetime # updated_at :datetime
# type :string(255) default("ProjectHook") # type :string(255) default("ProjectHook")
# service_id :integer # service_id :integer
# push_events :boolean default(TRUE), not null # push_events :boolean default(TRUE), not null
# issues_events :boolean default(FALSE), not null # issues_events :boolean default(FALSE), not null
# merge_requests_events :boolean default(FALSE), not null # merge_requests_events :boolean default(FALSE), not null
# tag_push_events :boolean default(FALSE) # tag_push_events :boolean default(FALSE)
# note_events :boolean default(FALSE), not null # note_events :boolean default(FALSE), not null
# enable_ssl_verification :boolean default(TRUE)
# #
class WebHook < ActiveRecord::Base class WebHook < ActiveRecord::Base
......
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
# project_id :integer # project_id :integer
# created_at :datetime # created_at :datetime
# updated_at :datetime # updated_at :datetime
# template :boolean default(FALSE)
# #
class Label < ActiveRecord::Base class Label < ActiveRecord::Base
......
class LfsObject < ActiveRecord::Base
has_many :lfs_objects_projects, dependent: :destroy
has_many :projects, through: :lfs_objects_projects
validates :oid, presence: true, uniqueness: true
mount_uploader :file, LfsObjectUploader
end
class LfsObjectsProject < ActiveRecord::Base
belongs_to :project
belongs_to :lfs_object
validates :lfs_object_id, presence: true
validates :lfs_object_id, uniqueness: { scope: [:project_id], message: "already exists in project" }
validates :project_id, presence: true
end
...@@ -20,6 +20,7 @@ ...@@ -20,6 +20,7 @@
# position :integer default(0) # position :integer default(0)
# locked_at :datetime # locked_at :datetime
# updated_by_id :integer # updated_by_id :integer
# merge_error :string(255)
# #
require Rails.root.join("app/models/commit") require Rails.root.join("app/models/commit")
...@@ -40,7 +41,7 @@ class MergeRequest < ActiveRecord::Base ...@@ -40,7 +41,7 @@ class MergeRequest < ActiveRecord::Base
after_create :create_merge_request_diff after_create :create_merge_request_diff
after_update :update_merge_request_diff after_update :update_merge_request_diff
delegate :commits, :diffs, to: :merge_request_diff, prefix: nil delegate :commits, :diffs, :diffs_no_whitespace, to: :merge_request_diff, prefix: nil
# When this attribute is true some MR validation is ignored # When this attribute is true some MR validation is ignored
# It allows us to close or modify broken merge requests # It allows us to close or modify broken merge requests
......
...@@ -19,7 +19,7 @@ class MergeRequestDiff < ActiveRecord::Base ...@@ -19,7 +19,7 @@ class MergeRequestDiff < ActiveRecord::Base
# Prevent store of diff if commits amount more then 500 # Prevent store of diff if commits amount more then 500
COMMITS_SAFE_SIZE = 500 COMMITS_SAFE_SIZE = 500
attr_reader :commits, :diffs attr_reader :commits, :diffs, :diffs_no_whitespace
belongs_to :merge_request belongs_to :merge_request
...@@ -47,6 +47,20 @@ class MergeRequestDiff < ActiveRecord::Base ...@@ -47,6 +47,20 @@ class MergeRequestDiff < ActiveRecord::Base
@diffs ||= (load_diffs(st_diffs) || []) @diffs ||= (load_diffs(st_diffs) || [])
end end
def diffs_no_whitespace
# Get latest sha of branch from source project
source_sha = merge_request.source_project.commit(source_branch).sha
compare_result = Gitlab::CompareResult.new(
Gitlab::Git::Compare.new(
merge_request.target_project.repository.raw_repository,
merge_request.target_branch,
source_sha,
), { ignore_whitespace_change: true }
)
@diffs_no_whitespace ||= load_diffs(dump_commits(compare_result.diffs))
end
def commits def commits
@commits ||= load_commits(st_commits || []) @commits ||= load_commits(st_commits || [])
end end
......
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
# type :string(255) # type :string(255)
# description :string(255) default(""), not null # description :string(255) default(""), not null
# avatar :string(255) # avatar :string(255)
# public :boolean default(FALSE)
# #
class Namespace < ActiveRecord::Base class Namespace < ActiveRecord::Base
......
...@@ -52,6 +52,7 @@ class Project < ActiveRecord::Base ...@@ -52,6 +52,7 @@ class Project < ActiveRecord::Base
default_value_for :visibility_level, gitlab_config_features.visibility_level default_value_for :visibility_level, gitlab_config_features.visibility_level
default_value_for :issues_enabled, gitlab_config_features.issues default_value_for :issues_enabled, gitlab_config_features.issues
default_value_for :merge_requests_enabled, gitlab_config_features.merge_requests default_value_for :merge_requests_enabled, gitlab_config_features.merge_requests
default_value_for :builds_enabled, gitlab_config_features.builds
default_value_for :wiki_enabled, gitlab_config_features.wiki default_value_for :wiki_enabled, gitlab_config_features.wiki
default_value_for :wall_enabled, false default_value_for :wall_enabled, false
default_value_for :snippets_enabled, gitlab_config_features.snippets default_value_for :snippets_enabled, gitlab_config_features.snippets
...@@ -122,6 +123,9 @@ class Project < ActiveRecord::Base ...@@ -122,6 +123,9 @@ class Project < ActiveRecord::Base
has_many :starrers, through: :users_star_projects, source: :user has_many :starrers, through: :users_star_projects, source: :user
has_many :ci_commits, dependent: :destroy, class_name: 'Ci::Commit', foreign_key: :gl_project_id has_many :ci_commits, dependent: :destroy, class_name: 'Ci::Commit', foreign_key: :gl_project_id
has_many :ci_builds, through: :ci_commits, source: :builds, dependent: :destroy, class_name: 'Ci::Build' has_many :ci_builds, through: :ci_commits, source: :builds, dependent: :destroy, class_name: 'Ci::Build'
has_many :releases, dependent: :destroy
has_many :lfs_objects_projects, dependent: :destroy
has_many :lfs_objects, through: :lfs_objects_projects
has_one :import_data, dependent: :destroy, class_name: "ProjectImportData" has_one :import_data, dependent: :destroy, class_name: "ProjectImportData"
has_one :gitlab_ci_project, dependent: :destroy, class_name: "Ci::Project", foreign_key: :gitlab_id has_one :gitlab_ci_project, dependent: :destroy, class_name: "Ci::Project", foreign_key: :gitlab_id
...@@ -248,7 +252,7 @@ class Project < ActiveRecord::Base ...@@ -248,7 +252,7 @@ class Project < ActiveRecord::Base
joins(:namespace). joins(:namespace).
iwhere('namespaces.path' => namespace_path) iwhere('namespaces.path' => namespace_path)
projects.where('projects.path' => project_path).take || projects.where('projects.path' => project_path).take ||
projects.iwhere('projects.path' => project_path).take projects.iwhere('projects.path' => project_path).take
end end
...@@ -456,10 +460,6 @@ class Project < ActiveRecord::Base ...@@ -456,10 +460,6 @@ class Project < ActiveRecord::Base
list.find { |service| service.to_param == name } list.find { |service| service.to_param == name }
end end
def gitlab_ci?
gitlab_ci_service && gitlab_ci_service.active && gitlab_ci_project.present?
end
def ci_services def ci_services
services.select { |service| service.category == :ci } services.select { |service| service.category == :ci }
end end
...@@ -781,9 +781,33 @@ class Project < ActiveRecord::Base ...@@ -781,9 +781,33 @@ class Project < ActiveRecord::Base
) )
end end
def enable_ci # TODO: this should be migrated to Project table,
# the same as issues_enabled
def builds_enabled
gitlab_ci_service && gitlab_ci_service.active
end
def builds_enabled?
builds_enabled
end
def builds_enabled=(value)
service = gitlab_ci_service || create_gitlab_ci_service service = gitlab_ci_service || create_gitlab_ci_service
service.active = true service.active = value
service.save service.save
end end
def enable_ci
self.builds_enabled = true
end
def unlink_fork
if forked?
forked_from_project.lfs_objects.find_each do |lfs_object|
lfs_object.projects << self
end
forked_project_link.destroy
end
end
end end
# == Schema Information # == Schema Information
# #
# Table name: services # Table name: ci_services
# #
# id :integer not null, primary key # id :integer not null, primary key
# type :string(255) # type :string(255)
......
# == Schema Information # == Schema Information
# #
# Table name: services # Table name: ci_services
# #
# id :integer not null, primary key # id :integer not null, primary key
# type :string(255) # type :string(255)
......
# == Schema Information # == Schema Information
# #
# Table name: services # Table name: ci_services
# #
# id :integer not null, primary key # id :integer not null, primary key
# type :string(255) # type :string(255)
......
...@@ -32,7 +32,6 @@ class DroneCiService < CiService ...@@ -32,7 +32,6 @@ class DroneCiService < CiService
def compose_service_hook def compose_service_hook
hook = service_hook || build_service_hook hook = service_hook || build_service_hook
hook.url = [drone_url, "/api/hook", "?owner=#{project.namespace.path}", "&name=#{project.path}", "&access_token=#{token}"].join
hook.enable_ssl_verification = enable_ssl_verification hook.enable_ssl_verification = enable_ssl_verification
hook.save hook.save
end end
......
...@@ -86,6 +86,8 @@ class ProjectWiki ...@@ -86,6 +86,8 @@ class ProjectWiki
commit = commit_details(:created, message, title) commit = commit_details(:created, message, title)
wiki.write_page(title, format, content, commit) wiki.write_page(title, format, content, commit)
update_project_activity
rescue Gollum::DuplicatePageError => e rescue Gollum::DuplicatePageError => e
@error_message = "Duplicate page: #{e.message}" @error_message = "Duplicate page: #{e.message}"
return false return false
...@@ -95,10 +97,14 @@ class ProjectWiki ...@@ -95,10 +97,14 @@ class ProjectWiki
commit = commit_details(:updated, message, page.title) commit = commit_details(:updated, message, page.title)
wiki.update_page(page, page.name, format, content, commit) wiki.update_page(page, page.name, format, content, commit)
update_project_activity
end end
def delete_page(page, message = nil) def delete_page(page, message = nil)
wiki.delete_page(page, commit_details(:deleted, message, page.title)) wiki.delete_page(page, commit_details(:deleted, message, page.title))
update_project_activity
end end
def page_title_and_dir(title) def page_title_and_dir(title)
...@@ -146,4 +152,8 @@ class ProjectWiki ...@@ -146,4 +152,8 @@ class ProjectWiki
def path_to_repo def path_to_repo
@path_to_repo ||= File.join(Gitlab.config.gitlab_shell.repos_path, "#{path_with_namespace}.git") @path_to_repo ||= File.join(Gitlab.config.gitlab_shell.repos_path, "#{path_with_namespace}.git")
end end
def update_project_activity
@project.touch(:last_activity_at)
end
end end
# == Schema Information
#
# Table name: releases
#
# id :integer not null, primary key
# tag :string(255)
# description :text
# project_id :integer
# created_at :datetime
# updated_at :datetime
#
class Release < ActiveRecord::Base
belongs_to :project
validates :description, :project, :tag, presence: true
end
...@@ -346,8 +346,8 @@ class Repository ...@@ -346,8 +346,8 @@ class Repository
end end
end end
def branch_names_contains(sha) def refs_contains_sha(ref_type, sha)
args = %W(#{Gitlab.config.git.bin_path} branch --contains #{sha}) args = %W(#{Gitlab.config.git.bin_path} #{ref_type} --contains #{sha})
names = Gitlab::Popen.popen(args, path_to_repo).first names = Gitlab::Popen.popen(args, path_to_repo).first
if names.respond_to?(:split) if names.respond_to?(:split)
...@@ -363,21 +363,12 @@ class Repository ...@@ -363,21 +363,12 @@ class Repository
end end
end end
def tag_names_contains(sha) def branch_names_contains(sha)
args = %W(#{Gitlab.config.git.bin_path} tag --contains #{sha}) refs_contains_sha('branch', sha)
names = Gitlab::Popen.popen(args, path_to_repo).first end
if names.respond_to?(:split)
names = names.split("\n").map(&:strip)
names.each do |name|
name.slice! '* '
end
names def tag_names_contains(sha)
else refs_contains_sha('tag', sha)
[]
end
end end
def branches def branches
......
...@@ -54,6 +54,7 @@ ...@@ -54,6 +54,7 @@
# public_email :string(255) default(""), not null # public_email :string(255) default(""), not null
# dashboard :integer default(0) # dashboard :integer default(0)
# project_view :integer default(0) # project_view :integer default(0)
# consumed_timestep :integer
# layout :integer default(0) # layout :integer default(0)
# #
...@@ -404,6 +405,15 @@ class User < ActiveRecord::Base ...@@ -404,6 +405,15 @@ class User < ActiveRecord::Base
end end
end end
def master_or_owner_projects_id
@master_or_owner_projects_id ||= begin
scope = { access_level: [ Gitlab::Access::MASTER, Gitlab::Access::OWNER ] }
project_ids = personal_projects.pluck(:id)
project_ids.push(*groups_projects.where(members: scope).pluck(:id))
project_ids.push(*projects.where(members: scope).pluck(:id).uniq)
end
end
# Projects user has access to # Projects user has access to
def authorized_projects def authorized_projects
@authorized_projects ||= Project.where(id: authorized_projects_id) @authorized_projects ||= Project.where(id: authorized_projects_id)
...@@ -764,14 +774,10 @@ class User < ActiveRecord::Base ...@@ -764,14 +774,10 @@ class User < ActiveRecord::Base
!solo_owned_groups.present? !solo_owned_groups.present?
end end
def ci_authorized_projects
@ci_authorized_projects ||= Ci::Project.where(gitlab_id: authorized_projects_id)
end
def ci_authorized_runners def ci_authorized_runners
@ci_authorized_runners ||= begin @ci_authorized_runners ||= begin
runner_ids = Ci::RunnerProject.joins(:project). runner_ids = Ci::RunnerProject.joins(:project).
where(ci_projects: { gitlab_id: authorized_projects_id }).select(:runner_id) where(ci_projects: { gitlab_id: master_or_owner_projects_id }).select(:runner_id)
Ci::Runner.specific.where(id: runner_ids) Ci::Runner.specific.where(id: runner_ids)
end end
end end
......
...@@ -3,7 +3,7 @@ require 'securerandom' ...@@ -3,7 +3,7 @@ require 'securerandom'
# Compare 2 branches for one repo or between repositories # Compare 2 branches for one repo or between repositories
# and return Gitlab::CompareResult object that responds to commits and diffs # and return Gitlab::CompareResult object that responds to commits and diffs
class CompareService class CompareService
def execute(source_project, source_branch, target_project, target_branch) def execute(source_project, source_branch, target_project, target_branch, diff_options = {})
source_commit = source_project.commit(source_branch) source_commit = source_project.commit(source_branch)
return unless source_commit return unless source_commit
...@@ -25,7 +25,7 @@ class CompareService ...@@ -25,7 +25,7 @@ class CompareService
target_project.repository.raw_repository, target_project.repository.raw_repository,
target_branch, target_branch,
source_sha, source_sha,
) ), diff_options
) )
end end
end end
require_relative 'base_service' require_relative 'base_service'
class CreateTagService < BaseService class CreateTagService < BaseService
def execute(tag_name, ref, message) def execute(tag_name, ref, message, release_description = nil)
valid_tag = Gitlab::GitRefValidator.validate(tag_name) valid_tag = Gitlab::GitRefValidator.validate(tag_name)
if valid_tag == false if valid_tag == false
return error('Tag name invalid') return error('Tag name invalid')
...@@ -19,8 +19,12 @@ class CreateTagService < BaseService ...@@ -19,8 +19,12 @@ class CreateTagService < BaseService
new_tag = repository.find_tag(tag_name) new_tag = repository.find_tag(tag_name)
if new_tag if new_tag
push_data = create_push_data(project, current_user, new_tag) if release_description
release = project.releases.find_or_initialize_by(tag: tag_name)
release.update_attributes(description: release_description)
end
push_data = create_push_data(project, current_user, new_tag)
EventCreateService.new.push(project, current_user, push_data) EventCreateService.new.push(project, current_user, push_data)
project.execute_hooks(push_data.dup, :tag_push_hooks) project.execute_hooks(push_data.dup, :tag_push_hooks)
project.execute_services(push_data.dup, :tag_push_hooks) project.execute_services(push_data.dup, :tag_push_hooks)
......
...@@ -11,8 +11,10 @@ class DeleteTagService < BaseService ...@@ -11,8 +11,10 @@ class DeleteTagService < BaseService
end end
if repository.rm_tag(tag_name) if repository.rm_tag(tag_name)
release = project.releases.find_by(tag: tag_name)
release.destroy if release
push_data = build_push_data(tag) push_data = build_push_data(tag)
EventCreateService.new.push(project, current_user, push_data) EventCreateService.new.push(project, current_user, push_data)
project.execute_hooks(push_data.dup, :tag_push_hooks) project.execute_hooks(push_data.dup, :tag_push_hooks)
project.execute_services(push_data.dup, :tag_push_hooks) project.execute_services(push_data.dup, :tag_push_hooks)
......
...@@ -60,7 +60,7 @@ class GitPushService ...@@ -60,7 +60,7 @@ class GitPushService
# If CI was disabled but .gitlab-ci.yml file was pushed # If CI was disabled but .gitlab-ci.yml file was pushed
# we enable CI automatically # we enable CI automatically
if !project.gitlab_ci? && gitlab_ci_yaml?(newrev) if !project.builds_enabled? && gitlab_ci_yaml?(newrev)
project.enable_ci project.enable_ci
end end
......
...@@ -22,24 +22,27 @@ module Issues ...@@ -22,24 +22,27 @@ module Issues
issue, issue.labels - old_labels, old_labels - issue.labels) issue, issue.labels - old_labels, old_labels - issue.labels)
end end
if issue.previous_changes.include?('milestone_id') handle_changes(issue)
create_milestone_note(issue)
end
if issue.previous_changes.include?('assignee_id')
create_assignee_note(issue)
notification_service.reassigned_issue(issue, current_user)
end
if issue.previous_changes.include?('title')
create_title_change_note(issue, issue.previous_changes['title'].first)
end
issue.create_new_cross_references!(current_user) issue.create_new_cross_references!(current_user)
execute_hooks(issue, 'update') execute_hooks(issue, 'update')
end end
issue issue
end end
def handle_changes(issue)
if issue.previous_changes.include?('milestone_id')
create_milestone_note(issue)
end
if issue.previous_changes.include?('assignee_id')
create_assignee_note(issue)
notification_service.reassigned_issue(issue, current_user)
end
if issue.previous_changes.include?('title')
create_title_change_note(issue, issue.previous_changes['title'].first)
end
end
end end
end end
module Labels
class GroupService < ::BaseService
def initialize(project_labels)
@project_labels = project_labels.group_by(&:title)
end
def execute
build(@project_labels)
end
def label(title)
if title
group_label = @project_labels[title].group_by(&:title)
build(group_label).first
else
nil
end
end
private
def build(label)
label.map { |title, labels| GroupLabel.new(title, labels) }
end
end
end
...@@ -35,35 +35,38 @@ module MergeRequests ...@@ -35,35 +35,38 @@ module MergeRequests
) )
end end
if merge_request.previous_changes.include?('target_branch') handle_changes(merge_request)
create_branch_change_note(merge_request, 'target', merge_request.create_new_cross_references!(current_user)
merge_request.previous_changes['target_branch'].first, execute_hooks(merge_request, 'update')
merge_request.target_branch) end
end
if merge_request.previous_changes.include?('milestone_id') merge_request
create_milestone_note(merge_request) end
end
if merge_request.previous_changes.include?('assignee_id') def handle_changes(merge_request)
create_assignee_note(merge_request) if merge_request.previous_changes.include?('target_branch')
notification_service.reassigned_merge_request(merge_request, current_user) create_branch_change_note(merge_request, 'target',
end merge_request.previous_changes['target_branch'].first,
merge_request.target_branch)
end
if merge_request.previous_changes.include?('title') if merge_request.previous_changes.include?('milestone_id')
create_title_change_note(merge_request, merge_request.previous_changes['title'].first) create_milestone_note(merge_request)
end end
if merge_request.previous_changes.include?('target_branch') || if merge_request.previous_changes.include?('assignee_id')
merge_request.previous_changes.include?('source_branch') create_assignee_note(merge_request)
merge_request.mark_as_unchecked notification_service.reassigned_merge_request(merge_request, current_user)
end end
merge_request.create_new_cross_references!(current_user) if merge_request.previous_changes.include?('title')
execute_hooks(merge_request, 'update') create_title_change_note(merge_request, merge_request.previous_changes['title'].first)
end end
merge_request if merge_request.previous_changes.include?('target_branch') ||
merge_request.previous_changes.include?('source_branch')
merge_request.mark_as_unchecked
end
end end
end end
end end
module Milestones
class GroupService < Milestones::BaseService
def initialize(project_milestones)
@project_milestones = project_milestones.group_by(&:title)
end
def execute
build(@project_milestones)
end
def milestone(title)
if title
group_milestone = @project_milestones[title].group_by(&:title)
build(group_milestone).first
else
nil
end
end
private
def build(milestone)
milestone.map{ |title, milestones| GroupMilestone.new(title, milestones) }
end
end
end
...@@ -17,7 +17,7 @@ module Projects ...@@ -17,7 +17,7 @@ module Projects
new_project = CreateService.new(current_user, new_params).execute new_project = CreateService.new(current_user, new_params).execute
if new_project.persisted? if new_project.persisted?
if @project.gitlab_ci? if @project.builds_enabled?
new_project.enable_ci new_project.enable_ci
settings = @project.gitlab_ci_project.attributes.select do |attr_name, value| settings = @project.gitlab_ci_project.attributes.select do |attr_name, value|
......
...@@ -33,17 +33,7 @@ class SystemHooksService ...@@ -33,17 +33,7 @@ class SystemHooksService
) )
end end
when Project when Project
owner = model.owner data.merge!(project_data(model))
data.merge!({
name: model.name,
path: model.path,
path_with_namespace: model.path_with_namespace,
project_id: model.id,
owner_name: owner.name,
owner_email: owner.respond_to?(:email) ? owner.email : "",
project_visibility: Project.visibility_levels.key(model.visibility_level_field).downcase
})
when User when User
data.merge!({ data.merge!({
name: model.name, name: model.name,
...@@ -51,16 +41,7 @@ class SystemHooksService ...@@ -51,16 +41,7 @@ class SystemHooksService
user_id: model.id user_id: model.id
}) })
when ProjectMember when ProjectMember
data.merge!({ data.merge!(project_member_data(model))
project_name: model.project.name,
project_path: model.project.path,
project_path_with_namespace: model.project.path_with_namespace,
project_id: model.project.id,
user_name: model.user.name,
user_email: model.user.email,
access_level: model.human_access,
project_visibility: Project.visibility_levels.key(model.project.visibility_level_field).downcase
})
when Group when Group
owner = model.owner owner = model.owner
...@@ -72,15 +53,7 @@ class SystemHooksService ...@@ -72,15 +53,7 @@ class SystemHooksService
owner_email: owner.respond_to?(:email) ? owner.email : nil, owner_email: owner.respond_to?(:email) ? owner.email : nil,
) )
when GroupMember when GroupMember
data.merge!( data.merge!(group_member_data(model))
group_name: model.group.name,
group_path: model.group.path,
group_id: model.group.id,
user_name: model.user.name,
user_email: model.user.email,
user_id: model.user.id,
group_access: model.human_access,
)
end end
end end
...@@ -96,4 +69,43 @@ class SystemHooksService ...@@ -96,4 +69,43 @@ class SystemHooksService
"#{model.class.name.downcase}_#{event.to_s}" "#{model.class.name.downcase}_#{event.to_s}"
end end
end end
def project_data(model)
owner = model.owner
{
name: model.name,
path: model.path,
path_with_namespace: model.path_with_namespace,
project_id: model.id,
owner_name: owner.name,
owner_email: owner.respond_to?(:email) ? owner.email : "",
project_visibility: Project.visibility_levels.key(model.visibility_level_field).downcase
}
end
def project_member_data(model)
{
project_name: model.project.name,
project_path: model.project.path,
project_path_with_namespace: model.project.path_with_namespace,
project_id: model.project.id,
user_name: model.user.name,
user_email: model.user.email,
access_level: model.human_access,
project_visibility: Project.visibility_levels.key(model.project.visibility_level_field).downcase
}
end
def group_member_data(model)
{
group_name: model.group.name,
group_path: model.group.path,
group_id: model.group.id,
user_name: model.user.name,
user_email: model.user.email,
user_id: model.user.id,
group_access: model.human_access,
}
end
end end
# encoding: utf-8
class ArtifactUploader < CarrierWave::Uploader::Base
storage :file
attr_accessor :build, :field
def self.artifacts_path
File.expand_path('shared/artifacts/', Rails.root)
end
def self.artifacts_upload_path
File.expand_path('shared/artifacts/tmp/uploads/', Rails.root)
end
def self.artifacts_cache_path
File.expand_path('shared/artifacts/tmp/cache/', Rails.root)
end
def initialize(build, field)
@build, @field = build, field
end
def artifacts_path
File.join(build.created_at.utc.strftime('%Y_%m'), build.project.id.to_s, build.id.to_s)
end
def store_dir
File.join(ArtifactUploader.artifacts_path, artifacts_path)
end
def cache_dir
File.join(ArtifactUploader.artifacts_cache_path, artifacts_path)
end
def file_storage?
self.class.storage == CarrierWave::Storage::File
end
def exists?
file.try(:exists?)
end
def move_to_cache
true
end
def move_to_store
true
end
end
# encoding: utf-8 # encoding: utf-8
class AttachmentUploader < CarrierWave::Uploader::Base class AttachmentUploader < CarrierWave::Uploader::Base
include UploaderHelper
storage :file storage :file
def store_dir def store_dir
"uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}" "uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}"
end end
def image?
img_ext = %w(png jpg jpeg gif bmp tiff)
if file.respond_to?(:extension)
img_ext.include?(file.extension.downcase)
else
# Not all CarrierWave storages respond to :extension
ext = file.path.split('.').last.downcase
img_ext.include?(ext)
end
rescue
false
end
def file_storage?
self.class.storage == CarrierWave::Storage::File
end
end end
# encoding: utf-8 # encoding: utf-8
class AvatarUploader < CarrierWave::Uploader::Base class AvatarUploader < CarrierWave::Uploader::Base
include UploaderHelper
storage :file storage :file
after :store, :reset_events_cache after :store, :reset_events_cache
...@@ -9,23 +11,6 @@ class AvatarUploader < CarrierWave::Uploader::Base ...@@ -9,23 +11,6 @@ class AvatarUploader < CarrierWave::Uploader::Base
"uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}" "uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}"
end end
def image?
img_ext = %w(png jpg jpeg gif bmp tiff)
if file.respond_to?(:extension)
img_ext.include?(file.extension.downcase)
else
# Not all CarrierWave storages respond to :extension
ext = file.path.split('.').last.downcase
img_ext.include?(ext)
end
rescue
false
end
def file_storage?
self.class.storage == CarrierWave::Storage::File
end
def reset_events_cache(file) def reset_events_cache(file)
model.reset_events_cache if model.is_a?(User) model.reset_events_cache if model.is_a?(User)
end end
......
# encoding: utf-8 # encoding: utf-8
class FileUploader < CarrierWave::Uploader::Base class FileUploader < CarrierWave::Uploader::Base
include UploaderHelper
storage :file storage :file
attr_accessor :project, :secret attr_accessor :project, :secret
...@@ -28,21 +30,4 @@ class FileUploader < CarrierWave::Uploader::Base ...@@ -28,21 +30,4 @@ class FileUploader < CarrierWave::Uploader::Base
def secure_url def secure_url
File.join("/uploads", @secret, file.filename) File.join("/uploads", @secret, file.filename)
end end
def file_storage?
self.class.storage == CarrierWave::Storage::File
end
def image?
img_ext = %w(png jpg jpeg gif bmp tiff)
if file.respond_to?(:extension)
img_ext.include?(file.extension.downcase)
else
# Not all CarrierWave storages respond to :extension
ext = file.path.split('.').last.downcase
img_ext.include?(ext)
end
rescue
false
end
end end
# encoding: utf-8
class LfsObjectUploader < CarrierWave::Uploader::Base
storage :file
def store_dir
"#{Gitlab.config.lfs.storage_path}/#{model.oid[0,2]}/#{model.oid[2,2]}"
end
def cache_dir
"#{Gitlab.config.lfs.storage_path}/tmp/cache"
end
def move_to_cache
true
end
def move_to_store
true
end
def exists?
file.try(:exists?)
end
def filename
model.oid[4..-1]
end
end
# Extra methods for uploader
module UploaderHelper
def image?
img_ext = %w(png jpg jpeg gif bmp tiff)
if file.respond_to?(:extension)
img_ext.include?(file.extension.downcase)
else
# Not all CarrierWave storages respond to :extension
ext = file.path.split('.').last.downcase
img_ext.include?(ext)
end
rescue
false
end
def file_storage?
self.class.storage == CarrierWave::Storage::File
end
end
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
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