Commit feecb4af authored by James Lopez's avatar James Lopez

Merge branch 'master' of gitlab.com:gitlab-org/gitlab-ce into fix/import-event-error

parents 0e5f0276 36c60b4c
...@@ -193,7 +193,7 @@ Style/EmptyLineBetweenDefs: ...@@ -193,7 +193,7 @@ Style/EmptyLineBetweenDefs:
# Don't use several empty lines in a row. # Don't use several empty lines in a row.
Style/EmptyLines: Style/EmptyLines:
Enabled: false Enabled: true
# Keep blank lines around access modifiers. # Keep blank lines around access modifiers.
Style/EmptyLinesAroundAccessModifier: Style/EmptyLinesAroundAccessModifier:
...@@ -284,7 +284,7 @@ Style/IfWithSemicolon: ...@@ -284,7 +284,7 @@ Style/IfWithSemicolon:
# Checks that conditional statements do not have an identical line at the # Checks that conditional statements do not have an identical line at the
# end of each branch, which can validly be moved out of the conditional. # end of each branch, which can validly be moved out of the conditional.
Style/IdenticalConditionalBranches: Style/IdenticalConditionalBranches:
Enabled: false Enabled: true
# Checks the indentation of the first line of the right-hand-side of a # Checks the indentation of the first line of the right-hand-side of a
# multi-line assignment. # multi-line assignment.
......
...@@ -8,27 +8,50 @@ v 8.10.0 (unreleased) ...@@ -8,27 +8,50 @@ v 8.10.0 (unreleased)
- Wrap code blocks on Activies and Todos page. !4783 (winniehell) - Wrap code blocks on Activies and Todos page. !4783 (winniehell)
- Align flash messages with left side of page content !4959 (winniehell) - Align flash messages with left side of page content !4959 (winniehell)
- Display last commit of deleted branch in push events !4699 (winniehell) - Display last commit of deleted branch in push events !4699 (winniehell)
- Escape file extension when parsing search results !5141 (winniehell)
- Apply the trusted_proxies config to the rack request object for use with rack_attack - Apply the trusted_proxies config to the rack request object for use with rack_attack
- Add Sidekiq queue duration to transaction metrics. - Add Sidekiq queue duration to transaction metrics.
- Add a new column `artifacts_size` to table `ci_builds` !4964
- Let Workhorse serve format-patch diffs - Let Workhorse serve format-patch diffs
- Make images fit to the size of the viewport !4810 - Make images fit to the size of the viewport !4810
- Fix check for New Branch button on Issue page !4630 (winniehell) - Fix check for New Branch button on Issue page !4630 (winniehell)
- Fix MR-auto-close text added to description. !4836 - Fix MR-auto-close text added to description. !4836
- Fix issue, preventing users w/o push access to sort tags !5105 (redetection)
- Add Spring EmojiOne updates.
- Add syntax for multiline blockquote using `>>>` fence !3954
- Fix viewing notification settings when a project is pending deletion
- Fix pagination when sorting by columns with lots of ties (like priority) - Fix pagination when sorting by columns with lots of ties (like priority)
- The Markdown reference parsers now re-use query results to prevent running the same queries multiple times !5020
- Updated project header design
- Exclude email check from the standard health check - Exclude email check from the standard health check
- Updated layout for Projects, Groups, Users on Admin area !4424
- Fix changing issue state columns in milestone view - Fix changing issue state columns in milestone view
- Add notification settings dropdown for groups - Add notification settings dropdown for groups
- Wildcards for protected branches. !4665
- Allow importing from Github using Personal Access Tokens. (Eric K Idema) - Allow importing from Github using Personal Access Tokens. (Eric K Idema)
- API: Todos !3188 (Robert Schilling)
- API: Expose shared groups for projects and shared projects for groups !5050 (Robert Schilling)
- Add "Enabled Git access protocols" to Application Settings
- Fix user creation with stronger minimum password requirements !4054 (nathan-pmt) - Fix user creation with stronger minimum password requirements !4054 (nathan-pmt)
- Only show New Snippet button to users that can create snippets.
- PipelinesFinder uses git cache data - PipelinesFinder uses git cache data
- Throttle the update of `project.pushes_since_gc` to 1 minute.
- Check for conflicts with existing Project's wiki path when creating a new project. - Check for conflicts with existing Project's wiki path when creating a new project.
- Show last push widget in upstream after push to fork
- Don't instantiate a git tree on Projects show default view - Don't instantiate a git tree on Projects show default view
- Bump Rinku to 2.0.0
- Remove unused front-end variable -> default_issues_tracker - Remove unused front-end variable -> default_issues_tracker
- Better caching of git calls on ProjectsController#show. - Better caching of git calls on ProjectsController#show.
- Avoid to retrieve MR closes_issues as much as possible.
- Add API endpoint for a group issues !4520 (mahcsig) - Add API endpoint for a group issues !4520 (mahcsig)
- Add Bugzilla integration !4930 (iamtjg) - Add Bugzilla integration !4930 (iamtjg)
- Instrument Rinku usage
- Metrics for Rouge::Plugins::Redcarpet and Rouge::Formatters::HTMLGitlab - Metrics for Rouge::Plugins::Redcarpet and Rouge::Formatters::HTMLGitlab
- RailsCache metris now includes fetch_hit/fetch_miss and read_hit/read_miss info.
- Allow [ci skip] to be in any case and allow [skip ci]. !4785 (simon_w) - Allow [ci skip] to be in any case and allow [skip ci]. !4785 (simon_w)
- Set import_url validation to be more strict
- Memoize MR merged/closed events retrieval
- Don't render discussion notes when requesting diff tab through AJAX
- Add basic system information like memory and disk usage to the admin panel - Add basic system information like memory and disk usage to the admin panel
v 8.9.5 (unreleased) v 8.9.5 (unreleased)
...@@ -43,6 +66,8 @@ v 8.9.5 (unreleased) ...@@ -43,6 +66,8 @@ v 8.9.5 (unreleased)
v 8.9.6 v 8.9.6
- Fix importing of events under notes for GitLab projects - Fix importing of events under notes for GitLab projects
- Add min value for project limit field on user's form !3622 (jastkand)
- Add reminder to not paste private SSH keys !4399 (Ingo Blechschmidt)
v 8.9.5 v 8.9.5
- Add more debug info to import/export and memory killer. !5108 - Add more debug info to import/export and memory killer. !5108
...@@ -58,9 +83,6 @@ v 8.9.5 ...@@ -58,9 +83,6 @@ v 8.9.5
- Admin should be able to turn shared runners into specific ones. !4961 - Admin should be able to turn shared runners into specific ones. !4961
- Update RedCloth to 4.3.2 for CVE-2012-6684. !4929 (Takuya Noguchi) - Update RedCloth to 4.3.2 for CVE-2012-6684. !4929 (Takuya Noguchi)
- Improve the request / withdraw access button. !4860 - Improve the request / withdraw access button. !4860
- Fix assigning shared runners as admins. !4961
- Show "locked" label for locked runners on runners admin. !4961
- Fixes issues importing events in Import/Export. Import/Export version bumped to 0.1.1
v 8.9.4 v 8.9.4
- Fix privilege escalation issue with OAuth external users. - Fix privilege escalation issue with OAuth external users.
...@@ -90,7 +112,7 @@ v 8.9.3 ...@@ -90,7 +112,7 @@ v 8.9.3
- Removed fade when filtering results. !4932 - Removed fade when filtering results. !4932
- Fix missing avatar on system notes. !4954 - Fix missing avatar on system notes. !4954
- Reduce overhead and optimize ProjectTeam#max_member_access performance. !4973 - Reduce overhead and optimize ProjectTeam#max_member_access performance. !4973
- Use update_columns to by_pass all the dirty code on active_record. !4985 - Use update_columns to bypass all the dirty code on active_record. !4985
- Fix restore Rake task warning message output !4980 - Fix restore Rake task warning message output !4980
v 8.9.2 v 8.9.2
......
source "https://rubygems.org" source 'https://rubygems.org'
gem 'rails', '4.2.6' gem 'rails', '4.2.6'
gem 'rails-deprecated_sanitizer', '~> 1.0.3' gem 'rails-deprecated_sanitizer', '~> 1.0.3'
...@@ -11,15 +11,15 @@ gem 'responders', '~> 2.0' ...@@ -11,15 +11,15 @@ gem 'responders', '~> 2.0'
gem 'sprockets', '~> 3.6.0' gem 'sprockets', '~> 3.6.0'
# Default values for AR models # Default values for AR models
gem "default_value_for", "~> 3.0.0" gem 'default_value_for', '~> 3.0.0'
# Supported DBs # Supported DBs
gem "mysql2", '~> 0.3.16', group: :mysql gem 'mysql2', '~> 0.3.16', group: :mysql
gem "pg", '~> 0.18.2', group: :postgres gem 'pg', '~> 0.18.2', group: :postgres
# Authentication libraries # Authentication libraries
gem 'devise', '~> 4.0' gem 'devise', '~> 4.0'
gem 'doorkeeper', '~> 3.1' gem 'doorkeeper', '~> 4.0'
gem 'omniauth', '~> 1.3.1' gem 'omniauth', '~> 1.3.1'
gem 'omniauth-auth0', '~> 1.4.1' gem 'omniauth-auth0', '~> 1.4.1'
gem 'omniauth-azure-oauth2', '~> 0.0.6' gem 'omniauth-azure-oauth2', '~> 0.0.6'
...@@ -28,7 +28,7 @@ gem 'omniauth-cas3', '~> 1.1.2' ...@@ -28,7 +28,7 @@ gem 'omniauth-cas3', '~> 1.1.2'
gem 'omniauth-facebook', '~> 3.0.0' gem 'omniauth-facebook', '~> 3.0.0'
gem 'omniauth-github', '~> 1.1.1' gem 'omniauth-github', '~> 1.1.1'
gem 'omniauth-gitlab', '~> 1.0.0' gem 'omniauth-gitlab', '~> 1.0.0'
gem 'omniauth-google-oauth2', '~> 0.2.0' gem 'omniauth-google-oauth2', '~> 0.4.1'
gem 'omniauth-kerberos', '~> 0.3.0', group: :kerberos gem 'omniauth-kerberos', '~> 0.3.0', group: :kerberos
gem 'omniauth-saml', '~> 1.6.0' gem 'omniauth-saml', '~> 1.6.0'
gem 'omniauth-shibboleth', '~> 1.2.0' gem 'omniauth-shibboleth', '~> 1.2.0'
...@@ -48,16 +48,16 @@ gem 'attr_encrypted', '~> 3.0.0' ...@@ -48,16 +48,16 @@ gem 'attr_encrypted', '~> 3.0.0'
gem 'u2f', '~> 0.2.1' gem 'u2f', '~> 0.2.1'
# Browser detection # Browser detection
gem "browser", '~> 2.2' gem 'browser', '~> 2.2'
# Extracting information from a git repository # Extracting information from a git repository
# Provide access to Gitlab::Git library # Provide access to Gitlab::Git library
gem "gitlab_git", '~> 10.2' gem 'gitlab_git', '~> 10.2'
# LDAP Auth # LDAP Auth
# GitLab fork with several improvements to original library. For full list of changes # GitLab fork with several improvements to original library. For full list of changes
# see https://github.com/intridea/omniauth-ldap/compare/master...gitlabhq:master # see https://github.com/intridea/omniauth-ldap/compare/master...gitlabhq:master
gem 'gitlab_omniauth-ldap', '~> 1.2.1', require: "omniauth-ldap" gem 'gitlab_omniauth-ldap', '~> 1.2.1', require: 'omniauth-ldap'
# Git Wiki # Git Wiki
# Required manually in config/initializers/gollum.rb to control load order # Required manually in config/initializers/gollum.rb to control load order
...@@ -65,7 +65,7 @@ gem 'gollum-lib', '~> 4.1.0', require: false ...@@ -65,7 +65,7 @@ gem 'gollum-lib', '~> 4.1.0', require: false
gem 'gollum-rugged_adapter', '~> 0.4.2', require: false gem 'gollum-rugged_adapter', '~> 0.4.2', require: false
# Language detection # Language detection
gem "github-linguist", "~> 4.7.0", require: "linguist" gem 'github-linguist', '~> 4.7.0', require: 'linguist'
# API # API
gem 'grape', '~> 0.13.0' gem 'grape', '~> 0.13.0'
...@@ -73,13 +73,13 @@ gem 'grape-entity', '~> 0.4.2' ...@@ -73,13 +73,13 @@ gem 'grape-entity', '~> 0.4.2'
gem 'rack-cors', '~> 0.4.0', require: 'rack/cors' gem 'rack-cors', '~> 0.4.0', require: 'rack/cors'
# Pagination # Pagination
gem "kaminari", "~> 0.17.0" gem 'kaminari', '~> 0.17.0'
# HAML # HAML
gem 'hamlit', '~> 2.5' gem 'hamlit', '~> 2.5'
# Files attachments # Files attachments
gem "carrierwave", '~> 0.10.0' gem 'carrierwave', '~> 0.10.0'
# Drag and Drop UI # Drag and Drop UI
gem 'dropzonejs-rails', '~> 0.7.1' gem 'dropzonejs-rails', '~> 0.7.1'
...@@ -94,20 +94,20 @@ gem 'fog-openstack', '~> 0.1' ...@@ -94,20 +94,20 @@ gem 'fog-openstack', '~> 0.1'
gem 'fog-rackspace', '~> 0.1.1' gem 'fog-rackspace', '~> 0.1.1'
# for aws storage # for aws storage
gem "unf", '~> 0.1.4' gem 'unf', '~> 0.1.4'
# Authorization # Authorization
gem "six", '~> 0.2.0' gem 'six', '~> 0.2.0'
# Seed data # Seed data
gem "seed-fu", '~> 2.3.5' gem 'seed-fu', '~> 2.3.5'
# Markdown and HTML processing # Markdown and HTML processing
gem 'html-pipeline', '~> 1.11.0' gem 'html-pipeline', '~> 1.11.0'
gem 'task_list', '~> 1.0.2', require: 'task_list/railtie' gem 'task_list', '~> 1.0.2', require: 'task_list/railtie'
gem 'github-markup', '~> 1.3.1' gem 'github-markup', '~> 1.3.1'
gem 'redcarpet', '~> 3.3.3' gem 'redcarpet', '~> 3.3.3'
gem 'RedCloth', '~> 4.2.9' gem 'RedCloth', '~> 4.3.2'
gem 'rdoc', '~>3.6' gem 'rdoc', '~>3.6'
gem 'org-ruby', '~> 0.9.12' gem 'org-ruby', '~> 0.9.12'
gem 'creole', '~> 0.5.0' gem 'creole', '~> 0.5.0'
...@@ -124,29 +124,29 @@ gem 'diffy', '~> 3.0.3' ...@@ -124,29 +124,29 @@ gem 'diffy', '~> 3.0.3'
# Application server # Application server
group :unicorn do group :unicorn do
gem "unicorn", '~> 4.9.0' gem 'unicorn', '~> 4.9.0'
gem 'unicorn-worker-killer', '~> 0.4.2' gem 'unicorn-worker-killer', '~> 0.4.2'
end end
# State machine # State machine
gem "state_machines-activerecord", '~> 0.4.0' gem 'state_machines-activerecord', '~> 0.4.0'
# Run events after state machine commits # Run events after state machine commits
gem 'after_commit_queue' gem 'after_commit_queue', '~> 1.3.0'
# Issue tags # Issue tags
gem 'acts-as-taggable-on', '~> 3.4' gem 'acts-as-taggable-on', '~> 3.4'
# Background jobs # Background jobs
gem 'sinatra', '~> 1.4.4', require: nil gem 'sinatra', '~> 1.4.4', require: false
gem 'sidekiq', '~> 4.0' gem 'sidekiq', '~> 4.0'
gem 'sidekiq-cron', '~> 0.4.0' gem 'sidekiq-cron', '~> 0.4.0'
gem 'redis-namespace' gem 'redis-namespace', '~> 1.5.2'
# HTTP requests # HTTP requests
gem "httparty", '~> 0.13.3' gem 'httparty', '~> 0.13.3'
# Colored output to console # Colored output to console
gem "rainbow", '~> 2.1.0' gem 'rainbow', '~> 2.1.0'
# GitLab settings # GitLab settings
gem 'settingslogic', '~> 2.0.9' gem 'settingslogic', '~> 2.0.9'
...@@ -156,7 +156,7 @@ gem 'settingslogic', '~> 2.0.9' ...@@ -156,7 +156,7 @@ gem 'settingslogic', '~> 2.0.9'
gem 'version_sorter', '~> 2.0.0' gem 'version_sorter', '~> 2.0.0'
# Cache # Cache
gem "redis-rails", '~> 4.0.0' gem 'redis-rails', '~> 4.0.0'
# Redis # Redis
gem 'redis', '~> 3.2' gem 'redis', '~> 3.2'
...@@ -169,13 +169,13 @@ gem 'tinder', '~> 1.10.0' ...@@ -169,13 +169,13 @@ gem 'tinder', '~> 1.10.0'
gem 'hipchat', '~> 1.5.0' gem 'hipchat', '~> 1.5.0'
# Flowdock integration # Flowdock integration
gem "gitlab-flowdock-git-hook", "~> 1.0.1" gem 'gitlab-flowdock-git-hook', '~> 1.0.1'
# Gemnasium integration # Gemnasium integration
gem "gemnasium-gitlab-service", "~> 0.2" gem 'gemnasium-gitlab-service', '~> 0.2'
# Slack integration # Slack integration
gem "slack-notifier", "~> 1.2.0" gem 'slack-notifier', '~> 1.2.0'
# Asana integration # Asana integration
gem 'asana', '~> 0.4.0' gem 'asana', '~> 0.4.0'
...@@ -187,20 +187,20 @@ gem 'ruby-fogbugz', '~> 0.2.1' ...@@ -187,20 +187,20 @@ gem 'ruby-fogbugz', '~> 0.2.1'
gem 'd3_rails', '~> 3.5.0' gem 'd3_rails', '~> 3.5.0'
# underscore-rails # underscore-rails
gem "underscore-rails", "~> 1.8.0" gem 'underscore-rails', '~> 1.8.0'
# Sanitize user input # Sanitize user input
gem "sanitize", '~> 2.0' gem 'sanitize', '~> 2.0'
gem 'babosa', '~> 1.0.2' gem 'babosa', '~> 1.0.2'
# Sanitizes SVG input # Sanitizes SVG input
gem "loofah", "~> 2.0.3" gem 'loofah', '~> 2.0.3'
# Working with license # Working with license
gem 'licensee', '~> 8.0.0' gem 'licensee', '~> 8.0.0'
# Protect against bruteforcing # Protect against bruteforcing
gem "rack-attack", '~> 4.3.1' gem 'rack-attack', '~> 4.3.1'
# Ace editor # Ace editor
gem 'ace-rails-ap', '~> 4.0.2' gem 'ace-rails-ap', '~> 4.0.2'
...@@ -214,16 +214,16 @@ gem 'charlock_holmes', '~> 0.7.3' ...@@ -214,16 +214,16 @@ gem 'charlock_holmes', '~> 0.7.3'
# Parse duration # Parse duration
gem 'chronic_duration', '~> 0.10.6' gem 'chronic_duration', '~> 0.10.6'
gem "sass-rails", '~> 5.0.0' gem 'sass-rails', '~> 5.0.0'
gem "coffee-rails", '~> 4.1.0' gem 'coffee-rails', '~> 4.1.0'
gem "uglifier", '~> 2.7.2' gem 'uglifier', '~> 2.7.2'
gem 'turbolinks', '~> 2.5.0' gem 'turbolinks', '~> 2.5.0'
gem 'jquery-turbolinks', '~> 2.1.0' gem 'jquery-turbolinks', '~> 2.1.0'
gem 'addressable', '~> 2.3.8' gem 'addressable', '~> 2.3.8'
gem 'bootstrap-sass', '~> 3.3.0' gem 'bootstrap-sass', '~> 3.3.0'
gem 'font-awesome-rails', '~> 4.6.1' gem 'font-awesome-rails', '~> 4.6.1'
gem 'gitlab_emoji', '~> 0.3.0' gem 'gemojione', '~> 2.6'
gem 'gon', '~> 6.0.1' gem 'gon', '~> 6.0.1'
gem 'jquery-atwho-rails', '~> 1.3.2' gem 'jquery-atwho-rails', '~> 1.3.2'
gem 'jquery-rails', '~> 4.1.0' gem 'jquery-rails', '~> 4.1.0'
...@@ -247,14 +247,13 @@ group :metrics do ...@@ -247,14 +247,13 @@ group :metrics do
end end
group :development do group :development do
gem "foreman" gem 'foreman', '~> 0.78.0'
gem 'brakeman', '~> 3.3.0', require: false gem 'brakeman', '~> 3.3.0', require: false
gem 'letter_opener_web', '~> 1.3.0' gem 'letter_opener_web', '~> 1.3.0'
gem 'quiet_assets', '~> 1.0.2'
gem 'rerun', '~> 0.11.0' gem 'rerun', '~> 0.11.0'
gem 'bullet', require: false gem 'bullet', '~> 5.0.0', require: false
gem 'rblineprof', platform: :mri, require: false gem 'rblineprof', '~> 0.3.6', platform: :mri, require: false
gem 'web-console', '~> 2.0' gem 'web-console', '~> 2.0'
# Better errors handler # Better errors handler
...@@ -262,23 +261,23 @@ group :development do ...@@ -262,23 +261,23 @@ group :development do
gem 'binding_of_caller', '~> 0.7.2' gem 'binding_of_caller', '~> 0.7.2'
# Docs generator # Docs generator
gem "sdoc", '~> 0.3.20' gem 'sdoc', '~> 0.3.20'
# thin instead webrick # thin instead webrick
gem 'thin', '~> 1.6.1' gem 'thin', '~> 1.7.0'
end end
group :development, :test do group :development, :test do
gem 'byebug', platform: :mri gem 'byebug', '~> 8.2.1', platform: :mri
gem 'pry-rails' gem 'pry-rails', '~> 0.3.4'
gem 'awesome_print', '~> 1.2.0', require: false gem 'awesome_print', '~> 1.2.0', require: false
gem 'fuubar', '~> 2.0.0' gem 'fuubar', '~> 2.0.0'
gem 'database_cleaner', '~> 1.4.0' gem 'database_cleaner', '~> 1.4.0'
gem 'factory_girl_rails', '~> 4.6.0' gem 'factory_girl_rails', '~> 4.6.0'
gem 'rspec-rails', '~> 3.4.0' gem 'rspec-rails', '~> 3.5.0'
gem 'rspec-retry' gem 'rspec-retry', '~> 0.4.5'
gem 'spinach-rails', '~> 0.2.1' gem 'spinach-rails', '~> 0.2.1'
gem 'spinach-rerun-reporter', '~> 0.0.2' gem 'spinach-rerun-reporter', '~> 0.0.2'
...@@ -304,14 +303,14 @@ group :development, :test do ...@@ -304,14 +303,14 @@ group :development, :test do
gem 'rubocop-rspec', '~> 1.5.0', require: false gem 'rubocop-rspec', '~> 1.5.0', require: false
gem 'scss_lint', '~> 0.47.0', require: false gem 'scss_lint', '~> 0.47.0', require: false
gem 'simplecov', '~> 0.11.0', require: false gem 'simplecov', '~> 0.11.0', require: false
gem 'flog', require: false gem 'flog', '~> 4.3.2', require: false
gem 'flay', require: false gem 'flay', '~> 2.6.1', require: false
gem 'bundler-audit', require: false gem 'bundler-audit', '~> 0.5.0', require: false
gem 'benchmark-ips', require: false gem 'benchmark-ips', '~> 2.3.0', require: false
gem "license_finder", require: false gem 'license_finder', '~> 2.1.0', require: false
gem 'knapsack' gem 'knapsack', '~> 1.11.0'
end end
group :test do group :test do
...@@ -319,30 +318,30 @@ group :test do ...@@ -319,30 +318,30 @@ group :test do
gem 'email_spec', '~> 1.6.0' gem 'email_spec', '~> 1.6.0'
gem 'webmock', '~> 1.21.0' gem 'webmock', '~> 1.21.0'
gem 'test_after_commit', '~> 0.4.2' gem 'test_after_commit', '~> 0.4.2'
gem 'sham_rack' gem 'sham_rack', '~> 1.3.6'
end end
group :production do group :production do
gem "gitlab_meta", '7.0' gem 'gitlab_meta', '7.0'
end end
gem "newrelic_rpm", '~> 3.14' gem 'newrelic_rpm', '~> 3.14'
gem 'octokit', '~> 4.3.0' gem 'octokit', '~> 4.3.0'
gem "mail_room", "~> 0.8" gem 'mail_room', '~> 0.8'
gem 'email_reply_parser', '~> 0.5.8' gem 'email_reply_parser', '~> 0.5.8'
## CI ## CI
gem 'activerecord-session_store', '~> 1.0.0' gem 'activerecord-session_store', '~> 1.0.0'
gem "nested_form", '~> 0.3.2' gem 'nested_form', '~> 0.3.2'
# OAuth # OAuth
gem 'oauth2', '~> 1.0.0' gem 'oauth2', '~> 1.2.0'
# Soft deletion # Soft deletion
gem "paranoia", "~> 2.0" gem 'paranoia', '~> 2.0'
# Health check # Health check
gem 'health_check', '~> 1.5.1' gem 'health_check', '~> 1.5.1'
......
GEM GEM
remote: https://rubygems.org/ remote: https://rubygems.org/
specs: specs:
RedCloth (4.2.9) RedCloth (4.3.2)
ace-rails-ap (4.0.2) ace-rails-ap (4.0.2)
actionmailer (4.2.6) actionmailer (4.2.6)
actionpack (= 4.2.6) actionpack (= 4.2.6)
...@@ -171,8 +171,8 @@ GEM ...@@ -171,8 +171,8 @@ GEM
diff-lcs (1.2.5) diff-lcs (1.2.5)
diffy (3.0.7) diffy (3.0.7)
docile (1.1.5) docile (1.1.5)
doorkeeper (3.1.0) doorkeeper (4.0.0)
railties (>= 3.2) railties (>= 4.2)
dropzonejs-rails (0.7.2) dropzonejs-rails (0.7.2)
rails (> 3.1) rails (> 3.1)
email_reply_parser (0.5.8) email_reply_parser (0.5.8)
...@@ -255,7 +255,7 @@ GEM ...@@ -255,7 +255,7 @@ GEM
ruby-progressbar (~> 1.4) ruby-progressbar (~> 1.4)
gemnasium-gitlab-service (0.2.6) gemnasium-gitlab-service (0.2.6)
rugged (~> 0.21) rugged (~> 0.21)
gemojione (2.2.1) gemojione (2.6.1)
json json
get_process_mem (0.2.0) get_process_mem (0.2.0)
gherkin-ruby (0.3.2) gherkin-ruby (0.3.2)
...@@ -274,8 +274,6 @@ GEM ...@@ -274,8 +274,6 @@ GEM
diff-lcs (~> 1.1) diff-lcs (~> 1.1)
mime-types (>= 1.16, < 3) mime-types (>= 1.16, < 3)
posix-spawn (~> 0.3) posix-spawn (~> 0.3)
gitlab_emoji (0.3.1)
gemojione (~> 2.2, >= 2.2.1)
gitlab_git (10.2.3) gitlab_git (10.2.3)
activesupport (~> 4.0) activesupport (~> 4.0)
charlock_holmes (~> 0.7.3) charlock_holmes (~> 0.7.3)
...@@ -355,7 +353,7 @@ GEM ...@@ -355,7 +353,7 @@ GEM
jquery-ui-rails (5.0.5) jquery-ui-rails (5.0.5)
railties (>= 3.2.16) railties (>= 3.2.16)
json (1.8.3) json (1.8.3)
jwt (1.5.2) jwt (1.5.4)
kaminari (0.17.0) kaminari (0.17.0)
actionpack (>= 3.0.0) actionpack (>= 3.0.0)
activesupport (>= 3.0.0) activesupport (>= 3.0.0)
...@@ -395,7 +393,7 @@ GEM ...@@ -395,7 +393,7 @@ GEM
mini_portile2 (2.1.0) mini_portile2 (2.1.0)
minitest (5.7.0) minitest (5.7.0)
mousetrap-rails (1.4.6) mousetrap-rails (1.4.6)
multi_json (1.11.2) multi_json (1.12.1)
multi_xml (0.5.5) multi_xml (0.5.5)
multipart-post (2.0.0) multipart-post (2.0.0)
mysql2 (0.3.20) mysql2 (0.3.20)
...@@ -408,12 +406,12 @@ GEM ...@@ -408,12 +406,12 @@ GEM
pkg-config (~> 1.1.7) pkg-config (~> 1.1.7)
numerizer (0.1.1) numerizer (0.1.1)
oauth (0.4.7) oauth (0.4.7)
oauth2 (1.0.0) oauth2 (1.2.0)
faraday (>= 0.8, < 0.10) faraday (>= 0.8, < 0.10)
jwt (~> 1.0) jwt (~> 1.0)
multi_json (~> 1.3) multi_json (~> 1.3)
multi_xml (~> 0.5) multi_xml (~> 0.5)
rack (~> 1.2) rack (>= 1.2, < 3)
octokit (4.3.0) octokit (4.3.0)
sawyer (~> 0.7.0, >= 0.5.3) sawyer (~> 0.7.0, >= 0.5.3)
omniauth (1.3.1) omniauth (1.3.1)
...@@ -441,7 +439,7 @@ GEM ...@@ -441,7 +439,7 @@ GEM
omniauth-gitlab (1.0.1) omniauth-gitlab (1.0.1)
omniauth (~> 1.0) omniauth (~> 1.0)
omniauth-oauth2 (~> 1.0) omniauth-oauth2 (~> 1.0)
omniauth-google-oauth2 (0.2.10) omniauth-google-oauth2 (0.4.1)
addressable (~> 2.3) addressable (~> 2.3)
jwt (~> 1.0) jwt (~> 1.0)
multi_json (~> 1.3) multi_json (~> 1.3)
...@@ -499,8 +497,6 @@ GEM ...@@ -499,8 +497,6 @@ GEM
pry-rails (0.3.4) pry-rails (0.3.4)
pry (>= 0.9.10) pry (>= 0.9.10)
pyu-ruby-sasl (0.0.3.3) pyu-ruby-sasl (0.0.3.3)
quiet_assets (1.0.3)
railties (>= 3.1, < 5.0)
rack (1.6.4) rack (1.6.4)
rack-accept (0.4.5) rack-accept (0.4.5)
rack (>= 0.4) rack (>= 0.4)
...@@ -556,7 +552,7 @@ GEM ...@@ -556,7 +552,7 @@ GEM
recaptcha (3.0.0) recaptcha (3.0.0)
json json
redcarpet (3.3.3) redcarpet (3.3.3)
redis (3.3.0) redis (3.2.2)
redis-actionpack (4.0.1) redis-actionpack (4.0.1)
actionpack (~> 4) actionpack (~> 4)
redis-rack (~> 1.5.0) redis-rack (~> 1.5.0)
...@@ -580,36 +576,36 @@ GEM ...@@ -580,36 +576,36 @@ GEM
listen (~> 3.0) listen (~> 3.0)
responders (2.1.1) responders (2.1.1)
railties (>= 4.2.0, < 5.1) railties (>= 4.2.0, < 5.1)
rinku (1.7.3) rinku (2.0.0)
rotp (2.1.2) rotp (2.1.2)
rouge (1.11.0) rouge (1.11.0)
rqrcode (0.7.0) rqrcode (0.7.0)
chunky_png chunky_png
rqrcode-rails3 (0.1.7) rqrcode-rails3 (0.1.7)
rqrcode (>= 0.4.2) rqrcode (>= 0.4.2)
rspec (3.4.0) rspec (3.5.0)
rspec-core (~> 3.4.0) rspec-core (~> 3.5.0)
rspec-expectations (~> 3.4.0) rspec-expectations (~> 3.5.0)
rspec-mocks (~> 3.4.0) rspec-mocks (~> 3.5.0)
rspec-core (3.4.4) rspec-core (3.5.0)
rspec-support (~> 3.4.0) rspec-support (~> 3.5.0)
rspec-expectations (3.4.0) rspec-expectations (3.5.0)
diff-lcs (>= 1.2.0, < 2.0) diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.4.0) rspec-support (~> 3.5.0)
rspec-mocks (3.4.1) rspec-mocks (3.5.0)
diff-lcs (>= 1.2.0, < 2.0) diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.4.0) rspec-support (~> 3.5.0)
rspec-rails (3.4.2) rspec-rails (3.5.0)
actionpack (>= 3.0, < 4.3) actionpack (>= 3.0)
activesupport (>= 3.0, < 4.3) activesupport (>= 3.0)
railties (>= 3.0, < 4.3) railties (>= 3.0)
rspec-core (~> 3.4.0) rspec-core (~> 3.5.0)
rspec-expectations (~> 3.4.0) rspec-expectations (~> 3.5.0)
rspec-mocks (~> 3.4.0) rspec-mocks (~> 3.5.0)
rspec-support (~> 3.4.0) rspec-support (~> 3.5.0)
rspec-retry (0.4.5) rspec-retry (0.4.5)
rspec-core rspec-core
rspec-support (3.4.1) rspec-support (3.5.0)
rubocop (0.40.0) rubocop (0.40.0)
parser (>= 2.3.1.0, < 3.0) parser (>= 2.3.1.0, < 3.0)
powerpack (~> 0.1) powerpack (~> 0.1)
...@@ -634,8 +630,8 @@ GEM ...@@ -634,8 +630,8 @@ GEM
sanitize (2.1.0) sanitize (2.1.0)
nokogiri (>= 1.4.4) nokogiri (>= 1.4.4)
sass (3.4.22) sass (3.4.22)
sass-rails (5.0.4) sass-rails (5.0.5)
railties (>= 4.0.0, < 5.0) railties (>= 4.0.0, < 6)
sass (~> 3.1) sass (~> 3.1)
sprockets (>= 2.8, < 4.0) sprockets (>= 2.8, < 4.0)
sprockets-rails (>= 2.0, < 4.0) sprockets-rails (>= 2.0, < 4.0)
...@@ -649,9 +645,9 @@ GEM ...@@ -649,9 +645,9 @@ GEM
sdoc (0.3.20) sdoc (0.3.20)
json (>= 1.1.3) json (>= 1.1.3)
rdoc (~> 3.10) rdoc (~> 3.10)
seed-fu (2.3.5) seed-fu (2.3.6)
activerecord (>= 3.1, < 4.3) activerecord (>= 3.1)
activesupport (>= 3.1, < 4.3) activesupport (>= 3.1)
select2-rails (3.5.9.3) select2-rails (3.5.9.3)
thor (~> 0.14) thor (~> 0.14)
sentry-raven (1.1.0) sentry-raven (1.1.0)
...@@ -662,10 +658,11 @@ GEM ...@@ -662,10 +658,11 @@ GEM
rack rack
shoulda-matchers (2.8.0) shoulda-matchers (2.8.0)
activesupport (>= 3.0.0) activesupport (>= 3.0.0)
sidekiq (4.1.2) sidekiq (4.1.4)
concurrent-ruby (~> 1.0) concurrent-ruby (~> 1.0)
connection_pool (~> 2.2, >= 2.2.0) connection_pool (~> 2.2, >= 2.2.0)
redis (~> 3.2, >= 3.2.1) redis (~> 3.2, >= 3.2.1)
sinatra (>= 1.4.7)
sidekiq-cron (0.4.0) sidekiq-cron (0.4.0)
redis-namespace (>= 1.5.2) redis-namespace (>= 1.5.2)
rufus-scheduler (>= 2.0.24) rufus-scheduler (>= 2.0.24)
...@@ -676,8 +673,8 @@ GEM ...@@ -676,8 +673,8 @@ GEM
json (~> 1.8) json (~> 1.8)
simplecov-html (~> 0.10.0) simplecov-html (~> 0.10.0)
simplecov-html (0.10.0) simplecov-html (0.10.0)
sinatra (1.4.6) sinatra (1.4.7)
rack (~> 1.4) rack (~> 1.5)
rack-protection (~> 1.4) rack-protection (~> 1.4)
tilt (>= 1.3, < 3) tilt (>= 1.3, < 3)
six (0.2.0) six (0.2.0)
...@@ -693,17 +690,17 @@ GEM ...@@ -693,17 +690,17 @@ GEM
spinach (>= 0.4) spinach (>= 0.4)
spinach-rerun-reporter (0.0.2) spinach-rerun-reporter (0.0.2)
spinach (~> 0.8) spinach (~> 0.8)
spring (1.7.1) spring (1.7.2)
spring-commands-rspec (1.0.4) spring-commands-rspec (1.0.4)
spring (>= 0.9.1) spring (>= 0.9.1)
spring-commands-spinach (1.1.0) spring-commands-spinach (1.1.0)
spring (>= 0.9.1) spring (>= 0.9.1)
spring-commands-teaspoon (0.0.2) spring-commands-teaspoon (0.0.2)
spring (>= 0.9.1) spring (>= 0.9.1)
sprockets (3.6.0) sprockets (3.6.2)
concurrent-ruby (~> 1.0) concurrent-ruby (~> 1.0)
rack (> 1, < 3) rack (> 1, < 3)
sprockets-rails (3.0.4) sprockets-rails (3.1.1)
actionpack (>= 4.0) actionpack (>= 4.0)
activesupport (>= 4.0) activesupport (>= 4.0)
sprockets (>= 3.0.0) sprockets (>= 3.0.0)
...@@ -727,10 +724,10 @@ GEM ...@@ -727,10 +724,10 @@ GEM
temple (0.7.7) temple (0.7.7)
test_after_commit (0.4.2) test_after_commit (0.4.2)
activerecord (>= 3.2) activerecord (>= 3.2)
thin (1.6.4) thin (1.7.0)
daemons (~> 1.0, >= 1.0.9) daemons (~> 1.0, >= 1.0.9)
eventmachine (~> 1.0, >= 1.0.4) eventmachine (~> 1.0, >= 1.0.4)
rack (~> 1.0) rack (>= 1, < 3)
thor (0.19.1) thor (0.19.1)
thread_safe (0.3.5) thread_safe (0.3.5)
tilt (2.0.5) tilt (2.0.5)
...@@ -804,12 +801,12 @@ PLATFORMS ...@@ -804,12 +801,12 @@ PLATFORMS
ruby ruby
DEPENDENCIES DEPENDENCIES
RedCloth (~> 4.2.9) RedCloth (~> 4.3.2)
ace-rails-ap (~> 4.0.2) ace-rails-ap (~> 4.0.2)
activerecord-session_store (~> 1.0.0) activerecord-session_store (~> 1.0.0)
acts-as-taggable-on (~> 3.4) acts-as-taggable-on (~> 3.4)
addressable (~> 2.3.8) addressable (~> 2.3.8)
after_commit_queue after_commit_queue (~> 1.3.0)
akismet (~> 2.0) akismet (~> 2.0)
allocations (~> 1.0) allocations (~> 1.0)
asana (~> 0.4.0) asana (~> 0.4.0)
...@@ -818,15 +815,15 @@ DEPENDENCIES ...@@ -818,15 +815,15 @@ DEPENDENCIES
awesome_print (~> 1.2.0) awesome_print (~> 1.2.0)
babosa (~> 1.0.2) babosa (~> 1.0.2)
base32 (~> 0.3.0) base32 (~> 0.3.0)
benchmark-ips benchmark-ips (~> 2.3.0)
better_errors (~> 1.0.1) better_errors (~> 1.0.1)
binding_of_caller (~> 0.7.2) binding_of_caller (~> 0.7.2)
bootstrap-sass (~> 3.3.0) bootstrap-sass (~> 3.3.0)
brakeman (~> 3.3.0) brakeman (~> 3.3.0)
browser (~> 2.2) browser (~> 2.2)
bullet bullet (~> 5.0.0)
bundler-audit bundler-audit (~> 0.5.0)
byebug byebug (~> 8.2.1)
capybara (~> 2.6.2) capybara (~> 2.6.2)
capybara-screenshot (~> 1.0.0) capybara-screenshot (~> 1.0.0)
carrierwave (~> 0.10.0) carrierwave (~> 0.10.0)
...@@ -841,14 +838,14 @@ DEPENDENCIES ...@@ -841,14 +838,14 @@ DEPENDENCIES
devise (~> 4.0) devise (~> 4.0)
devise-two-factor (~> 3.0.0) devise-two-factor (~> 3.0.0)
diffy (~> 3.0.3) diffy (~> 3.0.3)
doorkeeper (~> 3.1) doorkeeper (~> 4.0)
dropzonejs-rails (~> 0.7.1) dropzonejs-rails (~> 0.7.1)
email_reply_parser (~> 0.5.8) email_reply_parser (~> 0.5.8)
email_spec (~> 1.6.0) email_spec (~> 1.6.0)
factory_girl_rails (~> 4.6.0) factory_girl_rails (~> 4.6.0)
ffaker (~> 2.0.0) ffaker (~> 2.0.0)
flay flay (~> 2.6.1)
flog flog (~> 4.3.2)
fog-aws (~> 0.9) fog-aws (~> 0.9)
fog-azure (~> 0.0) fog-azure (~> 0.0)
fog-core (~> 1.40) fog-core (~> 1.40)
...@@ -857,13 +854,13 @@ DEPENDENCIES ...@@ -857,13 +854,13 @@ DEPENDENCIES
fog-openstack (~> 0.1) fog-openstack (~> 0.1)
fog-rackspace (~> 0.1.1) fog-rackspace (~> 0.1.1)
font-awesome-rails (~> 4.6.1) font-awesome-rails (~> 4.6.1)
foreman foreman (~> 0.78.0)
fuubar (~> 2.0.0) fuubar (~> 2.0.0)
gemnasium-gitlab-service (~> 0.2) gemnasium-gitlab-service (~> 0.2)
gemojione (~> 2.6)
github-linguist (~> 4.7.0) github-linguist (~> 4.7.0)
github-markup (~> 1.3.1) github-markup (~> 1.3.1)
gitlab-flowdock-git-hook (~> 1.0.1) gitlab-flowdock-git-hook (~> 1.0.1)
gitlab_emoji (~> 0.3.0)
gitlab_git (~> 10.2) gitlab_git (~> 10.2)
gitlab_meta (= 7.0) gitlab_meta (= 7.0)
gitlab_omniauth-ldap (~> 1.2.1) gitlab_omniauth-ldap (~> 1.2.1)
...@@ -884,9 +881,9 @@ DEPENDENCIES ...@@ -884,9 +881,9 @@ DEPENDENCIES
jquery-ui-rails (~> 5.0.0) jquery-ui-rails (~> 5.0.0)
jwt jwt
kaminari (~> 0.17.0) kaminari (~> 0.17.0)
knapsack knapsack (~> 1.11.0)
letter_opener_web (~> 1.3.0) letter_opener_web (~> 1.3.0)
license_finder license_finder (~> 2.1.0)
licensee (~> 8.0.0) licensee (~> 8.0.0)
loofah (~> 2.0.3) loofah (~> 2.0.3)
mail_room (~> 0.8) mail_room (~> 0.8)
...@@ -898,7 +895,7 @@ DEPENDENCIES ...@@ -898,7 +895,7 @@ DEPENDENCIES
net-ssh (~> 3.0.1) net-ssh (~> 3.0.1)
newrelic_rpm (~> 3.14) newrelic_rpm (~> 3.14)
nokogiri (~> 1.6.7, >= 1.6.7.2) nokogiri (~> 1.6.7, >= 1.6.7.2)
oauth2 (~> 1.0.0) oauth2 (~> 1.2.0)
octokit (~> 4.3.0) octokit (~> 4.3.0)
omniauth (~> 1.3.1) omniauth (~> 1.3.1)
omniauth-auth0 (~> 1.4.1) omniauth-auth0 (~> 1.4.1)
...@@ -908,7 +905,7 @@ DEPENDENCIES ...@@ -908,7 +905,7 @@ DEPENDENCIES
omniauth-facebook (~> 3.0.0) omniauth-facebook (~> 3.0.0)
omniauth-github (~> 1.1.1) omniauth-github (~> 1.1.1)
omniauth-gitlab (~> 1.0.0) omniauth-gitlab (~> 1.0.0)
omniauth-google-oauth2 (~> 0.2.0) omniauth-google-oauth2 (~> 0.4.1)
omniauth-kerberos (~> 0.3.0) omniauth-kerberos (~> 0.3.0)
omniauth-saml (~> 1.6.0) omniauth-saml (~> 1.6.0)
omniauth-shibboleth (~> 1.2.0) omniauth-shibboleth (~> 1.2.0)
...@@ -919,28 +916,27 @@ DEPENDENCIES ...@@ -919,28 +916,27 @@ DEPENDENCIES
pg (~> 0.18.2) pg (~> 0.18.2)
poltergeist (~> 1.9.0) poltergeist (~> 1.9.0)
premailer-rails (~> 1.9.0) premailer-rails (~> 1.9.0)
pry-rails pry-rails (~> 0.3.4)
quiet_assets (~> 1.0.2)
rack-attack (~> 4.3.1) rack-attack (~> 4.3.1)
rack-cors (~> 0.4.0) rack-cors (~> 0.4.0)
rack-oauth2 (~> 1.2.1) rack-oauth2 (~> 1.2.1)
rails (= 4.2.6) rails (= 4.2.6)
rails-deprecated_sanitizer (~> 1.0.3) rails-deprecated_sanitizer (~> 1.0.3)
rainbow (~> 2.1.0) rainbow (~> 2.1.0)
rblineprof rblineprof (~> 0.3.6)
rdoc (~> 3.6) rdoc (~> 3.6)
recaptcha (~> 3.0) recaptcha (~> 3.0)
redcarpet (~> 3.3.3) redcarpet (~> 3.3.3)
redis (~> 3.2) redis (~> 3.2)
redis-namespace redis-namespace (~> 1.5.2)
redis-rails (~> 4.0.0) redis-rails (~> 4.0.0)
request_store (~> 1.3.0) request_store (~> 1.3.0)
rerun (~> 0.11.0) rerun (~> 0.11.0)
responders (~> 2.0) responders (~> 2.0)
rouge (~> 1.11) rouge (~> 1.11)
rqrcode-rails3 (~> 0.1.7) rqrcode-rails3 (~> 0.1.7)
rspec-rails (~> 3.4.0) rspec-rails (~> 3.5.0)
rspec-retry rspec-retry (~> 0.4.5)
rubocop (~> 0.40.0) rubocop (~> 0.40.0)
rubocop-rspec (~> 1.5.0) rubocop-rspec (~> 1.5.0)
ruby-fogbugz (~> 0.2.1) ruby-fogbugz (~> 0.2.1)
...@@ -952,7 +948,7 @@ DEPENDENCIES ...@@ -952,7 +948,7 @@ DEPENDENCIES
select2-rails (~> 3.5.9) select2-rails (~> 3.5.9)
sentry-raven (~> 1.1.0) sentry-raven (~> 1.1.0)
settingslogic (~> 2.0.9) settingslogic (~> 2.0.9)
sham_rack sham_rack (~> 1.3.6)
shoulda-matchers (~> 2.8.0) shoulda-matchers (~> 2.8.0)
sidekiq (~> 4.0) sidekiq (~> 4.0)
sidekiq-cron (~> 0.4.0) sidekiq-cron (~> 0.4.0)
...@@ -973,7 +969,7 @@ DEPENDENCIES ...@@ -973,7 +969,7 @@ DEPENDENCIES
teaspoon (~> 1.1.0) teaspoon (~> 1.1.0)
teaspoon-jasmine (~> 2.2.0) teaspoon-jasmine (~> 2.2.0)
test_after_commit (~> 0.4.2) test_after_commit (~> 0.4.2)
thin (~> 1.6.1) thin (~> 1.7.0)
tinder (~> 1.10.0) tinder (~> 1.10.0)
turbolinks (~> 2.5.0) turbolinks (~> 2.5.0)
u2f (~> 0.2.1) u2f (~> 0.2.1)
......
app/assets/images/emoji.png

257 KB | W: | H:

app/assets/images/emoji.png

1000 KB | W: | H:

app/assets/images/emoji.png
app/assets/images/emoji.png
app/assets/images/emoji.png
app/assets/images/emoji.png
  • 2-up
  • Swipe
  • Onion skin
app/assets/images/emoji@2x.png

673 KB | W: | H:

app/assets/images/emoji@2x.png

2.38 MB | W: | H:

app/assets/images/emoji@2x.png
app/assets/images/emoji@2x.png
app/assets/images/emoji@2x.png
app/assets/images/emoji@2x.png
  • 2-up
  • Swipe
  • Onion skin
...@@ -54,7 +54,6 @@ ...@@ -54,7 +54,6 @@
#= require_directory ./u2f #= require_directory ./u2f
#= require_directory . #= require_directory .
#= require fuzzaldrin-plus #= require fuzzaldrin-plus
#= require cropper
#= require u2f #= require u2f
window.slugify = (text) -> window.slugify = (text) ->
......
...@@ -2,7 +2,7 @@ class @CiBuild ...@@ -2,7 +2,7 @@ class @CiBuild
@interval: null @interval: null
@state: null @state: null
constructor: (@build_url, @build_status, @state) -> constructor: (@page_url, @build_url, @build_status, @state) ->
clearInterval(CiBuild.interval) clearInterval(CiBuild.interval)
# Init breakpoint checker # Init breakpoint checker
...@@ -41,7 +41,7 @@ class @CiBuild ...@@ -41,7 +41,7 @@ class @CiBuild
# Only valid for runnig build when output changes during time # Only valid for runnig build when output changes during time
# #
CiBuild.interval = setInterval => CiBuild.interval = setInterval =>
if window.location.href.split("#").first() is @build_url if window.location.href.split("#").first() is @page_url
@getBuildTrace() @getBuildTrace()
, 4000 , 4000
...@@ -57,7 +57,7 @@ class @CiBuild ...@@ -57,7 +57,7 @@ class @CiBuild
getBuildTrace: -> getBuildTrace: ->
$.ajax $.ajax
url: "#{@build_url}/trace.json?state=#{encodeURIComponent(@state)}" url: "#{@page_url}/trace.json?state=#{encodeURIComponent(@state)}"
dataType: "json" dataType: "json"
success: (log) => success: (log) =>
if log.state if log.state
...@@ -70,7 +70,7 @@ class @CiBuild ...@@ -70,7 +70,7 @@ class @CiBuild
$('.js-build-output').html log.html $('.js-build-output').html log.html
@checkAutoscroll() @checkAutoscroll()
else if log.status isnt @build_status else if log.status isnt @build_status
Turbolinks.visit @build_url Turbolinks.visit @page_url
checkAutoscroll: -> checkAutoscroll: ->
$("html,body").scrollTop $("#build-trace").height() if "enabled" is $("#autoscroll-button").data("state") $("html,body").scrollTop $("#build-trace").height() if "enabled" is $("#autoscroll-button").data("state")
......
...@@ -127,11 +127,10 @@ class Dispatcher ...@@ -127,11 +127,10 @@ class Dispatcher
when 'groups' when 'groups'
new UsersSelect() new UsersSelect()
when 'projects' when 'projects'
new NamespaceSelect() new NamespaceSelects()
when 'dashboard', 'root' when 'dashboard', 'root'
shortcut_handler = new ShortcutsDashboardNavigation() shortcut_handler = new ShortcutsDashboardNavigation()
when 'profiles' when 'profiles'
new Profile()
new NotificationsForm() new NotificationsForm()
new NotificationsDropdown() new NotificationsDropdown()
when 'projects' when 'projects'
......
...@@ -70,12 +70,12 @@ class @DropzoneInput ...@@ -70,12 +70,12 @@ class @DropzoneInput
pasteText response.link.markdown pasteText response.link.markdown
return return
error: (temp, errorMessage) -> error: (temp) ->
errorAlert = $(form).find('.error-alert') errorAlert = $(form).find('.error-alert')
checkIfMsgExists = errorAlert.children().length checkIfMsgExists = errorAlert.children().length
if checkIfMsgExists is 0 if checkIfMsgExists is 0
errorAlert.append divAlert errorAlert.append divAlert
$(".div-dropzone-alert").append btnAlert + errorMessage $(".div-dropzone-alert").append "#{btnAlert}Attaching the file failed."
return return
totaluploadprogress: (totalUploadProgress) -> totaluploadprogress: (totalUploadProgress) ->
......
...@@ -4,7 +4,7 @@ window.GitLab ?= {} ...@@ -4,7 +4,7 @@ window.GitLab ?= {}
GitLab.GfmAutoComplete = GitLab.GfmAutoComplete =
dataLoading: false dataLoading: false
dataLoaded: false dataLoaded: false
cachedData: {}
dataSource: '' dataSource: ''
# Emoji # Emoji
...@@ -55,7 +55,7 @@ GitLab.GfmAutoComplete = ...@@ -55,7 +55,7 @@ GitLab.GfmAutoComplete =
@setupAtWho() @setupAtWho()
if @dataSource if @dataSource
if !@dataLoading if not @dataLoading and not @cachedData
@dataLoading = true @dataLoading = true
# We should wait until initializations are done # We should wait until initializations are done
...@@ -70,6 +70,8 @@ GitLab.GfmAutoComplete = ...@@ -70,6 +70,8 @@ GitLab.GfmAutoComplete =
@loadData(data) @loadData(data)
, 1000) , 1000)
if @cachedData?
@loadData(@cachedData)
setupAtWho: -> setupAtWho: ->
# Emoji # Emoji
...@@ -188,7 +190,7 @@ GitLab.GfmAutoComplete = ...@@ -188,7 +190,7 @@ GitLab.GfmAutoComplete =
callbacks: callbacks:
beforeSave: (merges) -> beforeSave: (merges) ->
sanitizeLabelTitle = (title)-> sanitizeLabelTitle = (title)->
if /\w+\s+\w+/g.test(title) if /[\w\?&]+\s+[\w\?&]+/g.test(title)
"\"#{sanitize(title)}\"" "\"#{sanitize(title)}\""
else else
sanitize(title) sanitize(title)
...@@ -205,6 +207,7 @@ GitLab.GfmAutoComplete = ...@@ -205,6 +207,7 @@ GitLab.GfmAutoComplete =
$.getJSON(dataSource) $.getJSON(dataSource)
loadData: (data) -> loadData: (data) ->
@cachedData = data
@dataLoaded = true @dataLoaded = true
# load members # load members
......
...@@ -56,6 +56,7 @@ class GitLabDropdownFilter ...@@ -56,6 +56,7 @@ class GitLabDropdownFilter
return BLUR_KEYCODES.indexOf(keyCode) >= 0 return BLUR_KEYCODES.indexOf(keyCode) >= 0
filter: (search_text) -> filter: (search_text) ->
@options.onFilter(search_text) if @options.onFilter
data = @options.data() data = @options.data()
if data? and not @options.filterByText if data? and not @options.filterByText
...@@ -195,6 +196,7 @@ class GitLabDropdown ...@@ -195,6 +196,7 @@ class GitLabDropdown
@filter = new GitLabDropdownFilter @filterInput, @filter = new GitLabDropdownFilter @filterInput,
filterInputBlur: @filterInputBlur filterInputBlur: @filterInputBlur
filterByText: @options.filterByText filterByText: @options.filterByText
onFilter: @options.onFilter
remote: @options.filterRemote remote: @options.filterRemote
query: @options.data query: @options.data
keys: searchFields keys: searchFields
...@@ -530,7 +532,7 @@ class GitLabDropdown ...@@ -530,7 +532,7 @@ class GitLabDropdown
if $el.length if $el.length
e.preventDefault() e.preventDefault()
e.stopImmediatePropagation() e.stopImmediatePropagation()
$(selector, @dropdown)[0].click() $el.first().trigger('click')
addArrowKeyEvent: -> addArrowKeyEvent: ->
ARROW_KEY_CODES = [38, 40] ARROW_KEY_CODES = [38, 40]
......
...@@ -7,13 +7,16 @@ class @ImporterStatus ...@@ -7,13 +7,16 @@ class @ImporterStatus
$('.js-add-to-import') $('.js-add-to-import')
.off 'click' .off 'click'
.on 'click', (e) => .on 'click', (e) =>
new_namespace = null
$btn = $(e.currentTarget) $btn = $(e.currentTarget)
$tr = $btn.closest('tr') $tr = $btn.closest('tr')
$target_field = $tr.find('.import-target')
$namespace_input = $target_field.find('input')
id = $tr.attr('id').replace('repo_', '') id = $tr.attr('id').replace('repo_', '')
if $tr.find('.import-target input').length > 0 new_namespace = null
new_namespace = $tr.find('.import-target input').prop('value')
$tr.find('.import-target').empty().append("#{new_namespace} / #{$tr.find('.import-target').data('project_name')}") if $namespace_input.length > 0
new_namespace = $namespace_input.prop('value')
$target_field.empty().append("#{new_namespace}/#{$target_field.data('project_name')}")
$btn $btn
.disable() .disable()
......
...@@ -11,11 +11,11 @@ issuable_created = false ...@@ -11,11 +11,11 @@ issuable_created = false
initTemplates: -> initTemplates: ->
Issuable.labelRow = _.template( Issuable.labelRow = _.template(
'<% _.each(labels, function(label){ %> '<% _.each(labels, function(label){ %>
<span class="label-row btn-group" role="group" aria-label="<%= _.escape(label.title) %>" style="color: <%= label.text_color %>;"> <span class="label-row btn-group" role="group" aria-label="<%- label.title %>" style="color: <%- label.text_color %>;">
<a href="#" class="btn btn-transparent has-tooltip" style="background-color: <%= label.color %>;" title="<%= _.escape(label.description) %>" data-container="body"> <a href="#" class="btn btn-transparent has-tooltip" style="background-color: <%- label.color %>;" title="<%- label.description %>" data-container="body">
<%= _.escape(label.title) %> <%- label.title %>
</a> </a>
<button type="button" class="btn btn-transparent label-remove js-label-filter-remove" style="background-color: <%= label.color %>;" data-label="<%= _.escape(label.title) %>"> <button type="button" class="btn btn-transparent label-remove js-label-filter-remove" style="background-color: <%- label.color %>;" data-label="<%- label.title %>">
<i class="fa fa-times"></i> <i class="fa fa-times"></i>
</button> </button>
</span> </span>
......
...@@ -32,9 +32,9 @@ class @LabelsSelect ...@@ -32,9 +32,9 @@ class @LabelsSelect
if issueUpdateURL if issueUpdateURL
labelHTMLTemplate = _.template( labelHTMLTemplate = _.template(
'<% _.each(labels, function(label){ %> '<% _.each(labels, function(label){ %>
<a href="<%= ["",issueURLSplit[1], issueURLSplit[2],""].join("/") %>issues?label_name[]=<%= _.escape(label.title) %>"> <a href="<%- ["",issueURLSplit[1], issueURLSplit[2],""].join("/") %>issues?label_name[]=<%- encodeURIComponent(label.title) %>">
<span class="label has-tooltip color-label" title="<%= _.escape(label.description) %>" style="background-color: <%= label.color %>; color: <%= label.text_color %>;"> <span class="label has-tooltip color-label" title="<%- label.description %>" style="background-color: <%- label.color %>; color: <%- label.text_color %>;">
<%= _.escape(label.title) %> <%- label.title %>
</span> </span>
</a> </a>
<% }); %>' <% }); %>'
...@@ -261,7 +261,7 @@ class @LabelsSelect ...@@ -261,7 +261,7 @@ class @LabelsSelect
$a.attr('data-label-id', label.id) $a.attr('data-label-id', label.id)
$a.addClass(selectedClass.join(' ')) $a.addClass(selectedClass.join(' '))
.html("#{colorEl} #{_.escape(label.title)}") .html("#{colorEl} #{label.title}")
# Return generated html # Return generated html
$li.html($a).prop('outerHTML') $li.html($a).prop('outerHTML')
...@@ -288,7 +288,7 @@ class @LabelsSelect ...@@ -288,7 +288,7 @@ class @LabelsSelect
fieldName: $dropdown.data('field-name') fieldName: $dropdown.data('field-name')
id: (label) -> id: (label) ->
if $dropdown.hasClass("js-filter-submit") and not label.isAny? if $dropdown.hasClass("js-filter-submit") and not label.isAny?
_.escape label.title label.title
else else
label.id label.id
......
...@@ -5,12 +5,12 @@ ...@@ -5,12 +5,12 @@
w.gl.utils.isInGroupsPage = -> w.gl.utils.isInGroupsPage = ->
return $('body').data('page').split(':')[0] is 'groups' return gl.utils.getPagePath() is 'groups'
w.gl.utils.isInProjectPage = -> w.gl.utils.isInProjectPage = ->
return $('body').data('page').split(':')[0] is 'projects' return gl.utils.getPagePath() is 'projects'
w.gl.utils.getProjectSlug = -> w.gl.utils.getProjectSlug = ->
...@@ -40,6 +40,9 @@ ...@@ -40,6 +40,9 @@
e.stopImmediatePropagation() e.stopImmediatePropagation()
return false return false
gl.utils.getPagePath = ->
return $('body').data('page').split(':')[0]
jQuery.timefor = (time, suffix, expiredLabel) -> jQuery.timefor = (time, suffix, expiredLabel) ->
......
...@@ -49,8 +49,9 @@ ...@@ -49,8 +49,9 @@
insertText = "#{startChar}#{tag}#{selected}#{if wrap then tag else ' '}" insertText = "#{startChar}#{tag}#{selected}#{if wrap then tag else ' '}"
if document.queryCommandSupported('insertText') if document.queryCommandSupported('insertText')
document.execCommand 'insertText', false, insertText inserted = document.execCommand 'insertText', false, insertText
else
unless inserted
try try
document.execCommand("ms-beginUndoUnit") document.execCommand("ms-beginUndoUnit")
......
...@@ -24,14 +24,14 @@ class @MilestoneSelect ...@@ -24,14 +24,14 @@ class @MilestoneSelect
if issueUpdateURL if issueUpdateURL
milestoneLinkTemplate = _.template( milestoneLinkTemplate = _.template(
'<a href="/<%= namespace %>/<%= path %>/milestones/<%= iid %>" class="bold has-tooltip" data-container="body" title="<%= remaining %>"><%= _.escape(title) %></a>' '<a href="/<%- namespace %>/<%- path %>/milestones/<%- iid %>" class="bold has-tooltip" data-container="body" title="<%- remaining %>"><%- title %></a>'
) )
milestoneLinkNoneTemplate = '<span class="no-value">None</span>' milestoneLinkNoneTemplate = '<span class="no-value">None</span>'
collapsedSidebarLabelTemplate = _.template( collapsedSidebarLabelTemplate = _.template(
'<span class="has-tooltip" data-container="body" title="<%= remaining %>" data-placement="left"> '<span class="has-tooltip" data-container="body" title="<%- remaining %>" data-placement="left">
<%= _.escape(title) %> <%- title %>
</span>' </span>'
) )
......
class @NamespaceSelect class @NamespaceSelect
constructor: -> constructor: (opts) ->
namespaceFormatResult = (namespace) -> {
markup = "<div class='namespace-result'>" @dropdown
markup += "<span class='namespace-kind'>" + namespace.kind + "</span>" } = opts
markup += "<span class='namespace-path'>" + namespace.path + "</span>"
markup += "</div>" showAny = true
markup fieldName = 'namespace_id'
formatSelection = (namespace) -> if @dropdown.attr 'data-field-name'
namespace.kind + ": " + namespace.path fieldName = @dropdown.data 'fieldName'
$('.ajax-namespace-select').each (i, select) -> if @dropdown.attr 'data-show-any'
$(select).select2 showAny = @dropdown.data 'showAny'
placeholder: "Search for namespace"
multiple: $(select).hasClass('multiselect') @dropdown.glDropdown(
minimumInputLength: 0 filterable: true
query: (query) -> selectable: true
Api.namespaces query.term, (namespaces) -> filterRemote: true
data = { results: namespaces } search:
query.callback(data) fields: ['path']
fieldName: fieldName
dropdownCssClass: "ajax-namespace-dropdown" toggleLabel: (selected) ->
formatResult: namespaceFormatResult return if not selected.id? then selected.text else "#{selected.kind}: #{selected.path}"
formatSelection: formatSelection data: (term, dataCallback) ->
Api.namespaces term, (namespaces) ->
if showAny
anyNamespace =
text: 'Any namespace'
id: null
namespaces.unshift(anyNamespace)
namespaces.splice 1, 0, 'divider'
dataCallback(namespaces)
text: (namespace) ->
return if not namespace.id? then namespace.text else "#{namespace.kind}: #{namespace.path}"
renderRow: @renderRow
clicked: @onSelectItem
)
onSelectItem: (item, el, e) =>
e.preventDefault()
class @NamespaceSelects
constructor: (opts = {}) ->
{
@$dropdowns = $('.js-namespace-select')
} = opts
@$dropdowns.each (i, dropdown) ->
$dropdown = $(dropdown)
new NamespaceSelect(
dropdown: $dropdown
)
...@@ -100,13 +100,40 @@ class @Notes ...@@ -100,13 +100,40 @@ class @Notes
$('.note .js-task-list-container').taskList('disable') $('.note .js-task-list-container').taskList('disable')
$(document).off 'tasklist:changed', '.note .js-task-list-container' $(document).off 'tasklist:changed', '.note .js-task-list-container'
keydownNoteText: (e) -> keydownNoteText: (e) =>
$this = $(this) return if isMetaKey e
if $this.val() is '' and e.which is 38 and not isMetaKey e
myLastNote = $("li.note[data-author-id='#{gon.current_user_id}'][data-editable]:last") $textarea = $(e.target)
if myLastNote.length
myLastNoteEditBtn = myLastNote.find('.js-note-edit') # Edit previous note when UP arrow is hit
myLastNoteEditBtn.trigger('click', [true, myLastNote]) switch e.which
when 38
return unless $textarea.val() is ''
myLastNote = $("li.note[data-author-id='#{gon.current_user_id}'][data-editable]:last")
if myLastNote.length
myLastNoteEditBtn = myLastNote.find('.js-note-edit')
myLastNoteEditBtn.trigger('click', [true, myLastNote])
# Cancel creating diff note or editing any note when ESCAPE is hit
when 27
discussionNoteForm = $textarea.closest('.js-discussion-note-form')
if discussionNoteForm.length
if $textarea.val() isnt ''
return unless confirm('Are you sure you want to cancel creating this comment?')
@removeDiscussionNoteForm(discussionNoteForm)
return
editNote = $textarea.closest('.note')
if editNote.length
originalText = $textarea.closest('form').data('original-note')
newText = $textarea.val()
if originalText isnt newText
return unless confirm('Are you sure you want to cancel editing this comment?')
@removeNoteEditForm(editNote)
isMetaKey = (e) -> isMetaKey = (e) ->
(e.metaKey or e.ctrlKey or e.altKey or e.shiftKey) (e.metaKey or e.ctrlKey or e.altKey or e.shiftKey)
...@@ -213,12 +240,16 @@ class @Notes ...@@ -213,12 +240,16 @@ class @Notes
@note_ids.push(note.id) @note_ids.push(note.id)
form = $("#new-discussion-note-form-#{note.discussion_id}") form = $("#new-discussion-note-form-#{note.discussion_id}")
if note.original_discussion_id? and form.length is 0
form = $("#new-discussion-note-form-#{note.original_discussion_id}")
row = form.closest("tr") row = form.closest("tr")
note_html = $(note.html) note_html = $(note.html)
note_html.syntaxHighlight() note_html.syntaxHighlight()
# is this the first note of discussion? # is this the first note of discussion?
discussionContainer = $(".notes[data-discussion-id='" + note.discussion_id + "']") discussionContainer = $(".notes[data-discussion-id='" + note.discussion_id + "']")
if note.original_discussion_id? and discussionContainer.length is 0
discussionContainer = $(".notes[data-discussion-id='" + note.original_discussion_id + "']")
if discussionContainer.length is 0 if discussionContainer.length is 0
# insert the note and the reply button after the temp row # insert the note and the reply button after the temp row
row.after note.discussion_html row.after note.discussion_html
...@@ -291,6 +322,7 @@ class @Notes ...@@ -291,6 +322,7 @@ class @Notes
form.addClass "js-main-target-form" form.addClass "js-main-target-form"
form.find("#note_line_code").remove() form.find("#note_line_code").remove()
form.find("#note_position").remove()
form.find("#note_type").remove() form.find("#note_type").remove()
### ###
...@@ -308,10 +340,12 @@ class @Notes ...@@ -308,10 +340,12 @@ class @Notes
new Autosave textarea, [ new Autosave textarea, [
"Note" "Note"
form.find("#note_commit_id").val()
form.find("#note_line_code").val()
form.find("#note_noteable_type").val() form.find("#note_noteable_type").val()
form.find("#note_noteable_id").val() form.find("#note_noteable_id").val()
form.find("#note_commit_id").val()
form.find("#note_type").val()
form.find("#note_line_code").val()
form.find("#note_position").val()
] ]
### ###
...@@ -401,9 +435,12 @@ class @Notes ...@@ -401,9 +435,12 @@ class @Notes
Hides edit form and restores the original note text to the editor textarea. Hides edit form and restores the original note text to the editor textarea.
### ###
cancelEdit: (e) -> cancelEdit: (e) =>
e.preventDefault() e.preventDefault()
note = $(this).closest(".note") note = $(e.target).closest('.note')
@removeNoteEditForm(note)
removeNoteEditForm: (note) ->
form = note.find(".current-note-edit-form") form = note.find(".current-note-edit-form")
note.removeClass "is-editting" note.removeClass "is-editting"
form.removeClass("current-note-edit-form") form.removeClass("current-note-edit-form")
...@@ -482,10 +519,12 @@ class @Notes ...@@ -482,10 +519,12 @@ class @Notes
setupDiscussionNoteForm: (dataHolder, form) => setupDiscussionNoteForm: (dataHolder, form) =>
# setup note target # setup note target
form.attr 'id', "new-discussion-note-form-#{dataHolder.data("discussionId")}" form.attr 'id', "new-discussion-note-form-#{dataHolder.data("discussionId")}"
form.attr "data-line-code", dataHolder.data("lineCode")
form.find("#note_type").val dataHolder.data("noteType") form.find("#note_type").val dataHolder.data("noteType")
form.find("#line_type").val dataHolder.data("lineType") form.find("#line_type").val dataHolder.data("lineType")
form.find("#note_commit_id").val dataHolder.data("commitId") form.find("#note_commit_id").val dataHolder.data("commitId")
form.find("#note_line_code").val dataHolder.data("lineCode") form.find("#note_line_code").val dataHolder.data("lineCode")
form.find("#note_position").val dataHolder.attr("data-position")
form.find("#note_noteable_type").val dataHolder.data("noteableType") form.find("#note_noteable_type").val dataHolder.data("noteableType")
form.find("#note_noteable_id").val dataHolder.data("noteableId") form.find("#note_noteable_id").val dataHolder.data("noteableId")
form.find('.js-note-discard') form.find('.js-note-discard')
......
...@@ -78,3 +78,6 @@ $ -> ...@@ -78,3 +78,6 @@ $ ->
if comment && comment.length > 1 && $title.val() == '' if comment && comment.length > 1 && $title.val() == ''
$title.val(comment[1]).change() $title.val(comment[1]).change()
if gl.utils.getPagePath() == 'profiles'
new Profile()
class @ProtectedBranchSelect
constructor: (currentProject) ->
$('.dropdown-footer').hide();
@dropdown = $('.js-protected-branch-select').glDropdown(
data: @getProtectedBranches
filterable: true
remote: false
search:
fields: ['title']
selectable: true
toggleLabel: (selected) -> if (selected and 'id' of selected) then selected.title else 'Protected Branch'
fieldName: 'protected_branch[name]'
text: (protected_branch) -> _.escape(protected_branch.title)
id: (protected_branch) -> _.escape(protected_branch.id)
onFilter: @toggleCreateNewButton
clicked: () -> $('.protect-branch-btn').attr('disabled', false)
)
$('.create-new-protected-branch').on 'click', (event) =>
# Refresh the dropdown's data, which ends up calling `getProtectedBranches`
@dropdown.data('glDropdown').remote.execute()
@dropdown.data('glDropdown').selectRowAtIndex(event, 0)
getProtectedBranches: (term, callback) =>
if @selectedBranch
callback(gon.open_branches.concat(@selectedBranch))
else
callback(gon.open_branches)
toggleCreateNewButton: (branchName) =>
@selectedBranch = { title: branchName, id: branchName, text: branchName }
if branchName is ''
$('.protected-branch-select-footer-list').addClass('hidden')
$('.dropdown-footer').hide();
else
$('.create-new-protected-branch').text("Create Protected Branch: #{branchName}")
$('.protected-branch-select-footer-list').removeClass('hidden')
$('.dropdown-footer').show();
...@@ -11,7 +11,8 @@ $ -> ...@@ -11,7 +11,8 @@ $ ->
dataType: "json" dataType: "json"
data: data:
id: id id: id
developers_can_push: checked protected_branch:
developers_can_push: checked
success: -> success: ->
row = $(e.target) row = $(e.target)
......
...@@ -61,8 +61,8 @@ class @UsersSelect ...@@ -61,8 +61,8 @@ class @UsersSelect
collapsedAssigneeTemplate = _.template( collapsedAssigneeTemplate = _.template(
'<% if( avatar ) { %> '<% if( avatar ) { %>
<a class="author_link" href="/u/<%= username %>"> <a class="author_link" href="/u/<%- username %>">
<img width="24" class="avatar avatar-inline s24" alt="" src="<%= avatar %>"> <img width="24" class="avatar avatar-inline s24" alt="" src="<%- avatar %>">
<span class="author">Toni Boehm</span> <span class="author">Toni Boehm</span>
</a> </a>
<% } else { %> <% } else { %>
...@@ -72,13 +72,13 @@ class @UsersSelect ...@@ -72,13 +72,13 @@ class @UsersSelect
assigneeTemplate = _.template( assigneeTemplate = _.template(
'<% if (username) { %> '<% if (username) { %>
<a class="author_link bold" href="/u/<%= username %>"> <a class="author_link bold" href="/u/<%- username %>">
<% if( avatar ) { %> <% if( avatar ) { %>
<img width="32" class="avatar avatar-inline s32" alt="" src="<%= avatar %>"> <img width="32" class="avatar avatar-inline s32" alt="" src="<%- avatar %>">
<% } %> <% } %>
<span class="author"><%= name %></span> <span class="author"><%- name %></span>
<span class="username"> <span class="username">
@<%= username %> @<%- username %>
</span> </span>
</a> </a>
<% } else { %> <% } else { %>
......
.blank-state-welcome {
text-align: center;
border-bottom: 1px solid $border-color;
.blank-state-text {
margin-bottom: 0;
}
}
.blank-state { .blank-state {
padding-top: 20px; padding-top: 20px;
padding-bottom: 20px; padding-bottom: 20px;
...@@ -6,7 +15,15 @@ ...@@ -6,7 +15,15 @@
.blank-state-no-icon { .blank-state-no-icon {
padding-top: 40px; padding-top: 40px;
padding-bottom: 40px; padding-bottom: 40px;
}
.blank-state-icon {
padding-bottom: 20px;
path {
fill: $gray-darkest;
}
} }
.blank-state-title { .blank-state-title {
...@@ -21,3 +38,7 @@ ...@@ -21,3 +38,7 @@
margin-bottom: $gl-padding; margin-bottom: $gl-padding;
font-size: 15px; font-size: 15px;
} }
.blank-state-welcome-title {
font-size: 24px;
}
...@@ -281,3 +281,21 @@ ...@@ -281,3 +281,21 @@
color: $gl-icon-color; color: $gl-icon-color;
} }
} }
.clone-dropdown-btn a {
color: $dropdown-link-color;
&:hover {
text-decoration: none;
}
}
.btn-static {
background-color: $background-color !important;
border: 1px solid lightgrey;
cursor: default;
&:active {
-moz-box-shadow: inset 0 0 0 white;
-webkit-box-shadow: inset 0 0 0 white;
box-shadow: inset 0 0 0 white;
}
}
...@@ -20,8 +20,12 @@ ...@@ -20,8 +20,12 @@
} }
.open { .open {
.dropdown-menu { .dropdown-menu,
.dropdown-menu-nav {
display: block; display: block;
@media (max-width: $screen-xs-max) {
width: 100%;
}
} }
.dropdown-menu-toggle { .dropdown-menu-toggle {
...@@ -64,9 +68,14 @@ ...@@ -64,9 +68,14 @@
color: $dropdown-toggle-hover-icon-color; color: $dropdown-toggle-hover-icon-color;
} }
} }
&.large {
width: 200px;
}
} }
.dropdown-menu { .dropdown-menu,
.dropdown-menu-nav {
display: none; display: none;
position: absolute; position: absolute;
top: 100%; top: 100%;
...@@ -77,7 +86,7 @@ ...@@ -77,7 +86,7 @@
margin-bottom: 0; margin-bottom: 0;
font-size: 15px; font-size: 15px;
font-weight: normal; font-weight: normal;
padding: 10px 0; padding: 8px 0;
background-color: $dropdown-bg; background-color: $dropdown-bg;
border: 1px solid $dropdown-border-color; border: 1px solid $dropdown-border-color;
border-radius: $border-radius-base; border-radius: $border-radius-base;
...@@ -101,12 +110,12 @@ ...@@ -101,12 +110,12 @@
li { li {
text-align: left; text-align: left;
list-style: none; list-style: none;
padding: 0 10px; padding: 0 8px;
} }
.divider { .divider {
height: 1px; height: 1px;
margin: 8px 10px; margin: 8px;
padding: 0; padding: 0;
background-color: $dropdown-divider-color; background-color: $dropdown-divider-color;
} }
...@@ -122,7 +131,7 @@ ...@@ -122,7 +131,7 @@
a { a {
display: block; display: block;
position: relative; position: relative;
padding: 5px 10px; padding: 5px 8px;
color: $dropdown-link-color; color: $dropdown-link-color;
line-height: initial; line-height: initial;
text-overflow: ellipsis; text-overflow: ellipsis;
......
...@@ -50,7 +50,7 @@ ...@@ -50,7 +50,7 @@
} }
a:not(.btn) { a:not(.btn) {
color: $gl-dark-link-color; color: $gl-text-color;
} }
.left-options { .left-options {
......
...@@ -20,17 +20,6 @@ ...@@ -20,17 +20,6 @@
.sidebar-wrapper { .sidebar-wrapper {
background: $color-darker; background: $color-darker;
.sidebar-user {
background: $color-darker;
color: $color-light;
&:hover {
background-color: $color-dark;
color: $white-light;
text-decoration: none;
}
}
} }
.nav-sidebar li { .nav-sidebar li {
......
...@@ -60,7 +60,7 @@ header { ...@@ -60,7 +60,7 @@ header {
margin: ($header-height - 28) / 2 0; margin: ($header-height - 28) / 2 0;
margin-left: 10px; margin-left: 10px;
height: 28px; height: 28px;
width: 28px; min-width: 28px;
line-height: 28px; line-height: 28px;
text-align: center; text-align: center;
...@@ -241,14 +241,23 @@ header { ...@@ -241,14 +241,23 @@ header {
.navbar-collapse { .navbar-collapse {
padding-left: 5px; padding-left: 5px;
li { .nav > li {
display: table-cell; display: table-cell;
width: 1%; width: 1%;
a {
margin-left: 8px !important;
}
} }
} }
} }
} }
.header-user {
.dropdown-menu-nav {
width: 140px;
margin-top: -5px;
}
}
.header-user-avatar {
float: left;
margin-right: 5px;
border-radius: 50%;
}
...@@ -137,6 +137,15 @@ ul.content-list { ...@@ -137,6 +137,15 @@ ul.content-list {
padding-top: 1px; padding-top: 1px;
float: right; float: right;
> .control-text {
margin-right: $gl-padding-top;
line-height: 40px;
&:last-child {
margin-right: 0;
}
}
> .btn, > .btn,
> .btn-group { > .btn-group {
margin-right: $gl-padding-top; margin-right: $gl-padding-top;
...@@ -166,6 +175,12 @@ ul.content-list { ...@@ -166,6 +175,12 @@ ul.content-list {
.panel > .content-list > li { .panel > .content-list > li {
padding: $gl-padding-top $gl-padding; padding: $gl-padding-top $gl-padding;
&.commit {
@media (min-width: $screen-sm-min) {
padding-left: 46px + $gl-padding;
}
}
} }
ul.controls { ul.controls {
......
...@@ -77,10 +77,10 @@ ...@@ -77,10 +77,10 @@
&.sub-nav { &.sub-nav {
text-align: center; text-align: center;
background-color: $background-color; background-color: $dark-background-color;
.container-fluid { .container-fluid {
background-color: $background-color; background-color: $dark-background-color;
margin-bottom: 0; margin-bottom: 0;
} }
...@@ -134,6 +134,11 @@ ...@@ -134,6 +134,11 @@
margin-bottom: 0; margin-bottom: 0;
border-bottom: none; border-bottom: none;
&.wide {
width: 100%;
display: block;
}
li a { li a {
padding: 16px 10px 11px; padding: 16px 10px 11px;
} }
...@@ -164,6 +169,7 @@ ...@@ -164,6 +169,7 @@
> .btn { > .btn {
margin-right: $gl-padding-top; margin-right: $gl-padding-top;
display: inline-block; display: inline-block;
vertical-align: top;
&:last-child { &:last-child {
margin-right: 0; margin-right: 0;
......
...@@ -3,6 +3,12 @@ ...@@ -3,6 +3,12 @@
padding-bottom: 25px; padding-bottom: 25px;
transition: padding $sidebar-transition-duration; transition: padding $sidebar-transition-duration;
&.page-sidebar-pinned {
.sidebar-wrapper {
@include box-shadow(none);
}
}
.sidebar-wrapper { .sidebar-wrapper {
position: fixed; position: fixed;
top: 0; top: 0;
...@@ -11,6 +17,7 @@ ...@@ -11,6 +17,7 @@
height: 100%; height: 100%;
overflow: hidden; overflow: hidden;
transition: width $sidebar-transition-duration; transition: width $sidebar-transition-duration;
@include box-shadow(2px 0 16px 0 #bbb);
} }
} }
...@@ -40,32 +47,16 @@ ...@@ -40,32 +47,16 @@
} }
} }
.sidebar-user {
padding: 15px;
position: absolute;
left: 0;
bottom: 0;
width: $sidebar_width;
overflow: hidden;
font-size: 16px;
line-height: 36px;
transition: width $sidebar-transition-duration, padding $sidebar-transition-duration;
@media (min-width: $sidebar-breakpoint) {
bottom: 50px;
}
}
.nav-sidebar { .nav-sidebar {
position: absolute; position: absolute;
top: 50px; top: 50px;
bottom: 65px; bottom: 0;
width: $sidebar_width; width: $sidebar_width;
overflow-y: auto; overflow-y: auto;
overflow-x: hidden; overflow-x: hidden;
@media (min-width: $sidebar-breakpoint) { @media (min-width: $sidebar-breakpoint) {
bottom: 115px; bottom: 50px;
} }
&.navbar-collapse { &.navbar-collapse {
......
...@@ -12,10 +12,11 @@ $sidebar-breakpoint: 1024px; ...@@ -12,10 +12,11 @@ $sidebar-breakpoint: 1024px;
/* /*
* UI elements * UI elements
*/ */
$border-color: #e5e5e5; $border-color: #e5e5e5;
$focus-border-color: #3aabf0; $focus-border-color: #3aabf0;
$table-border-color: #f0f0f0; $table-border-color: #f0f0f0;
$background-color: #fafafa; $background-color: #fafafa;
$dark-background-color: #f7f7f7;
/* /*
* Text * Text
...@@ -153,9 +154,6 @@ $warning-message-bg: #fbf2d9; ...@@ -153,9 +154,6 @@ $warning-message-bg: #fbf2d9;
$warning-message-color: #9e8e60; $warning-message-color: #9e8e60;
$warning-message-border: #f0e2bb; $warning-message-border: #f0e2bb;
/* header */
$light-grey-header: #faf9f9;
/* tanuki logo colors */ /* tanuki logo colors */
$tanuki-red: #e24329; $tanuki-red: #e24329;
$tanuki-orange: #fc6d26; $tanuki-orange: #fc6d26;
......
...@@ -71,3 +71,36 @@ ...@@ -71,3 +71,36 @@
@extend .broadcast-message; @extend .broadcast-message;
margin-bottom: 20px; margin-bottom: 20px;
} }
// Users List
.users-list {
.user-row {
display: -webkit-flex;
display: -ms-flexbox;
display: flex;
}
.user-details {
flex: 1 1 auto;
}
.user-name {
display: inline-block;
font-weight: bold;
}
.controls {
> .btn, > .dropdown {
margin-left: 5px;
}
}
.dropdown {
.btn-block {
margin-bottom: 0;
line-height: inherit;
}
}
}
...@@ -434,13 +434,3 @@ ...@@ -434,13 +434,3 @@
} }
} }
} }
.discussion {
.diff-content {
.diff-line-num {
&:before {
content: attr(data-linenumber);
}
}
}
}
...@@ -38,6 +38,39 @@ ...@@ -38,6 +38,39 @@
margin-right: 15px; margin-right: 15px;
} }
} }
&.group-admin {
display: -webkit-flex;
display: -ms-flexbox;
display: flex;
.group-avatar, .group-details, .group-controls {
display: -webkit-flex;
display: -ms-flexbox;
display: flex;
}
.group-details {
flex: 1 1 auto;
flex-direction: column;
min-width: 0;
}
.group-controls {
align-items: center;
a {
margin-left: 5px;
}
}
}
}
.ldap-group-links {
.form-actions {
margin-bottom: $gl-padding;
}
} }
.groups-cover-block { .groups-cover-block {
......
...@@ -63,8 +63,8 @@ form.edit-issue { ...@@ -63,8 +63,8 @@ form.edit-issue {
.merge-request, .merge-request,
.issue { .issue {
&.today { &.today {
background: #efe; background: #f8feef;
border-color: #cec; border-color: #e1e8d5;
} }
&.closed { &.closed {
......
...@@ -167,7 +167,8 @@ ...@@ -167,7 +167,8 @@
.commit { .commit {
margin: 0; margin: 0;
padding: 2px 0; padding-top: 2px;
padding-bottom: 2px;
list-style: none; list-style: none;
&:hover { &:hover {
background: none; background: none;
......
...@@ -64,86 +64,49 @@ ...@@ -64,86 +64,49 @@
} }
.project-home-panel { .project-home-panel {
background: $white-light; padding-top: 24px;
text-align: left; padding-bottom: 24px;
padding: 24px 0;
.container-fluid { @media (min-width: $screen-sm-min) {
position: relative; border-bottom: 1px solid $border-color;
@media (min-width: $screen-lg-min) {
.row {
display: flex;
-ms-flex-align: center;
-webkit-align-items: center;
-webkit-box-align: center;
}
}
} }
.cover-controls { .project-avatar {
.project-settings-dropdown { float: none;
margin-left: 10px; margin-left: auto;
display: inline-block; margin-right: auto;
.dropdown-menu { &.identicon {
left: auto; border-radius: 50%;
width: auto;
right: 0;
max-width: 240px;
}
} }
} }
.cover-title { .project-title {
margin-bottom: 0; margin-top: 10px;
} margin-bottom: 10px;
font-size: 24px;
.project-image-container { font-weight: 400;
@include make-sm-column(1); line-height: 1;
max-width: 86px;
min-width: 86px;
padding-right: 0;
@media (max-width: $screen-md-max) {
padding-left: 0;
margin: 0 0 10px;
max-width: none;
min-width: none;
.avatar.s70 { .fa {
margin: auto; margin-left: 2px;
} font-size: 12px;
vertical-align: middle;
} }
} }
.project-info { .project-home-desc {
@include make-sm-column(10); margin-left: auto;
margin-right: auto;
margin-bottom: 15px;
max-width: 480px;
h1 { > p {
font-size: 24px; margin-bottom: 0;
font-weight: normal;
margin: 0;
} }
.project-home-desc {
p {
margin: 0;
}
}
}
.identicon {
float: left;
@include border-radius(50%);
}
.avatar {
float: none;
} }
.notifications-btn { .notifications-btn {
.fa-bell, .fa-bell,
.fa-spinner { .fa-spinner {
margin-right: 6px; margin-right: 6px;
...@@ -153,127 +116,106 @@ ...@@ -153,127 +116,106 @@
margin-left: 6px; margin-left: 6px;
} }
} }
}
.project-repo-buttons { .project-repo-buttons {
font-size: 0; font-size: 0;
.btn { .btn {
@include btn-gray; @include btn-gray;
padding: 3px 10px; padding: 3px 10px;
text-transform: none;
background-color: $background-color;
.fa { .fa {
color: $layout-link-gray; color: $layout-link-gray;
}
.fa-caret-down {
margin-left: 3px;
}
} }
form { .fa-caret-down {
margin-left: 10px; margin-left: 3px;
} }
}
.count-buttons { .project-repo-btn-group,
display: inline-block; .notification-dropdown {
vertical-align: top; margin-left: 10px;
margin-top: 16px; }
}
.project-clone-holder { .count-buttons {
display: inline-block; display: inline-block;
margin-top: 16px; vertical-align: top;
}
input { .project-clone-holder {
height: 29px; display: inline-block;
}
input {
height: 29px;
} }
}
.count-with-arrow { .count-with-arrow {
display: inline-block; display: inline-block;
position: relative; position: relative;
margin-left: 4px; margin-left: 4px;
.arrow { .arrow {
&:before { &:before {
content: ''; content: '';
display: inline-block;
position: absolute;
width: 0;
height: 0;
border-color: transparent;
border-style: solid;
top: 50%;
left: 0;
margin-top: -6px;
border-width: 7px 5px 7px 0;
border-right-color: #dce0e5;
}
&:after {
content: '';
position: absolute;
width: 0;
height: 0;
border-color: transparent;
border-style: solid;
top: 50%;
left: 1px;
margin-top: -9px;
border-width: 10px 7px 10px 0;
border-right-color: #fff;
}
}
.count {
@include btn-gray;
display: inline-block; display: inline-block;
background: white; position: absolute;
border-radius: 2px; width: 0;
border-width: 1px; height: 0;
border-color: transparent;
border-style: solid; border-style: solid;
font-size: 13px; top: 50%;
font-weight: 600; left: 0;
line-height: 13px; margin-top: -6px;
padding: $gl-vert-padding $gl-padding; border-width: 7px 5px 7px 0;
letter-spacing: .4px; border-right-color: #dce0e5;
padding: 7px 14px; pointer-events: none;
text-align: center;
vertical-align: middle;
touch-action: manipulation;
cursor: pointer;
background-image: none;
white-space: nowrap;
margin: 0 10px 0 4px;
a {
color: inherit;
}
&:hover {
background: #fff;
}
} }
}
}
.project-right-buttons { &:after {
position: absolute; content: '';
right: 16px; position: absolute;
bottom: 0; width: 0;
height: 0;
@media (max-width: $screen-md-max) { border-color: transparent;
top: 0; border-style: solid;
top: 50%;
left: 1px;
margin-top: -9px;
border-width: 10px 7px 10px 0;
border-right-color: #fff;
pointer-events: none;
}
} }
} .count {
@include btn-gray;
@media (max-width: $screen-md-max) { display: inline-block;
text-align: center; background: white;
border-radius: 2px;
border-width: 1px;
border-style: solid;
font-size: 13px;
font-weight: 600;
line-height: 13px;
padding: $gl-vert-padding $gl-padding;
letter-spacing: .4px;
padding: 7px 14px;
text-align: center;
vertical-align: middle;
touch-action: manipulation;
background-image: none;
white-space: nowrap;
margin: 0 10px 0 4px;
a {
color: inherit;
}
.project-info, &:hover {
.project-image-container { background: #fff;
width: 100%; }
} }
} }
} }
...@@ -421,36 +363,42 @@ a.deploy-project-label { ...@@ -421,36 +363,42 @@ a.deploy-project-label {
} }
.project-stats { .project-stats {
margin-top: $gl-padding;
margin-bottom: 0;
padding: 0;
background-color: $white-light;
font-size: 0; font-size: 0;
border-bottom: 1px solid $border-color;
ul.nav { .nav {
display: inline-block; padding-top: 12px;
padding-bottom: 12px;
} }
.nav li { .nav > li {
display: inline-block; display: inline-block;
margin: 16px 0;
margin-right: 16px; &:not(:last-child) {
margin-right: $gl-padding;
}
&.project-repo-buttons-right {
margin-top: 10px;
@media (min-width: $screen-md-min) {
float: right;
margin-top: 0;
}
}
} }
.nav > li > a { .nav > li > a {
padding: 0;
background-color: transparent; background-color: transparent;
padding: 5px 10px;
font-size: 15px; font-size: 15px;
line-height: 29px;
color: $notes-light-color; color: $notes-light-color;
}
li { &:hover,
display: inline; &:focus {
} color: darken($notes-light-color, 15%);
}
a {
float: left;
font-size: 17px;
} }
li.missing { li.missing {
...@@ -458,6 +406,8 @@ a.deploy-project-label { ...@@ -458,6 +406,8 @@ a.deploy-project-label {
border-radius: $border-radius-default; border-radius: $border-radius-default;
a { a {
padding-left: 10px;
padding-right: 10px;
color: $notes-light-color; color: $notes-light-color;
display: block; display: block;
} }
...@@ -466,10 +416,6 @@ a.deploy-project-label { ...@@ -466,10 +416,6 @@ a.deploy-project-label {
background-color: $gray-normal; background-color: $gray-normal;
} }
} }
&.row-content-block.second-block {
margin-top: 0;
}
} }
pre.light-well { pre.light-well {
...@@ -529,10 +475,6 @@ pre.light-well { ...@@ -529,10 +475,6 @@ pre.light-well {
a:hover { a:hover {
text-decoration: none; text-decoration: none;
} }
> span {
margin-left: 10px;
}
} }
} }
...@@ -557,8 +499,32 @@ pre.light-well { ...@@ -557,8 +499,32 @@ pre.light-well {
} }
.project-last-commit { .project-last-commit {
@media (min-width: $screen-sm-min) {
margin-top: $gl-padding;
}
&.container-fluid {
padding-top: 12px;
padding-bottom: 12px;
background-color: $background-color;
border: 1px solid $border-color;
border-right-width: 0;
border-left-width: 0;
@media (min-width: $screen-sm-min) {
border-right-width: 1px;
border-left-width: 1px;
}
}
&.container-limited {
@media (min-width: 1281px) {
border-radius: $border-radius-base;
}
}
.ci-status { .ci-status {
margin-right: 16px; margin-right: $gl-padding;
} }
.commit-row-message { .commit-row-message {
...@@ -566,19 +532,12 @@ pre.light-well { ...@@ -566,19 +532,12 @@ pre.light-well {
} }
.commit_short_id { .commit_short_id {
margin: 0 5px; margin-right: 5px;
color: $gl-link-color; color: $gl-link-color;
font-weight: 600; font-weight: 600;
} }
.commit-author-link { .commit-author-link {
margin-left: 7px;
text-decoration: none;
.avatar {
float: none;
margin-right: 4px;
}
.commit-author-name { .commit-author-name {
font-weight: 600; font-weight: 600;
} }
...@@ -601,15 +560,10 @@ pre.light-well { ...@@ -601,15 +560,10 @@ pre.light-well {
} }
.git-clone-holder { .git-clone-holder {
width: 498px; width: 380px;
.btn-clipboard { .btn-clipboard {
border: 1px solid $border-color; border: 1px solid $border-color;
padding: 6px $gl-padding;
}
.project-home-dropdown + & {
margin-right: 45px;
} }
.clone-options { .clone-options {
......
...@@ -208,7 +208,7 @@ ...@@ -208,7 +208,7 @@
margin-top: 5px; margin-top: 5px;
@media (min-width: $screen-sm-min) { @media (min-width: $screen-sm-min) {
width: 160px; width: 180px;
margin-top: 0; margin-top: 0;
} }
} }
......
...@@ -87,6 +87,7 @@ class Admin::ApplicationSettingsController < Admin::ApplicationController ...@@ -87,6 +87,7 @@ class Admin::ApplicationSettingsController < Admin::ApplicationController
:version_check_enabled, :version_check_enabled,
:admin_notification_email, :admin_notification_email,
:user_oauth_applications, :user_oauth_applications,
:user_default_external,
:shared_runners_enabled, :shared_runners_enabled,
:shared_runners_text, :shared_runners_text,
:max_artifacts_size, :max_artifacts_size,
...@@ -110,6 +111,7 @@ class Admin::ApplicationSettingsController < Admin::ApplicationController ...@@ -110,6 +111,7 @@ class Admin::ApplicationSettingsController < Admin::ApplicationController
:send_user_confirmation_email, :send_user_confirmation_email,
:container_registry_token_expire_delay, :container_registry_token_expire_delay,
:repository_storage, :repository_storage,
:enabled_git_access_protocol,
restricted_visibility_levels: [], restricted_visibility_levels: [],
import_sources: [], import_sources: [],
disabled_oauth_sign_in_sources: [] disabled_oauth_sign_in_sources: []
......
...@@ -10,6 +10,7 @@ class Admin::GroupsController < Admin::ApplicationController ...@@ -10,6 +10,7 @@ class Admin::GroupsController < Admin::ApplicationController
def show def show
@members = @group.members.order("access_level DESC").page(params[:members_page]) @members = @group.members.order("access_level DESC").page(params[:members_page])
@requesters = @group.requesters
@projects = @group.projects.page(params[:projects_page]) @projects = @group.projects.page(params[:projects_page])
end end
......
...@@ -22,7 +22,6 @@ class Admin::HooksController < Admin::ApplicationController ...@@ -22,7 +22,6 @@ class Admin::HooksController < Admin::ApplicationController
redirect_to admin_hooks_path redirect_to admin_hooks_path
end end
def test def test
@hook = SystemHook.find(params[:hook_id]) @hook = SystemHook.find(params[:hook_id])
data = { data = {
......
...@@ -5,11 +5,12 @@ class Admin::ProjectsController < Admin::ApplicationController ...@@ -5,11 +5,12 @@ class Admin::ProjectsController < Admin::ApplicationController
def index def index
@projects = Project.all @projects = Project.all
@projects = @projects.in_namespace(params[:namespace_id]) if params[:namespace_id].present? @projects = @projects.in_namespace(params[:namespace_id]) if params[:namespace_id].present?
@projects = @projects.where("projects.visibility_level IN (?)", params[:visibility_levels]) if params[:visibility_levels].present? @projects = @projects.where(visibility_level: params[:visibility_level]) if params[:visibility_level].present?
@projects = @projects.with_push if params[:with_push].present? @projects = @projects.with_push if params[:with_push].present?
@projects = @projects.abandoned if params[:abandoned].present? @projects = @projects.abandoned if params[:abandoned].present?
@projects = @projects.where(last_repository_check_failed: true) if params[:last_repository_check_failed].present? @projects = @projects.where(last_repository_check_failed: true) if params[:last_repository_check_failed].present?
@projects = @projects.non_archived unless params[:with_archived].present? @projects = @projects.non_archived unless params[:archived].present?
@projects = @projects.personal(current_user) if params[:personal].present?
@projects = @projects.search(params[:name]) if params[:name].present? @projects = @projects.search(params[:name]) if params[:name].present?
@projects = @projects.sort(@sort = params[:sort]) @projects = @projects.sort(@sort = params[:sort])
@projects = @projects.includes(:namespace).order("namespaces.path, projects.name ASC").page(params[:page]) @projects = @projects.includes(:namespace).order("namespaces.path, projects.name ASC").page(params[:page])
...@@ -20,7 +21,8 @@ class Admin::ProjectsController < Admin::ApplicationController ...@@ -20,7 +21,8 @@ class Admin::ProjectsController < Admin::ApplicationController
@group_members = @group.members.order("access_level DESC").page(params[:group_members_page]) @group_members = @group.members.order("access_level DESC").page(params[:group_members_page])
end end
@project_members = @project.project_members.page(params[:project_members_page]) @project_members = @project.members.page(params[:project_members_page])
@requesters = @project.requesters
end end
def transfer def transfer
......
...@@ -10,7 +10,7 @@ module MembershipActions ...@@ -10,7 +10,7 @@ module MembershipActions
end end
def approve_access_request def approve_access_request
@member = membershipable.members.request.find(params[:id]) @member = membershipable.requesters.find(params[:id])
return render_403 unless can?(current_user, action_member_permission(:update, @member), @member) return render_403 unless can?(current_user, action_member_permission(:update, @member), @member)
...@@ -20,7 +20,8 @@ module MembershipActions ...@@ -20,7 +20,8 @@ module MembershipActions
end end
def leave def leave
@member = membershipable.members.find_by(user_id: current_user) @member = membershipable.members.find_by(user_id: current_user) ||
membershipable.requesters.find_by(user_id: current_user)
Members::DestroyService.new(@member, current_user).execute Members::DestroyService.new(@member, current_user).execute
source_type = @member.real_source_type.humanize(capitalize: false) source_type = @member.real_source_type.humanize(capitalize: false)
......
class ConfirmationsController < Devise::ConfirmationsController class ConfirmationsController < Devise::ConfirmationsController
def almost_there def almost_there
flash[:notice] = nil flash[:notice] = nil
render layout: "devise_empty" render layout: "devise_empty"
......
...@@ -7,7 +7,7 @@ class Groups::GroupMembersController < Groups::ApplicationController ...@@ -7,7 +7,7 @@ class Groups::GroupMembersController < Groups::ApplicationController
def index def index
@project = @group.projects.find(params[:project_id]) if params[:project_id] @project = @group.projects.find(params[:project_id]) if params[:project_id]
@members = @group.group_members @members = @group.group_members
@members = @members.non_pending unless can?(current_user, :admin_group, @group) @members = @members.non_invite unless can?(current_user, :admin_group, @group)
if params[:search].present? if params[:search].present?
users = @group.users.search(params[:search]).to_a users = @group.users.search(params[:search]).to_a
...@@ -15,6 +15,7 @@ class Groups::GroupMembersController < Groups::ApplicationController ...@@ -15,6 +15,7 @@ class Groups::GroupMembersController < Groups::ApplicationController
end end
@members = @members.order('access_level DESC').page(params[:page]).per(50) @members = @members.order('access_level DESC').page(params[:page]).per(50)
@requesters = @group.requesters if can?(current_user, :admin_group, @group)
@group_member = @group.group_members.new @group_member = @group.group_members.new
end end
...@@ -34,7 +35,8 @@ class Groups::GroupMembersController < Groups::ApplicationController ...@@ -34,7 +35,8 @@ class Groups::GroupMembersController < Groups::ApplicationController
end end
def destroy def destroy
@group_member = @group.group_members.find(params[:id]) @group_member = @group.members.find_by(id: params[:id]) ||
@group.requesters.find_by(id: params[:id])
Members::DestroyService.new(@group_member, current_user).execute Members::DestroyService.new(@group_member, current_user).execute
......
class Import::BaseController < ApplicationController class Import::BaseController < ApplicationController
private private
def get_or_create_namespace def get_or_create_namespace
......
...@@ -5,7 +5,6 @@ class Import::FogbugzController < Import::BaseController ...@@ -5,7 +5,6 @@ class Import::FogbugzController < Import::BaseController
rescue_from Fogbugz::AuthenticationException, with: :fogbugz_unauthorized rescue_from Fogbugz::AuthenticationException, with: :fogbugz_unauthorized
def new def new
end end
def callback def callback
...@@ -22,7 +21,6 @@ class Import::FogbugzController < Import::BaseController ...@@ -22,7 +21,6 @@ class Import::FogbugzController < Import::BaseController
end end
def new_user_map def new_user_map
end end
def create_user_map def create_user_map
......
...@@ -27,10 +27,7 @@ class Import::GitlabProjectsController < Import::BaseController ...@@ -27,10 +27,7 @@ class Import::GitlabProjectsController < Import::BaseController
notice: "Project '#{@project.name}' is being imported." notice: "Project '#{@project.name}' is being imported."
) )
else else
redirect_to( redirect_back_or_default(options: { alert: "Project could not be imported: #{@project.errors.full_messages.join(', ')}" })
new_import_gitlab_project_path,
alert: "Project could not be imported: #{@project.errors.full_messages.join(', ')}"
)
end end
end end
......
...@@ -44,5 +44,4 @@ class Import::GitoriousController < Import::BaseController ...@@ -44,5 +44,4 @@ class Import::GitoriousController < Import::BaseController
def verify_gitorious_import_enabled def verify_gitorious_import_enabled
render_404 unless gitorious_import_enabled? render_404 unless gitorious_import_enabled?
end end
end end
...@@ -3,7 +3,6 @@ class Import::GoogleCodeController < Import::BaseController ...@@ -3,7 +3,6 @@ class Import::GoogleCodeController < Import::BaseController
before_action :user_map, only: [:new_user_map, :create_user_map] before_action :user_map, only: [:new_user_map, :create_user_map]
def new def new
end end
def callback def callback
...@@ -34,7 +33,6 @@ class Import::GoogleCodeController < Import::BaseController ...@@ -34,7 +33,6 @@ class Import::GoogleCodeController < Import::BaseController
end end
def new_user_map def new_user_map
end end
def create_user_map def create_user_map
......
...@@ -5,7 +5,6 @@ class InvitesController < ApplicationController ...@@ -5,7 +5,6 @@ class InvitesController < ApplicationController
respond_to :html respond_to :html
def show def show
end end
def accept def accept
......
...@@ -57,7 +57,7 @@ class Projects::BlobController < Projects::ApplicationController ...@@ -57,7 +57,7 @@ class Projects::BlobController < Projects::ApplicationController
diffy = Diffy::Diff.new(@blob.data, @content, diff: '-U 3', include_diff_info: true) diffy = Diffy::Diff.new(@blob.data, @content, diff: '-U 3', include_diff_info: true)
diff_lines = diffy.diff.scan(/.*\n/)[2..-1] diff_lines = diffy.diff.scan(/.*\n/)[2..-1]
diff_lines = Gitlab::Diff::Parser.new.parse(diff_lines) diff_lines = Gitlab::Diff::Parser.new.parse(diff_lines)
@diff_lines = Gitlab::Diff::Highlight.new(diff_lines).highlight @diff_lines = Gitlab::Diff::Highlight.new(diff_lines, repository: @repository).highlight
render layout: false render layout: false
end end
......
...@@ -121,7 +121,6 @@ class Projects::CommitController < Projects::ApplicationController ...@@ -121,7 +121,6 @@ class Projects::CommitController < Projects::ApplicationController
opts[:ignore_whitespace_change] = true if params[:format] == 'diff' opts[:ignore_whitespace_change] = true if params[:format] == 'diff'
@diffs = commit.diffs(opts) @diffs = commit.diffs(opts)
@diff_refs = [commit.parent || commit, commit]
@notes_count = commit.notes.count @notes_count = commit.notes.count
@statuses = CommitStatus.where(pipeline: pipelines) @statuses = CommitStatus.where(pipeline: pipelines)
......
...@@ -14,14 +14,22 @@ class Projects::CompareController < Projects::ApplicationController ...@@ -14,14 +14,22 @@ class Projects::CompareController < Projects::ApplicationController
def show def show
compare = CompareService.new. compare = CompareService.new.
execute(@project, @head_ref, @project, @base_ref, diff_options) execute(@project, @head_ref, @project, @start_ref, diff_options)
if compare if compare
@commits = Commit.decorate(compare.commits, @project) @commits = Commit.decorate(compare.commits, @project)
@start_commit = @project.commit(@start_ref)
@commit = @project.commit(@head_ref) @commit = @project.commit(@head_ref)
@base_commit = @project.merge_base_commit(@base_ref, @head_ref) @base_commit = @project.merge_base_commit(@start_ref, @head_ref)
@diffs = compare.diffs(diff_options) @diffs = compare.diffs(diff_options)
@diff_refs = [@base_commit, @commit] @diff_refs = Gitlab::Diff::DiffRefs.new(
base_sha: @base_commit.try(:sha),
start_sha: @start_commit.try(:sha),
head_sha: @commit.try(:sha)
)
@diff_notes_disabled = true @diff_notes_disabled = true
@grouped_diff_notes = {} @grouped_diff_notes = {}
end end
...@@ -35,12 +43,12 @@ class Projects::CompareController < Projects::ApplicationController ...@@ -35,12 +43,12 @@ class Projects::CompareController < Projects::ApplicationController
private private
def assign_ref_vars def assign_ref_vars
@base_ref = Addressable::URI.unescape(params[:from]) @start_ref = Addressable::URI.unescape(params[:from])
@ref = @head_ref = Addressable::URI.unescape(params[:to]) @ref = @head_ref = Addressable::URI.unescape(params[:to])
end end
def merge_request def merge_request
@merge_request ||= @project.merge_requests.opened. @merge_request ||= @project.merge_requests.opened.
find_by(source_project: @project, source_branch: @head_ref, target_branch: @base_ref) find_by(source_project: @project, source_branch: @head_ref, target_branch: @start_ref)
end end
end end
# This file should be identical in GitLab Community Edition and Enterprise Edition
class Projects::GitHttpController < Projects::ApplicationController class Projects::GitHttpController < Projects::ApplicationController
include ActionController::HttpAuthentication::Basic
include KerberosSpnegoHelper
attr_reader :user attr_reader :user
# Git clients will not know what authenticity token to send along # Git clients will not know what authenticity token to send along
...@@ -14,6 +19,8 @@ class Projects::GitHttpController < Projects::ApplicationController ...@@ -14,6 +19,8 @@ class Projects::GitHttpController < Projects::ApplicationController
render_ok render_ok
elsif receive_pack? && receive_pack_allowed? elsif receive_pack? && receive_pack_allowed?
render_ok render_ok
elsif http_blocked?
render_not_allowed
else else
render_not_found render_not_found
end end
...@@ -40,9 +47,12 @@ class Projects::GitHttpController < Projects::ApplicationController ...@@ -40,9 +47,12 @@ class Projects::GitHttpController < Projects::ApplicationController
private private
def authenticate_user def authenticate_user
return if project && project.public? && upload_pack? if project && project.public? && upload_pack?
return # Allow access
end
authenticate_or_request_with_http_basic do |login, password| if allow_basic_auth? && basic_auth_provided?
login, password = user_name_and_password(request)
auth_result = Gitlab::Auth.find_for_git_client(login, password, project: project, ip: request.ip) auth_result = Gitlab::Auth.find_for_git_client(login, password, project: project, ip: request.ip)
if auth_result.type == :ci && upload_pack? if auth_result.type == :ci && upload_pack?
...@@ -53,8 +63,31 @@ class Projects::GitHttpController < Projects::ApplicationController ...@@ -53,8 +63,31 @@ class Projects::GitHttpController < Projects::ApplicationController
@user = auth_result.user @user = auth_result.user
end end
ci? || user if ci? || user
return # Allow access
end
elsif allow_kerberos_spnego_auth? && spnego_provided?
@user = find_kerberos_user
if user
send_final_spnego_response
return # Allow access
end
end end
send_challenges
render plain: "HTTP Basic: Access denied\n", status: 401
end
def basic_auth_provided?
has_basic_credentials?(request)
end
def send_challenges
challenges = []
challenges << 'Basic realm="GitLab"' if allow_basic_auth?
challenges << spnego_challenge if allow_kerberos_spnego_auth?
headers['Www-Authenticate'] = challenges.join("\n") if challenges.any?
end end
def ensure_project_found! def ensure_project_found!
...@@ -120,7 +153,11 @@ class Projects::GitHttpController < Projects::ApplicationController ...@@ -120,7 +153,11 @@ class Projects::GitHttpController < Projects::ApplicationController
end end
def render_not_found def render_not_found
render text: 'Not Found', status: :not_found render plain: 'Not Found', status: :not_found
end
def render_not_allowed
render plain: download_access.message, status: :forbidden
end end
def ci? def ci?
...@@ -131,12 +168,28 @@ class Projects::GitHttpController < Projects::ApplicationController ...@@ -131,12 +168,28 @@ class Projects::GitHttpController < Projects::ApplicationController
return false unless Gitlab.config.gitlab_shell.upload_pack return false unless Gitlab.config.gitlab_shell.upload_pack
if user if user
Gitlab::GitAccess.new(user, project).download_access_check.allowed? download_access.allowed?
else else
ci? || project.public? ci? || project.public?
end end
end end
def access
return @access if defined?(@access)
@access = Gitlab::GitAccess.new(user, project, 'http')
end
def download_access
return @download_access if defined?(@download_access)
@download_access = access.check('git-upload-pack')
end
def http_blocked?
!access.protocol_allowed?
end
def receive_pack_allowed? def receive_pack_allowed?
return false unless Gitlab.config.gitlab_shell.receive_pack return false unless Gitlab.config.gitlab_shell.receive_pack
......
...@@ -76,7 +76,6 @@ class Projects::IssuesController < Projects::ApplicationController ...@@ -76,7 +76,6 @@ class Projects::IssuesController < Projects::ApplicationController
render json: @issue.to_json(include: [:milestone, :labels]) render json: @issue.to_json(include: [:milestone, :labels])
end end
end end
end end
def create def create
......
...@@ -9,7 +9,6 @@ class Projects::MergeRequestsController < Projects::ApplicationController ...@@ -9,7 +9,6 @@ class Projects::MergeRequestsController < Projects::ApplicationController
:edit, :update, :show, :diffs, :commits, :builds, :merge, :merge_check, :edit, :update, :show, :diffs, :commits, :builds, :merge, :merge_check,
:ci_status, :toggle_subscription, :cancel_merge_when_build_succeeds, :remove_wip :ci_status, :toggle_subscription, :cancel_merge_when_build_succeeds, :remove_wip
] ]
before_action :closes_issues, only: [:edit, :update, :show, :diffs, :commits, :builds]
before_action :validates_merge_request, only: [:show, :diffs, :commits, :builds] before_action :validates_merge_request, only: [:show, :diffs, :commits, :builds]
before_action :define_show_vars, only: [:show, :diffs, :commits, :builds] before_action :define_show_vars, only: [:show, :diffs, :commits, :builds]
before_action :define_widget_vars, only: [:merge, :cancel_merge_when_build_succeeds, :merge_check] before_action :define_widget_vars, only: [:merge, :cancel_merge_when_build_succeeds, :merge_check]
...@@ -53,19 +52,19 @@ class Projects::MergeRequestsController < Projects::ApplicationController ...@@ -53,19 +52,19 @@ class Projects::MergeRequestsController < Projects::ApplicationController
end end
def show def show
@note_counts = Note.where(commit_id: @merge_request.commits.map(&:id)).
group(:commit_id).count
respond_to do |format| respond_to do |format|
format.html format.html
format.json { render json: @merge_request }
format.json do
render json: @merge_request
end
format.patch do format.patch do
headers.store(*Gitlab::Workhorse.send_git_patch(@project.repository, return render_404 unless @merge_request.diff_refs
@merge_request.diff_base_commit.id,
@merge_request.last_commit.id)) send_git_patch @project.repository, @merge_request.diff_refs
headers['Content-Disposition'] = 'inline'
head :ok
end end
format.diff do format.diff do
return render_404 unless @merge_request.diff_refs return render_404 unless @merge_request.diff_refs
...@@ -77,18 +76,17 @@ class Projects::MergeRequestsController < Projects::ApplicationController ...@@ -77,18 +76,17 @@ class Projects::MergeRequestsController < Projects::ApplicationController
def diffs def diffs
apply_diff_view_cookie! apply_diff_view_cookie!
@commit = @merge_request.last_commit @merge_request_diff = @merge_request.merge_request_diff
@base_commit = @merge_request.diff_base_commit
# MRs created before 8.4 don't have a diff_base_commit, @commit = @merge_request.diff_head_commit
# but we need it for the "View file @ ..." link by deleted files @base_commit = @merge_request.diff_base_commit || @merge_request.likely_diff_base_commit
@base_commit ||= @merge_request.first_commit.parent || @merge_request.first_commit
@comments_target = { @comments_target = {
noteable_type: 'MergeRequest', noteable_type: 'MergeRequest',
noteable_id: @merge_request.id noteable_id: @merge_request.id
} }
@use_legacy_diff_notes = !@merge_request.support_new_diff_notes?
@grouped_diff_notes = @merge_request.notes.grouped_diff_notes @grouped_diff_notes = @merge_request.notes.grouped_diff_notes
Banzai::NoteRenderer.render( Banzai::NoteRenderer.render(
...@@ -109,7 +107,15 @@ class Projects::MergeRequestsController < Projects::ApplicationController ...@@ -109,7 +107,15 @@ class Projects::MergeRequestsController < Projects::ApplicationController
def commits def commits
respond_to do |format| respond_to do |format|
format.html { render 'show' } format.html { render 'show' }
format.json { render json: { html: view_to_html_string('projects/merge_requests/show/_commits') } } format.json do
# Get commits from repository
# or from cache if already merged
@commits = @merge_request.commits
@note_counts = Note.where(commit_id: @commits.map(&:id)).
group(:commit_id).count
render json: { html: view_to_html_string('projects/merge_requests/show/_commits') }
end
end end
end end
...@@ -134,7 +140,7 @@ class Projects::MergeRequestsController < Projects::ApplicationController ...@@ -134,7 +140,7 @@ class Projects::MergeRequestsController < Projects::ApplicationController
@target_project = merge_request.target_project @target_project = merge_request.target_project
@source_project = merge_request.source_project @source_project = merge_request.source_project
@commits = @merge_request.compare_commits.reverse @commits = @merge_request.compare_commits.reverse
@commit = @merge_request.last_commit @commit = @merge_request.diff_head_commit
@base_commit = @merge_request.diff_base_commit @base_commit = @merge_request.diff_base_commit
@diffs = @merge_request.compare.diffs(diff_options) if @merge_request.compare @diffs = @merge_request.compare.diffs(diff_options) if @merge_request.compare
@diff_notes_disabled = true @diff_notes_disabled = true
...@@ -212,7 +218,7 @@ class Projects::MergeRequestsController < Projects::ApplicationController ...@@ -212,7 +218,7 @@ class Projects::MergeRequestsController < Projects::ApplicationController
return return
end end
if params[:sha] != @merge_request.source_sha if params[:sha] != @merge_request.diff_head_sha
@status = :sha_mismatch @status = :sha_mismatch
return return
end end
...@@ -274,16 +280,16 @@ class Projects::MergeRequestsController < Projects::ApplicationController ...@@ -274,16 +280,16 @@ class Projects::MergeRequestsController < Projects::ApplicationController
status ||= "preparing" status ||= "preparing"
else else
ci_service = @merge_request.source_project.ci_service ci_service = @merge_request.source_project.ci_service
status = ci_service.commit_status(merge_request.last_commit.sha, merge_request.source_branch) if ci_service status = ci_service.commit_status(merge_request.diff_head_sha, merge_request.source_branch) if ci_service
if ci_service.respond_to?(:commit_coverage) if ci_service.respond_to?(:commit_coverage)
coverage = ci_service.commit_coverage(merge_request.last_commit.sha, merge_request.source_branch) coverage = ci_service.commit_coverage(merge_request.diff_head_sha, merge_request.source_branch)
end end
end end
response = { response = {
title: merge_request.title, title: merge_request.title,
sha: merge_request.last_commit_short_sha, sha: merge_request.diff_head_commit.short_id,
status: status, status: status,
coverage: coverage coverage: coverage
} }
...@@ -308,10 +314,6 @@ class Projects::MergeRequestsController < Projects::ApplicationController ...@@ -308,10 +314,6 @@ class Projects::MergeRequestsController < Projects::ApplicationController
alias_method :issuable, :merge_request alias_method :issuable, :merge_request
alias_method :awardable, :merge_request alias_method :awardable, :merge_request
def closes_issues
@closes_issues ||= @merge_request.closes_issues
end
def authorize_update_merge_request! def authorize_update_merge_request!
return render_404 unless can?(current_user, :update_merge_request, @merge_request) return render_404 unless can?(current_user, :update_merge_request, @merge_request)
end end
...@@ -340,14 +342,33 @@ class Projects::MergeRequestsController < Projects::ApplicationController ...@@ -340,14 +342,33 @@ class Projects::MergeRequestsController < Projects::ApplicationController
end end
def define_show_vars def define_show_vars
@noteable = @merge_request
@commits_count = @merge_request.commits.count
@pipeline = @merge_request.pipeline
@statuses = @pipeline.statuses if @pipeline
if @merge_request.locked_long_ago?
@merge_request.unlock_mr
@merge_request.close
end
if request.format == :html || action_name == 'show'
define_show_html_vars
end
end
# Discussion tab data is only required on html requests
def define_show_html_vars
# Build a note object for comment form # Build a note object for comment form
@note = @project.notes.new(noteable: @merge_request) @note = @project.notes.new(noteable: @noteable)
@discussions = @merge_request.mr_and_commit_notes. @discussions = @noteable.mr_and_commit_notes.
inc_author_project_award_emoji. inc_author_project_award_emoji.
fresh. fresh.
discussions discussions
# This is not executed lazily
@notes = Banzai::NoteRenderer.render( @notes = Banzai::NoteRenderer.render(
@discussions.flatten, @discussions.flatten,
@project, @project,
...@@ -356,28 +377,11 @@ class Projects::MergeRequestsController < Projects::ApplicationController ...@@ -356,28 +377,11 @@ class Projects::MergeRequestsController < Projects::ApplicationController
@project_wiki, @project_wiki,
@ref @ref
) )
@noteable = @merge_request
# Get commits from repository
# or from cache if already merged
@commits = @merge_request.commits
@merge_request_diff = @merge_request.merge_request_diff
@pipeline = @merge_request.pipeline
@statuses = @pipeline.statuses if @pipeline
if @merge_request.locked_long_ago?
@merge_request.unlock_mr
@merge_request.close
end
end end
def define_widget_vars def define_widget_vars
@pipeline = @merge_request.pipeline @pipeline = @merge_request.pipeline
@pipelines = [@pipeline].compact @pipelines = [@pipeline].compact
closes_issues
end end
def invalid_mr def invalid_mr
......
...@@ -7,7 +7,6 @@ class Projects::NetworkController < Projects::ApplicationController ...@@ -7,7 +7,6 @@ class Projects::NetworkController < Projects::ApplicationController
before_action :authorize_download_code! before_action :authorize_download_code!
def show def show
@url = namespace_project_network_path(@project.namespace, @project, @ref, @options.merge(format: :json)) @url = namespace_project_network_path(@project.namespace, @project, @ref, @options.merge(format: :json))
@commit_url = namespace_project_commit_path(@project.namespace, @project, 'ae45ca32').gsub("ae45ca32", "%s") @commit_url = namespace_project_commit_path(@project.namespace, @project, 'ae45ca32').gsub("ae45ca32", "%s")
......
...@@ -128,7 +128,7 @@ class Projects::NotesController < Projects::ApplicationController ...@@ -128,7 +128,7 @@ class Projects::NotesController < Projects::ApplicationController
elsif note.valid? elsif note.valid?
Banzai::NoteRenderer.render([note], @project, current_user) Banzai::NoteRenderer.render([note], @project, current_user)
{ attrs = {
valid: true, valid: true,
id: note.id, id: note.id,
discussion_id: note.discussion_id, discussion_id: note.discussion_id,
...@@ -138,6 +138,23 @@ class Projects::NotesController < Projects::ApplicationController ...@@ -138,6 +138,23 @@ class Projects::NotesController < Projects::ApplicationController
discussion_html: note_to_discussion_html(note), discussion_html: note_to_discussion_html(note),
discussion_with_diff_html: note_to_discussion_with_diff_html(note) discussion_with_diff_html: note_to_discussion_with_diff_html(note)
} }
# The discussion_id is used to add the comment to the correct discussion
# element on the merge request page. Among other things, the discussion_id
# contains the sha of head commit of the merge request.
# When new commits are pushed into the merge request after the initial
# load of the merge request page, the discussion elements will still have
# the old discussion_ids, with the old head commit sha. The new comment,
# however, will have the new discussion_id with the new commit sha.
# To ensure that these new comments will still end up in the correct
# discussion element, we also send the original discussion_id, with the
# old commit sha, along, and fall back on this value when no discussion
# element with the new discussion_id could be found.
if note.new_diff_note? && note.position != note.original_position
attrs[:original_discussion_id] = note.original_discussion_id
end
attrs
else else
{ {
valid: false, valid: false,
...@@ -154,7 +171,7 @@ class Projects::NotesController < Projects::ApplicationController ...@@ -154,7 +171,7 @@ class Projects::NotesController < Projects::ApplicationController
def note_params def note_params
params.require(:note).permit( params.require(:note).permit(
:note, :noteable, :noteable_id, :noteable_type, :project_id, :note, :noteable, :noteable_id, :noteable_type, :project_id,
:attachment, :line_code, :commit_id, :type :attachment, :line_code, :commit_id, :type, :position
) )
end end
......
...@@ -6,7 +6,7 @@ class Projects::ProjectMembersController < Projects::ApplicationController ...@@ -6,7 +6,7 @@ class Projects::ProjectMembersController < Projects::ApplicationController
def index def index
@project_members = @project.project_members @project_members = @project.project_members
@project_members = @project_members.non_pending unless can?(current_user, :admin_project, @project) @project_members = @project_members.non_invite unless can?(current_user, :admin_project, @project)
if params[:search].present? if params[:search].present?
users = @project.users.search(params[:search]).to_a users = @project.users.search(params[:search]).to_a
...@@ -19,7 +19,7 @@ class Projects::ProjectMembersController < Projects::ApplicationController ...@@ -19,7 +19,7 @@ class Projects::ProjectMembersController < Projects::ApplicationController
if @group if @group
@group_members = @group.group_members @group_members = @group.group_members
@group_members = @group_members.non_pending unless can?(current_user, :admin_group, @group) @group_members = @group_members.non_invite unless can?(current_user, :admin_group, @group)
if params[:search].present? if params[:search].present?
users = @group.users.search(params[:search]).to_a users = @group.users.search(params[:search]).to_a
...@@ -29,6 +29,8 @@ class Projects::ProjectMembersController < Projects::ApplicationController ...@@ -29,6 +29,8 @@ class Projects::ProjectMembersController < Projects::ApplicationController
@group_members = @group_members.order('access_level DESC') @group_members = @group_members.order('access_level DESC')
end end
@requesters = @project.requesters if can?(current_user, :admin_project, @project)
@project_member = @project.project_members.new @project_member = @project.project_members.new
@project_group_links = @project.project_group_links @project_group_links = @project.project_group_links
end end
...@@ -48,7 +50,8 @@ class Projects::ProjectMembersController < Projects::ApplicationController ...@@ -48,7 +50,8 @@ class Projects::ProjectMembersController < Projects::ApplicationController
end end
def destroy def destroy
@project_member = @project.project_members.find(params[:id]) @project_member = @project.members.find_by(id: params[:id]) ||
@project.requesters.find_by(id: params[:id])
Members::DestroyService.new(@project_member, current_user).execute Members::DestroyService.new(@project_member, current_user).execute
......
...@@ -2,12 +2,14 @@ class Projects::ProtectedBranchesController < Projects::ApplicationController ...@@ -2,12 +2,14 @@ class Projects::ProtectedBranchesController < Projects::ApplicationController
# Authorize # Authorize
before_action :require_non_empty_project before_action :require_non_empty_project
before_action :authorize_admin_project! before_action :authorize_admin_project!
before_action :load_protected_branch, only: [:show, :update, :destroy]
layout "project_settings" layout "project_settings"
def index def index
@branches = @project.protected_branches.to_a @protected_branches = @project.protected_branches.order(:name).page(params[:page])
@protected_branch = @project.protected_branches.new @protected_branch = @project.protected_branches.new
gon.push({ open_branches: @project.open_branches.map { |br| { text: br.name, id: br.name, title: br.name } } })
end end
def create def create
...@@ -16,26 +18,24 @@ class Projects::ProtectedBranchesController < Projects::ApplicationController ...@@ -16,26 +18,24 @@ class Projects::ProtectedBranchesController < Projects::ApplicationController
@project) @project)
end end
def update def show
protected_branch = @project.protected_branches.find(params[:id]) @matching_branches = @protected_branch.matching(@project.repository.branches)
end
if protected_branch &&
protected_branch.update_attributes(
developers_can_push: params[:developers_can_push]
)
def update
if @protected_branch && @protected_branch.update_attributes(protected_branch_params)
respond_to do |format| respond_to do |format|
format.json { render json: protected_branch, status: :ok } format.json { render json: @protected_branch, status: :ok }
end end
else else
respond_to do |format| respond_to do |format|
format.json { render json: protected_branch.errors, status: :unprocessable_entity } format.json { render json: @protected_branch.errors, status: :unprocessable_entity }
end end
end end
end end
def destroy def destroy
@project.protected_branches.find(params[:id]).destroy @protected_branch.destroy
respond_to do |format| respond_to do |format|
format.html { redirect_to namespace_project_protected_branches_path } format.html { redirect_to namespace_project_protected_branches_path }
...@@ -45,6 +45,10 @@ class Projects::ProtectedBranchesController < Projects::ApplicationController ...@@ -45,6 +45,10 @@ class Projects::ProtectedBranchesController < Projects::ApplicationController
private private
def load_protected_branch
@protected_branch = @project.protected_branches.find(params[:id])
end
def protected_branch_params def protected_branch_params
params.require(:protected_branch).permit(:name, :developers_can_push) params.require(:protected_branch).permit(:name, :developers_can_push)
end end
......
...@@ -54,7 +54,7 @@ class Projects::SnippetsController < Projects::ApplicationController ...@@ -54,7 +54,7 @@ class Projects::SnippetsController < Projects::ApplicationController
def show def show
@note = @project.notes.new(noteable: @snippet) @note = @project.notes.new(noteable: @snippet)
@notes = @snippet.notes.fresh @notes = Banzai::NoteRenderer.render(@snippet.notes.fresh, @project, current_user)
@noteable = @snippet @noteable = @snippet
end end
......
...@@ -124,5 +124,4 @@ class Projects::WikisController < Projects::ApplicationController ...@@ -124,5 +124,4 @@ class Projects::WikisController < Projects::ApplicationController
def wiki_params def wiki_params
params[:wiki].slice(:title, :content, :format, :message) params[:wiki].slice(:title, :content, :format, :message)
end end
end end
...@@ -53,11 +53,11 @@ class ProjectsController < Projects::ApplicationController ...@@ -53,11 +53,11 @@ class ProjectsController < Projects::ApplicationController
notice: "Project '#{@project.name}' was successfully updated." notice: "Project '#{@project.name}' was successfully updated."
) )
end end
format.js
else else
format.html { render 'edit' } format.html { render 'edit' }
format.js
end end
format.js
end end
end end
......
...@@ -25,6 +25,7 @@ class TodosFinder ...@@ -25,6 +25,7 @@ class TodosFinder
def execute def execute
items = current_user.todos items = current_user.todos
items = by_action_id(items) items = by_action_id(items)
items = by_action(items)
items = by_author(items) items = by_author(items)
items = by_project(items) items = by_project(items)
items = by_state(items) items = by_state(items)
...@@ -43,6 +44,18 @@ class TodosFinder ...@@ -43,6 +44,18 @@ class TodosFinder
params[:action_id] params[:action_id]
end end
def to_action_id
Todo::ACTION_NAMES.key(action.to_sym)
end
def action?
action.present? && to_action_id
end
def action
params[:action]
end
def author? def author?
params[:author_id].present? params[:author_id].present?
end end
...@@ -96,6 +109,14 @@ class TodosFinder ...@@ -96,6 +109,14 @@ class TodosFinder
params[:type] params[:type]
end end
def by_action(items)
if action?
items = items.where(action: to_action_id)
end
items
end
def by_action_id(items) def by_action_id(items)
if action_id? if action_id?
items = items.where(action: action_id) items = items.where(action: action_id)
......
...@@ -31,7 +31,7 @@ module AppearancesHelper ...@@ -31,7 +31,7 @@ module AppearancesHelper
end end
end end
def navbar_icon(icon_name) def navbar_icon(icon_name, size: 16)
render "shared/icons/#{icon_name}.svg" render "shared/icons/#{icon_name}.svg", size: size
end end
end end
...@@ -306,4 +306,15 @@ module ApplicationHelper ...@@ -306,4 +306,15 @@ module ApplicationHelper
def truncate_first_line(message, length = 50) def truncate_first_line(message, length = 50)
truncate(message.each_line.first.chomp, length: length) if message truncate(message.each_line.first.chomp, length: length) if message
end end
# While similarly named to Rails's `link_to_if`, this method behaves quite differently.
# If `condition` is truthy, a link will be returned with the result of the block
# as its body. If `condition` is falsy, only the result of the block will be returned.
def conditional_link_to(condition, options, html_options = {}, &block)
if condition
link_to options, html_options, &block
else
capture(&block)
end
end
end end
...@@ -31,6 +31,28 @@ module ApplicationSettingsHelper ...@@ -31,6 +31,28 @@ module ApplicationSettingsHelper
current_application_settings.akismet_enabled? current_application_settings.akismet_enabled?
end end
def allowed_protocols_present?
current_application_settings.enabled_git_access_protocol.present?
end
def enabled_protocol
case current_application_settings.enabled_git_access_protocol
when 'http'
gitlab_config.protocol
when 'ssh'
'ssh'
end
end
def enabled_project_button(project, protocol)
case protocol
when 'ssh'
ssh_clone_button(project, 'bottom', append_link: false)
else
http_clone_button(project, 'bottom', append_link: false)
end
end
# Return a group of checkboxes that use Bootstrap's button plugin for a # Return a group of checkboxes that use Bootstrap's button plugin for a
# toggle button effect. # toggle button effect.
def restricted_level_checkboxes(help_block_id) def restricted_level_checkboxes(help_block_id)
......
...@@ -12,7 +12,7 @@ module BranchesHelper ...@@ -12,7 +12,7 @@ module BranchesHelper
def can_push_branch?(project, branch_name) def can_push_branch?(project, branch_name)
return false unless project.repository.branch_exists?(branch_name) return false unless project.repository.branch_exists?(branch_name)
::Gitlab::GitAccess.new(current_user, project).can_push_to_branch?(branch_name) ::Gitlab::GitAccess.new(current_user, project, 'web').can_push_to_branch?(branch_name)
end end
def project_branches def project_branches
......
...@@ -40,33 +40,33 @@ module ButtonHelper ...@@ -40,33 +40,33 @@ module ButtonHelper
type: :button type: :button
end end
def http_clone_button(project) def http_clone_button(project, placement = 'right', append_link: true)
klass = 'http-selector' klass = 'http-selector'
klass << ' has-tooltip' if current_user.try(:require_password?) klass << ' has-tooltip' if current_user.try(:require_password?)
protocol = gitlab_config.protocol.upcase protocol = gitlab_config.protocol.upcase
content_tag :a, protocol, content_tag (append_link ? :a : :span), protocol,
class: klass, class: klass,
href: project.http_url_to_repo, href: (project.http_url_to_repo if append_link),
data: { data: {
html: true, html: true,
placement: 'right', placement: placement,
container: 'body', container: 'body',
title: "Set a password on your account<br>to pull or push via #{protocol}" title: "Set a password on your account<br>to pull or push via #{protocol}"
} }
end end
def ssh_clone_button(project) def ssh_clone_button(project, placement = 'right', append_link: true)
klass = 'ssh-selector' klass = 'ssh-selector'
klass << ' has-tooltip' if current_user.try(:require_ssh_key?) klass << ' has-tooltip' if current_user.try(:require_ssh_key?)
content_tag :a, 'SSH', content_tag (append_link ? :a : :span), 'SSH',
class: klass, class: klass,
href: project.ssh_url_to_repo, href: (project.ssh_url_to_repo if append_link),
data: { data: {
html: true, html: true,
placement: 'right', placement: placement,
container: 'body', container: 'body',
title: 'Add an SSH key to your profile<br>to pull or push via SSH.' title: 'Add an SSH key to your profile<br>to pull or push via SSH.'
} }
......
...@@ -30,12 +30,8 @@ module DiffHelper ...@@ -30,12 +30,8 @@ module DiffHelper
options options
end end
def safe_diff_files(diffs, diff_refs) def safe_diff_files(diffs, diff_refs: nil, repository: nil)
diffs.decorate! { |diff| Gitlab::Diff::File.new(diff, diff_refs) } diffs.decorate! { |diff| Gitlab::Diff::File.new(diff, diff_refs: diff_refs, repository: repository) }
end
def generate_line_code(file_path, line)
Gitlab::Diff::LineCode.generate(file_path, line.new_pos, line.old_pos)
end end
def unfold_bottom_class(bottom) def unfold_bottom_class(bottom)
...@@ -93,6 +89,8 @@ module DiffHelper ...@@ -93,6 +89,8 @@ module DiffHelper
end end
def commit_for_diff(diff_file) def commit_for_diff(diff_file)
return diff_file.content_commit if diff_file.content_commit
if diff_file.deleted_file if diff_file.deleted_file
@base_commit || @commit.parent || @commit @base_commit || @commit.parent || @commit
else else
...@@ -100,10 +98,11 @@ module DiffHelper ...@@ -100,10 +98,11 @@ module DiffHelper
end end
end end
def diff_file_html_data(project, diff_commit, diff_file) def diff_file_html_data(project, diff_file)
commit = commit_for_diff(diff_file)
{ {
blob_diff_path: namespace_project_blob_diff_path(project.namespace, project, blob_diff_path: namespace_project_blob_diff_path(project.namespace, project,
tree_join(diff_commit.id, diff_file.file_path)) tree_join(commit.id, diff_file.file_path))
} }
end end
......
...@@ -39,7 +39,7 @@ module DropdownsHelper ...@@ -39,7 +39,7 @@ module DropdownsHelper
end end
end end
def dropdown_toggle(toggle_text, data_attr, options) def dropdown_toggle(toggle_text, data_attr, options = {})
content_tag(:button, class: "dropdown-menu-toggle #{options[:toggle_class] if options.has_key?(:toggle_class)}", id: (options[:id] if options.has_key?(:id)), type: "button", data: data_attr) do content_tag(:button, class: "dropdown-menu-toggle #{options[:toggle_class] if options.has_key?(:toggle_class)}", id: (options[:id] if options.has_key?(:id)), type: "button", data: data_attr) do
output = content_tag(:span, toggle_text, class: "dropdown-toggle-text") output = content_tag(:span, toggle_text, class: "dropdown-toggle-text")
output << icon('chevron-down') output << icon('chevron-down')
......
module EmailsHelper module EmailsHelper
# Google Actions # Google Actions
# https://developers.google.com/gmail/markup/reference/go-to-action # https://developers.google.com/gmail/markup/reference/go-to-action
def email_action(url) def email_action(url)
......
module IssuablesHelper module IssuablesHelper
def sidebar_gutter_toggle_icon def sidebar_gutter_toggle_icon
sidebar_gutter_collapsed? ? icon('angle-double-left') : icon('angle-double-right') sidebar_gutter_collapsed? ? icon('angle-double-left') : icon('angle-double-right')
end end
......
...@@ -118,7 +118,7 @@ module IssuesHelper ...@@ -118,7 +118,7 @@ module IssuesHelper
end end
def emoji_icon(name, unicode = nil, aliases = [], sprite: true) def emoji_icon(name, unicode = nil, aliases = [], sprite: true)
unicode ||= Emoji.emoji_filename(name) rescue "" unicode ||= Gitlab::Emoji.emoji_filename(name) rescue ""
data = { data = {
aliases: aliases.join(" "), aliases: aliases.join(" "),
......
module KerberosSpnegoHelper
def allow_basic_auth?
true # different behavior in GitLab Enterprise Edition
end
def allow_kerberos_spnego_auth?
false # different behavior in GitLab Enterprise Edition
end
end
...@@ -27,7 +27,7 @@ module MergeRequestsHelper ...@@ -27,7 +27,7 @@ module MergeRequestsHelper
end end
def ci_build_details_path(merge_request) def ci_build_details_path(merge_request)
build_url = merge_request.source_project.ci_service.build_page(merge_request.last_commit.sha, merge_request.source_branch) build_url = merge_request.source_project.ci_service.build_page(merge_request.diff_head_sha, merge_request.source_branch)
return nil unless build_url return nil unless build_url
parsed_url = URI.parse(build_url) parsed_url = URI.parse(build_url)
...@@ -55,6 +55,10 @@ module MergeRequestsHelper ...@@ -55,6 +55,10 @@ module MergeRequestsHelper
end.sort.to_sentence end.sort.to_sentence
end end
def mr_closes_issues
@mr_closes_issues ||= @merge_request.closes_issues
end
def mr_change_branches_path(merge_request) def mr_change_branches_path(merge_request)
new_namespace_project_merge_request_path( new_namespace_project_merge_request_path(
@project.namespace, @project, @project.namespace, @project,
......
...@@ -24,23 +24,55 @@ module NotesHelper ...@@ -24,23 +24,55 @@ module NotesHelper
}.to_json }.to_json
end end
def link_to_new_diff_note(line_code, line_type = nil) def link_to_new_diff_note(line_code, position, line_type = nil)
discussion_id = LegacyDiffNote.build_discussion_id( use_legacy_diff_note = @use_legacy_diff_notes
@comments_target[:noteable_type], # If the controller doesn't force the use of legacy diff notes, we
@comments_target[:noteable_id] || @comments_target[:commit_id], # determine this on a line-by-line basis by seeing if there already exist
line_code # active legacy diff notes at this line, in which case newly created notes
) # will use the legacy technology as well.
# We do this because the discussion_id values of legacy and "new" diff
# notes, which are used to group notes on the merge request discussion tab,
# are incompatible.
# If we didn't, diff notes that would show for the same line on the changes
# tab, would show in different discussions on the discussion tab.
use_legacy_diff_note ||= begin
line_diff_notes = @grouped_diff_notes[line_code]
line_diff_notes && line_diff_notes.any?(&:legacy_diff_note?)
end
data = { data = {
noteable_type: @comments_target[:noteable_type], noteable_type: @comments_target[:noteable_type],
noteable_id: @comments_target[:noteable_id], noteable_id: @comments_target[:noteable_id],
commit_id: @comments_target[:commit_id], commit_id: @comments_target[:commit_id],
line_type: line_type, line_type: line_type,
line_code: line_code, line_code: line_code
note_type: LegacyDiffNote.name,
discussion_id: discussion_id
} }
if use_legacy_diff_note
discussion_id = LegacyDiffNote.build_discussion_id(
@comments_target[:noteable_type],
@comments_target[:noteable_id] || @comments_target[:commit_id],
line_code
)
data.merge!(
note_type: LegacyDiffNote.name,
discussion_id: discussion_id
)
else
discussion_id = DiffNote.build_discussion_id(
@comments_target[:noteable_type],
@comments_target[:noteable_id] || @comments_target[:commit_id],
position
)
data.merge!(
position: position.to_json,
note_type: DiffNote.name,
discussion_id: discussion_id
)
end
button_tag(class: 'btn add-diff-note js-add-diff-note-button', button_tag(class: 'btn add-diff-note js-add-diff-note-button',
data: data, data: data,
title: 'Add a comment to this line') do title: 'Add a comment to this line') do
...@@ -60,14 +92,15 @@ module NotesHelper ...@@ -60,14 +92,15 @@ module NotesHelper
} }
if note.diff_note? if note.diff_note?
data.merge!( data[:note_type] = note.type
line_code: note.line_code,
note_type: LegacyDiffNote.name data.merge!(note.diff_attributes)
)
end end
button_tag 'Reply...', class: 'btn btn-text-field js-discussion-reply-button', content_tag(:div, class: "discussion-reply-holder") do
data: data, title: 'Add a reply' button_tag 'Reply...', class: 'btn btn-text-field js-discussion-reply-button',
data: data, title: 'Add a reply'
end
end end
def note_max_access_for_user(note) def note_max_access_for_user(note)
...@@ -79,4 +112,14 @@ module NotesHelper ...@@ -79,4 +112,14 @@ module NotesHelper
full_key = { project: note.project, user_id: note.author_id } full_key = { project: note.project, user_id: note.author_id }
@max_access_by_user_id[full_key] @max_access_by_user_id[full_key]
end end
def diff_note_path(note)
return unless note.diff_note?
if note.for_merge_request? && note.active?
diffs_namespace_project_merge_request_path(note.project.namespace, note.project, note.noteable, anchor: note.line_code)
elsif note.for_commit?
namespace_project_commit_path(note.project.namespace, note.project, note.noteable, anchor: note.line_code)
end
end
end end
...@@ -206,10 +206,14 @@ module ProjectsHelper ...@@ -206,10 +206,14 @@ module ProjectsHelper
end end
def default_clone_protocol def default_clone_protocol
if !current_user || current_user.require_ssh_key? if allowed_protocols_present?
gitlab_config.protocol enabled_protocol
else else
"ssh" if !current_user || current_user.require_ssh_key?
gitlab_config.protocol
else
'ssh'
end
end end
end end
...@@ -289,7 +293,11 @@ module ProjectsHelper ...@@ -289,7 +293,11 @@ module ProjectsHelper
end end
def last_push_event def last_push_event
if current_user return unless current_user
if fork = current_user.fork_of(@project)
current_user.recent_push(fork.id)
else
current_user.recent_push(@project.id) current_user.recent_push(@project.id)
end end
end end
......
module SearchHelper module SearchHelper
def search_autocomplete_opts(term) def search_autocomplete_opts(term)
return unless current_user return unless current_user
......
...@@ -23,4 +23,11 @@ module TimeHelper ...@@ -23,4 +23,11 @@ module TimeHelper
def date_from_to(from, to) def date_from_to(from, to)
"#{from.to_s(:short)} - #{to.to_s(:short)}" "#{from.to_s(:short)} - #{to.to_s(:short)}"
end end
def duration_in_numbers(finished_at, started_at)
diff_in_seconds = finished_at.to_i - started_at.to_i
time_format = diff_in_seconds < 1.hour ? "%M:%S" : "%H:%M:%S"
Time.at(diff_in_seconds).utc.strftime(time_format)
end
end end
# Helpers to send Git blobs, diffs or archives through Workhorse. # Helpers to send Git blobs, diffs, patches or archives through Workhorse.
# Workhorse will also serve files when using `send_file`. # Workhorse will also serve files when using `send_file`.
module WorkhorseHelper module WorkhorseHelper
# Send a Git blob through Workhorse # Send a Git blob through Workhorse
...@@ -16,6 +16,13 @@ module WorkhorseHelper ...@@ -16,6 +16,13 @@ module WorkhorseHelper
head :ok head :ok
end end
# Send a Git patch through Workhorse
def send_git_patch(repository, diff_refs)
headers.store(*Gitlab::Workhorse.send_git_patch(repository, diff_refs))
headers['Content-Disposition'] = 'inline'
head :ok
end
# Archive a Git repository and send it through Workhorse # Archive a Git repository and send it through Workhorse
def send_git_archive(repository, ref:, format:) def send_git_archive(repository, ref:, format:)
headers.store(*Gitlab::Workhorse.send_git_archive(repository, ref: ref, format: format)) headers.store(*Gitlab::Workhorse.send_git_archive(repository, ref: ref, format: format))
......
...@@ -29,8 +29,7 @@ module Emails ...@@ -29,8 +29,7 @@ module Emails
# used in notify layout # used in notify layout
@target_url = @message.target_url @target_url = @message.target_url
@project = Project.find(project_id) @project = Project.find(project_id)
@diff_notes_disabled = true
add_project_headers add_project_headers
headers['X-GitLab-Author'] = @message.author_username headers['X-GitLab-Author'] = @message.author_username
......
...@@ -157,10 +157,11 @@ class Ability ...@@ -157,10 +157,11 @@ class Ability
# Push abilities on the users team role # Push abilities on the users team role
rules.push(*project_team_rules(project.team, user)) rules.push(*project_team_rules(project.team, user))
if project.owner == user || owner = user.admin? ||
(project.group && project.group.has_owner?(user)) || project.owner == user ||
user.admin? (project.group && project.group.has_owner?(user))
if owner
rules.push(*project_owner_rules) rules.push(*project_owner_rules)
end end
...@@ -169,6 +170,10 @@ class Ability ...@@ -169,6 +170,10 @@ class Ability
# Allow to read builds for internal projects # Allow to read builds for internal projects
rules << :read_build if project.public_builds? rules << :read_build if project.public_builds?
unless owner || project.team.member?(user) || project_group_member?(project, user)
rules << :request_access
end
end end
if project.archived? if project.archived?
...@@ -345,8 +350,11 @@ class Ability ...@@ -345,8 +350,11 @@ class Ability
rules = [] rules = []
rules << :read_group if can_read_group?(user, group) rules << :read_group if can_read_group?(user, group)
owner = user.admin? || group.has_owner?(user)
master = owner || group.has_master?(user)
# Only group masters and group owners can create new projects # Only group masters and group owners can create new projects
if group.has_master?(user) || group.has_owner?(user) || user.admin? if master
rules += [ rules += [
:create_projects, :create_projects,
:admin_milestones :admin_milestones
...@@ -354,7 +362,7 @@ class Ability ...@@ -354,7 +362,7 @@ class Ability
end end
# Only group owner and administrators can admin group # Only group owner and administrators can admin group
if group.has_owner?(user) || user.admin? if owner
rules += [ rules += [
:admin_group, :admin_group,
:admin_namespace, :admin_namespace,
...@@ -363,6 +371,10 @@ class Ability ...@@ -363,6 +371,10 @@ class Ability
] ]
end end
if group.public? || (group.internal? && !user.external?)
rules << :request_access unless group.users.include?(user)
end
rules.flatten rules.flatten
end end
...@@ -564,5 +576,13 @@ class Ability ...@@ -564,5 +576,13 @@ class Ability
rules rules
end end
def project_group_member?(project, user)
project.group &&
(
project.group.members.exists?(user_id: user.id) ||
project.group.requesters.exists?(user_id: user.id)
)
end
end end
end end
...@@ -59,6 +59,9 @@ class ApplicationSetting < ActiveRecord::Base ...@@ -59,6 +59,9 @@ class ApplicationSetting < ActiveRecord::Base
presence: true, presence: true,
inclusion: { in: ->(_object) { Gitlab.config.repositories.storages.keys } } inclusion: { in: ->(_object) { Gitlab.config.repositories.storages.keys } }
validates :enabled_git_access_protocol,
inclusion: { in: %w(ssh http), allow_blank: true, allow_nil: true }
validates_each :restricted_visibility_levels do |record, attr, value| validates_each :restricted_visibility_levels do |record, attr, value|
unless value.nil? unless value.nil?
value.each do |level| value.each do |level|
...@@ -139,6 +142,7 @@ class ApplicationSetting < ActiveRecord::Base ...@@ -139,6 +142,7 @@ class ApplicationSetting < ActiveRecord::Base
send_user_confirmation_email: false, send_user_confirmation_email: false,
container_registry_token_expire_delay: 5, container_registry_token_expire_delay: 5,
repository_storage: 'default', repository_storage: 'default',
user_default_external: false,
) )
end end
......
...@@ -8,7 +8,7 @@ class AwardEmoji < ActiveRecord::Base ...@@ -8,7 +8,7 @@ class AwardEmoji < ActiveRecord::Base
belongs_to :user belongs_to :user
validates :awardable, :user, presence: true validates :awardable, :user, presence: true
validates :name, presence: true, inclusion: { in: Emoji.emojis_names } validates :name, presence: true, inclusion: { in: Gitlab::Emoji.emojis_names }
validates :name, uniqueness: { scope: [:user, :awardable_type, :awardable_id] } validates :name, uniqueness: { scope: [:user, :awardable_type, :awardable_id] }
participant :user participant :user
......
...@@ -13,21 +13,19 @@ module Ci ...@@ -13,21 +13,19 @@ module Ci
scope :ignore_failures, ->() { where(allow_failure: false) } scope :ignore_failures, ->() { where(allow_failure: false) }
scope :with_artifacts, ->() { where.not(artifacts_file: nil) } scope :with_artifacts, ->() { where.not(artifacts_file: nil) }
scope :with_expired_artifacts, ->() { with_artifacts.where('artifacts_expire_at < ?', Time.now) } scope :with_expired_artifacts, ->() { with_artifacts.where('artifacts_expire_at < ?', Time.now) }
scope :last_month, ->() { where('created_at > ?', Date.today - 1.month) }
mount_uploader :artifacts_file, ArtifactUploader mount_uploader :artifacts_file, ArtifactUploader
mount_uploader :artifacts_metadata, ArtifactUploader mount_uploader :artifacts_metadata, ArtifactUploader
acts_as_taggable acts_as_taggable
before_save :update_artifacts_size, if: :artifacts_file_changed?
before_destroy { project } before_destroy { project }
after_create :execute_hooks after_create :execute_hooks
class << self class << self
def last_month
where('created_at > ?', Date.today - 1.month)
end
def first_pending def first_pending
pending.unstarted.order('created_at ASC').first pending.unstarted.order('created_at ASC').first
end end
...@@ -329,7 +327,12 @@ module Ci ...@@ -329,7 +327,12 @@ module Ci
end end
def artifacts_metadata_entry(path, **options) def artifacts_metadata_entry(path, **options)
Gitlab::Ci::Build::Artifacts::Metadata.new(artifacts_metadata.path, path, **options).to_entry metadata = Gitlab::Ci::Build::Artifacts::Metadata.new(
artifacts_metadata.path,
path,
**options)
metadata.to_entry
end end
def erase_artifacts! def erase_artifacts!
...@@ -375,6 +378,14 @@ module Ci ...@@ -375,6 +378,14 @@ module Ci
private private
def update_artifacts_size
self.artifacts_size = if artifacts_file.exists?
artifacts_file.size
else
nil
end
end
def erase_trace! def erase_trace!
self.trace = nil self.trace = nil
end end
......
...@@ -16,6 +16,7 @@ module Ci ...@@ -16,6 +16,7 @@ module Ci
# Invalidate object and save if when touched # Invalidate object and save if when touched
after_touch :update_state after_touch :update_state
after_save :keep_around_commits
def self.truncate_sha(sha) def self.truncate_sha(sha)
sha[0...8] sha[0...8]
...@@ -212,5 +213,10 @@ module Ci ...@@ -212,5 +213,10 @@ module Ci
self.duration = statuses.latest.duration self.duration = statuses.latest.duration
save save
end end
def keep_around_commits
project.repository.keep_around(self.sha)
project.repository.keep_around(self.before_sha)
end
end end
end end
module Ci module Ci
class TriggerRequest < ActiveRecord::Base class TriggerRequest < ActiveRecord::Base
extend Ci::Model extend Ci::Model
belongs_to :trigger, class_name: 'Ci::Trigger' belongs_to :trigger, class_name: 'Ci::Trigger'
belongs_to :pipeline, class_name: 'Ci::Pipeline', foreign_key: :commit_id belongs_to :pipeline, class_name: 'Ci::Pipeline', foreign_key: :commit_id
has_many :builds, class_name: 'Ci::Build' has_many :builds, class_name: 'Ci::Build'
......
...@@ -214,6 +214,13 @@ class Commit ...@@ -214,6 +214,13 @@ class Commit
@raw.short_id(7) @raw.short_id(7)
end end
def diff_refs
Gitlab::Diff::DiffRefs.new(
base_sha: self.parent_id || self.sha,
head_sha: self.sha
)
end
def pipelines def pipelines
@pipeline ||= project.pipelines.where(sha: sha) @pipeline ||= project.pipelines.where(sha: sha)
end end
......
...@@ -23,7 +23,7 @@ class CommitRange ...@@ -23,7 +23,7 @@ class CommitRange
attr_reader :commit_from, :notation, :commit_to attr_reader :commit_from, :notation, :commit_to
attr_reader :ref_from, :ref_to attr_reader :ref_from, :ref_to
# Optional Project model # The Project model
attr_accessor :project attr_accessor :project
# The beginning and ending refs can be named or SHAs, and # The beginning and ending refs can be named or SHAs, and
...@@ -56,7 +56,7 @@ class CommitRange ...@@ -56,7 +56,7 @@ class CommitRange
# Initialize a CommitRange # Initialize a CommitRange
# #
# range_string - The String commit range. # range_string - The String commit range.
# project - An optional Project model. # project - The Project model.
# #
# Raises ArgumentError if `range_string` does not match `PATTERN`. # Raises ArgumentError if `range_string` does not match `PATTERN`.
def initialize(range_string, project) def initialize(range_string, project)
......
...@@ -58,7 +58,6 @@ module Issuable ...@@ -58,7 +58,6 @@ module Issuable
scope :references_project, -> { references(:project) } scope :references_project, -> { references(:project) }
scope :non_archived, -> { join_project.where(projects: { archived: false }) } scope :non_archived, -> { join_project.where(projects: { archived: false }) }
delegate :name, delegate :name,
:email, :email,
to: :author, to: :author,
......
...@@ -45,7 +45,7 @@ module Mentionable ...@@ -45,7 +45,7 @@ module Mentionable
def all_references(current_user = nil, text = nil, extractor: nil) def all_references(current_user = nil, text = nil, extractor: nil)
extractor ||= Gitlab::ReferenceExtractor. extractor ||= Gitlab::ReferenceExtractor.
new(project, current_user || author) new(project, current_user)
if text if text
extractor.analyze(text, author: author) extractor.analyze(text, author: author)
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
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