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

# Conflicts:
#	app/assets/stylesheets/pages/issuable.scss
This commit is contained in:
Fatih Acet 2016-05-23 23:08:00 +03:00
commit aa2a7dad59
664 changed files with 12591 additions and 2251 deletions

View File

@ -21,6 +21,7 @@ AllCops:
- 'lib/email_validator.rb'
- 'lib/gitlab/upgrader.rb'
- 'lib/gitlab/seeder.rb'
- 'generator_templates/**/*'
##################### Style ##################################
@ -151,7 +152,7 @@ Style/ConstantName:
# Use def with parentheses when there are arguments.
Style/DefWithParentheses:
Enabled: false
Enabled: true
# Checks for use of deprecated Hash methods.
Style/DeprecatedHashMethods:
@ -276,7 +277,7 @@ Style/IdenticalConditionalBranches:
Enabled: false
# Checks the indentation of the first line of the right-hand-side of a
# multi-line assignment.
# multi-line assignment.
Style/IndentAssignment:
Enabled: false
@ -298,7 +299,7 @@ Style/IndentHash:
# Use Kernel#loop for infinite loops.
Style/InfiniteLoop:
Enabled: false
Enabled: true
# Use the new lambda literal syntax for single-line blocks.
Style/Lambda:
@ -332,6 +333,12 @@ Style/MethodName:
Style/ModuleFunction:
Enabled: false
# Checks that the closing brace in an array literal is either on the same line
# as the last array element, or a new line.
Style/MultilineArrayBraceLayout:
Enabled: false
EnforcedStyle: symmetrical
# Avoid multi-line chains of blocks.
Style/MultilineBlockChain:
Enabled: false
@ -340,10 +347,22 @@ Style/MultilineBlockChain:
Style/MultilineBlockLayout:
Enabled: true
# Checks that the closing brace in a hash literal is either on the same line as
# the last hash element, or a new line.
Style/MultilineHashBraceLayout:
Enabled: false
EnforcedStyle: symmetrical
# Do not use then for multi-line if/unless.
Style/MultilineIfThen:
Enabled: false
# Checks that the closing brace in a method call is either on the same line as
# the last method argument, or a new line.
Style/MultilineMethodCallBraceLayout:
Enabled: false
EnforcedStyle: symmetrical
# Checks indentation of method calls with the dot operator that span more than
# one line.
Style/MultilineMethodCallIndentation:
@ -524,14 +543,13 @@ Style/SpaceAfterSemicolon:
Style/SpaceAroundEqualsInParameterDefault:
Enabled: false
# TODO: Enable SpaceAroundKeyword Cop.
# Use a space around keywords if appropriate.
Style/SpaceAroundKeyword:
Enabled: false
Enabled: true
# Use a single space around operators.
Style/SpaceAroundOperators:
Enabled: false
Enabled: true
# Checks that the left block brace has or doesn't have space before it.
Style/SpaceBeforeBlockBraces:
@ -754,23 +772,23 @@ Lint/BlockAlignment:
# Default values in optional keyword arguments and optional ordinal arguments
# should not refer back to the name of the argument.
Lint/CircularArgumentReference:
Enabled: false
Enabled: true
# Checks for condition placed in a confusing position relative to the keyword.
Lint/ConditionPosition:
Enabled: false
Enabled: true
# Check for debugger calls.
Lint/Debugger:
Enabled: false
Enabled: true
# Align ends corresponding to defs correctly.
Lint/DefEndAlignment:
Enabled: false
Enabled: true
# Check for deprecated class method calls.
Lint/DeprecatedClassMethods:
Enabled: false
Enabled: true
# Check for duplicate method definitions.
Lint/DuplicateMethods:
@ -782,15 +800,15 @@ Lint/DuplicatedKey:
# Check for immutable argument given to each_with_object.
Lint/EachWithObjectArgument:
Enabled: false
Enabled: true
# Check for odd code arrangement in an else block.
Lint/ElseLayout:
Enabled: false
Enabled: true
# Checks for empty ensure block.
Lint/EmptyEnsure:
Enabled: false
Enabled: true
# Checks for empty string interpolation.
Lint/EmptyInterpolation:
@ -798,37 +816,36 @@ Lint/EmptyInterpolation:
# Align ends correctly.
Lint/EndAlignment:
Enabled: false
Enabled: true
# END blocks should not be placed inside method definitions.
Lint/EndInMethod:
Enabled: false
Enabled: true
# Do not use return in an ensure block.
Lint/EnsureReturn:
Enabled: false
Enabled: true
# The use of eval represents a serious security risk.
Lint/Eval:
Enabled: false
Enabled: true
# Catches floating-point literals too large or small for Ruby to represent.
Lint/FloatOutOfRange:
Enabled: false
Enabled: true
# The number of parameters to format/sprint must match the fields.
Lint/FormatParameterMismatch:
Enabled: false
Enabled: true
# Don't suppress exception.
Lint/HandleExceptions:
Enabled: false
# TODO: Enable ImplicitStringConcatenation Cop.
# Checks for adjacent string literals on the same line, which could better be
# represented as a single string literal.
Lint/ImplicitStringConcatenation:
Enabled: false
Enabled: true
# TODO: Enable IneffectiveAccessModifier Cop.
# Checks for attempts to use `private` or `protected` to set the visibility
@ -839,7 +856,7 @@ Lint/IneffectiveAccessModifier:
# Checks for invalid character literals with a non-escaped whitespace
# character.
Lint/InvalidCharacterLiteral:
Enabled: false
Enabled: true
# Checks of literals used in conditions.
Lint/LiteralInCondition:
@ -847,7 +864,7 @@ Lint/LiteralInCondition:
# Checks for literals used in interpolation.
Lint/LiteralInInterpolation:
Enabled: false
Enabled: true
# Use Kernel#loop with break rather than begin/end/until or begin/end/while
# for post-loop tests.
@ -856,11 +873,11 @@ Lint/Loop:
# Do not use nested method definitions.
Lint/NestedMethodDefinition:
Enabled: false
Enabled: true
# Do not omit the accumulator when calling `next` in a `reduce`/`inject` block.
Lint/NextWithoutAccumulator:
Enabled: false
Enabled: true
# Checks for method calls with a space before the opening parenthesis.
Lint/ParenthesesAsGroupedExpression:
@ -869,11 +886,11 @@ Lint/ParenthesesAsGroupedExpression:
# Checks for `rand(1)` calls. Such calls always return `0` and most likely
# a mistake.
Lint/RandOne:
Enabled: false
Enabled: true
# Use parentheses in the method call to avoid confusion about precedence.
Lint/RequireParentheses:
Enabled: false
Enabled: true
# Avoid rescuing the Exception class.
Lint/RescueException:
@ -908,7 +925,7 @@ Lint/UnusedMethodArgument:
# Unreachable code.
Lint/UnreachableCode:
Enabled: false
Enabled: true
# Checks for useless access modifiers.
Lint/UselessAccessModifier:
@ -920,19 +937,19 @@ Lint/UselessAssignment:
# Checks for comparison of something with itself.
Lint/UselessComparison:
Enabled: false
Enabled: true
# Checks for useless `else` in `begin..end` without `rescue`.
Lint/UselessElseWithoutRescue:
Enabled: false
Enabled: true
# Checks for useless setter call to a local variable.
Lint/UselessSetterCall:
Enabled: false
Enabled: true
# Possible use of operator/literal/variable in void context.
Lint/Void:
Enabled: false
Enabled: true
##################### Performance ############################
@ -941,11 +958,10 @@ Lint/Void:
Performance/Casecmp:
Enabled: true
# TODO: Enable DoubleStartEndWith Cop.
# Use `str.{start,end}_with?(x, ..., y, ...)` instead of
# `str.{start,end}_with?(x, ...) || str.{start,end}_with?(y, ...)`.
Performance/DoubleStartEndWith:
Enabled: false
Enabled: true
# TODO: Enable EndWith Cop.
# Use `end_with?` instead of a regex match anchored to the end of a string.
@ -956,10 +972,9 @@ Performance/EndWith:
Performance/LstripRstrip:
Enabled: true
# TODO: Enable RangeInclude Cop.
# Use `Range#cover?` instead of `Range#include?`.
Performance/RangeInclude:
Enabled: false
Enabled: true
# TODO: Enable RedundantBlockCall Cop.
# Use `yield` instead of `block.call`.
@ -979,16 +994,14 @@ Performance/RedundantMerge:
MaxKeyValuePairs: 2
Enabled: false
# TODO: Enable RedundantSortBy Cop.
# Use `sort` instead of `sort_by { |x| x }`.
Performance/RedundantSortBy:
Enabled: false
Enabled: true
# TODO: Enable StartWith Cop.
# Use `start_with?` instead of a regex match anchored to the beginning of a
# string.
Performance/StartWith:
Enabled: false
Enabled: true
# Use `tr` instead of `gsub` when you are replacing the same number of
# characters. Use `delete` instead of `gsub` when you are deleting
@ -1024,11 +1037,11 @@ Rails/Delegate:
# Prefer `find_by` over `where.first`.
Rails/FindBy:
Enabled: false
Enabled: true
# Prefer `all.find_each` over `all.find`.
Rails/FindEach:
Enabled: false
Enabled: true
# Prefer has_many :through to has_and_belongs_to_many.
Rails/HasAndBelongsToMany:
@ -1040,7 +1053,7 @@ Rails/Output:
# Checks for incorrect grammar when using methods like `3.day.ago`.
Rails/PluralizationGrammar:
Enabled: false
Enabled: true
# Checks for `read_attribute(:attr)` and `write_attribute(:attr, val)`.
Rails/ReadWriteAttribute:
@ -1048,7 +1061,7 @@ Rails/ReadWriteAttribute:
# Checks the arguments of ActiveRecord scopes.
Rails/ScopeArgs:
Enabled: false
Enabled: true
# Checks the correct usage of time zone aware methods.
# http://danilenko.org/2012/7/6/rails_timezones

View File

@ -1,57 +1,115 @@
Please view this file on the master branch, on stable branches it's out of date.
v 8.8.0 (unreleased)
v 8.8.2 (unreleased)
- Fix Error 500 when accessing application settings due to nil disabled OAuth sign-in sources
- Fix Error 500 in CI charts by gracefully handling commits with no durations
v 8.8.1
- Add documentation for the "Health Check" feature
- Allow anonymous users to access a public project's pipelines
- Fix MySQL compatibility in zero downtime migrations helpers
- Fix the CI login to Container Registry (the gitlab-ci-token user)
v 8.8.0
- Implement GFM references for milestones (Alejandro Rodríguez)
- Snippets tab under user profile. !4001 (Long Nguyen)
- Fix error when using link to uploads in global snippets
- Fix Error 500 when attempting to retrieve project license when HEAD points to non-existent ref
- Assign labels and milestone to target project when moving issue. !3934 (Long Nguyen)
- Use a case-insensitive comparison in sanitizing URI schemes
- Toggle sign-up confirmation emails in application settings
- Make it possible to prevent tagged runner from picking untagged jobs
- Added `InlineDiffFilter` to the markdown parser. (Adam Butler)
- Added inline diff styling for `change_title` system notes. (Adam Butler)
- Project#open_branches has been cleaned up and no longer loads entire records into memory.
- Escape HTML in commit titles in system note messages
- Fix scope used when accessing container registry
- Fix creation of Ci::Commit object which can lead to pending, failed in some scenarios
- Improve multiple branch push performance by memoizing permission checking
- Log to application.log when an admin starts and stops impersonating a user
- Changing the confidentiality of an issue now creates a new system note (Alex Moore-Niemi)
- Updated gitlab_git to 10.1.0
- GitAccess#protected_tag? no longer loads all tags just to check if a single one exists
- Reduce delay in destroying a project from 1-minute to immediately
- Make build status canceled if any of the jobs was canceled and none failed
- Upgrade Sidekiq to 4.1.2
- Added /health_check endpoint for checking service status
- Make 'upcoming' filter for milestones work better across projects
- Sanitize repo paths in new project error message
- Bump mail_room to 0.7.0 to fix stuck IDLE connections
- Remove future dates from contribution calendar graph.
- Support e-mail notifications for comments on project snippets
- Fix API leak of notes of unauthorized issues, snippets and merge requests
- Use ActionDispatch Remote IP for Akismet checking
- Fix error when visiting commit builds page before build was updated
- Add 'l' shortcut to open Label dropdown on issuables and 'i' to create new issue on a project
- Update SVG sanitizer to conform to SVG 1.1
- Speed up push emails with multiple recipients by only generating the email once
- Updated search UI
- Added authentication service for Container Registry
- Display informative message when new milestone is created
- Sanitize milestones and labels titles
- Support multi-line tag messages. !3833 (Calin Seciu)
- Force users to reset their password after an admin changes it
- Allow "NEWS" and "CHANGES" as alternative names for CHANGELOG. !3768 (Connor Shea)
- Added button to toggle whitespaces changes on diff view
- Backport GitHub Enterprise import support from EE
- Create tags using Rugged for performance reasons. !3745
- Allow guests to set notification level in projects
- API: Expose Issue#user_notes_count. !3126 (Anton Popov)
- Don't show forks button when user can't view forks
- Fix atom feed links and rendering
- Files over 5MB can only be viewed in their raw form, files over 1MB without highlighting !3718
- Add support for supressing text diffs using .gitattributes on the default branch (Matt Oakes)
- Add eager load paths to help prevent dependency load issues in Sidekiq workers. !3724
- Added multiple colors for labels in dropdowns when dups happen.
- Show commits in the same order as `git log`
- Improve description for the Two-factor Authentication sign-in screen. (Connor Shea)
- API support for the 'since' and 'until' operators on commit requests (Paco Guzman)
- Fix Gravatar hint in user profile when Gravatar is disabled. !3988 (Artem Sidorenko)
- Expire repository exists? and has_visible_content? caches after a push if necessary
- Fix unintentional filtering bug in issues sorted by milestone due (Takuya Noguchi)
- Fix unintentional filtering bug in Issue/MR sorted by milestone due (Takuya Noguchi)
- Fix adding a todo for private group members (Ahmad Sherif)
- Bump ace-rails-ap gem version from 2.0.1 to 4.0.2 which upgrades Ace Editor from 1.1.2 to 1.2.3
- Total method execution timings are no longer tracked
- Allow Admins to remove the Login with buttons for OAuth services and still be able to import !4034. (Andrei Gliga)
- Add API endpoints for un/subscribing from/to a label. !4051 (Ahmad Sherif)
- Hide left sidebar on phone screens to give more space for content
- Redesign navigation for profile and group pages
- Add counter metrics for rails cache
- Import pull requests from GitHub where the source or target branches were removed
- All Grape API helpers are now instrumented
- Improve Issue formatting for the Slack Service (Jeroen van Baarsen)
- Fixed advice on invalid permissions on upload path !2948 (Ludovic Perrine)
- Allows MR authors to have the source branch removed when merging the MR. !2801 (Jeroen Jacobs)
- When creating a .gitignore file a dropdown with templates will be provided
v 8.7.6
- Fix links on wiki pages for relative url setups. !4131 (Artem Sidorenko)
- Fix import from GitLab.com to a private instance failure. !4181
- Fix external imports not finding the import data. !4106
v 8.7.5
- Fix relative links in wiki pages. !4050
- Fix always showing build notification message when switching between merge requests !4086
- Fix an issue when filtering merge requests with more than one label. !3886
- Fix short note for the default scope on build page (Takuya Noguchi)
v 8.7.4
- Fix always showing build notification message when switching between merge requests
- Links for Redmine issue references are generated correctly again (Benedikt Huss)
- Fix an issue when filtering merge requests with more than one label. !3886
- Links for Redmine issue references are generated correctly again !4048 (Benedikt Huss)
- Fix setting trusted proxies !3970
- Fix BitBucket importer bug when throwing exceptions !3941
- Use sign out path only if not empty !3989
- Running rake gitlab:db:drop_tables now drops tables with cascade !4020
- Running rake gitlab:db:drop_tables uses "IF EXISTS" as a precaution !4100
- Use a case-insensitive comparison in sanitizing URI schemes
v 8.7.3
- Emails, Gitlab::Email::Message, Gitlab::Diff, and Premailer::Adapter::Nokogiri are now instrumented
- Merge request widget displays TeamCity build state and code coverage correctly again.
- Fix the line code when importing PR review comments from GitHub. !4010
- Wikis are now initialized on legacy projects when checking repositories
- Remove animate.css in favor of a smaller subset of animations. !3937 (Connor Shea)
v 8.7.2
- The "New Branch" button is now loaded asynchronously
@ -860,7 +918,7 @@ v 8.1.3
- Use issue editor as cross reference comment author when issue is edited with a new mention
- Add Facebook authentication
v 8.1.2
v 8.1.1
- Fix cloning Wiki repositories via HTTP (Stan Hu)
- Add migration to remove satellites directory
- Fix specific runners visibility
@ -1485,20 +1543,17 @@ v 7.10.0
- Fix stuck Merge Request merging events from old installations (Ben Bodenmiller)
- Fix merge request comments on files with multiple commits
- Fix Resource Owner Password Authentication Flow
v 7.9.4
- Security: Fix project import URL regex to prevent arbitary local repos from being imported
- Fixed issue where only 25 commits would load in file listings
- Fix LDAP identities after config update
v 7.9.3
- Contains no changes
- Add icons to Add dropdown items.
- Allow admin to create public deploy keys that are accessible to any project.
- Warn when gitlab-shell version doesn't match requirement.
- Skip email confirmation when set by admin or via LDAP.
- Only allow users to reference groups, projects, issues, MRs, commits they have access to.
v 7.9.4
- Security: Fix project import URL regex to prevent arbitary local repos from being imported
- Fixed issue where only 25 commits would load in file listings
- Fix LDAP identities after config update
v 7.9.3
- Contains no changes

View File

@ -1 +1 @@
0.7.1
0.7.3

12
Gemfile
View File

@ -36,6 +36,7 @@ gem 'omniauth-shibboleth', '~> 1.2.0'
gem 'omniauth-twitter', '~> 1.2.0'
gem 'omniauth_crowd', '~> 2.2.0'
gem 'rack-oauth2', '~> 1.2.1'
gem 'jwt'
# Spam and anti-bot protection
gem 'recaptcha', require: 'recaptcha/rails'
@ -224,6 +225,7 @@ gem 'request_store', '~> 1.3.0'
gem 'select2-rails', '~> 3.5.9'
gem 'virtus', '~> 1.0.1'
gem 'net-ssh', '~> 3.0.1'
gem 'base32', '~> 0.3.0'
# Sentry integration
gem 'sentry-raven', '~> 0.15'
@ -291,9 +293,9 @@ group :development, :test do
gem 'spring-commands-spinach', '~> 1.1.0'
gem 'spring-commands-teaspoon', '~> 0.0.2'
gem 'rubocop', '~> 0.38.0', require: false
gem 'rubocop', '~> 0.40.0', require: false
gem 'scss_lint', '~> 0.47.0', require: false
gem 'coveralls', '~> 0.8.2', require: false
gem 'coveralls', '~> 0.8.2', require: false
gem 'simplecov', '~> 0.11.0', require: false
gem 'flog', require: false
gem 'flay', require: false
@ -323,8 +325,7 @@ gem "mail_room", "~> 0.7"
gem 'email_reply_parser', '~> 0.5.8'
## CI
gem 'activerecord-deprecated_finders', '~> 1.0.3'
gem 'activerecord-session_store', '~> 0.1.0'
gem 'activerecord-session_store', '~> 1.0.0'
gem "nested_form", '~> 0.3.2'
# OAuth
@ -332,3 +333,6 @@ gem 'oauth2', '~> 1.0.0'
# Soft deletion
gem "paranoia", "~> 2.0"
# Health check
gem 'health_check', '~> 1.5.1'

View File

@ -33,11 +33,12 @@ GEM
activemodel (= 4.2.6)
activesupport (= 4.2.6)
arel (~> 6.0)
activerecord-deprecated_finders (1.0.4)
activerecord-session_store (0.1.2)
actionpack (>= 4.0.0, < 5)
activerecord (>= 4.0.0, < 5)
railties (>= 4.0.0, < 5)
activerecord-session_store (1.0.0)
actionpack (>= 4.0, < 5.1)
activerecord (>= 4.0, < 5.1)
multi_json (~> 1.11, >= 1.11.2)
rack (>= 1.5.2, < 3)
railties (>= 4.0, < 5.1)
activesupport (4.2.6)
i18n (~> 0.7)
json (~> 1.7, >= 1.7.7)
@ -71,6 +72,7 @@ GEM
ice_nine (~> 0.11.0)
thread_safe (~> 0.3, >= 0.3.1)
babosa (1.0.2)
base32 (0.3.2)
bcrypt (3.1.10)
benchmark-ips (2.3.0)
better_errors (1.0.1)
@ -402,6 +404,8 @@ GEM
html2haml (>= 1.0.1)
railties (>= 4.0.1)
hashie (3.4.3)
health_check (1.5.1)
rails (>= 2.3.0)
highline (1.7.8)
hipchat (1.5.2)
httparty
@ -547,7 +551,7 @@ GEM
orm_adapter (0.5.0)
paranoia (2.1.4)
activerecord (~> 4.0)
parser (2.3.0.6)
parser (2.3.1.0)
ast (~> 2.2)
pg (0.18.4)
poltergeist (1.9.0)
@ -682,15 +686,15 @@ GEM
rspec-retry (0.4.5)
rspec-core
rspec-support (3.4.1)
rubocop (0.38.0)
parser (>= 2.3.0.6, < 3.0)
rubocop (0.40.0)
parser (>= 2.3.1.0, < 3.0)
powerpack (~> 0.1)
rainbow (>= 1.99.1, < 3.0)
ruby-progressbar (~> 1.7)
unicode-display_width (~> 1.0, >= 1.0.1)
ruby-fogbugz (0.2.1)
crack (~> 0.4)
ruby-progressbar (1.7.5)
ruby-progressbar (1.8.1)
ruby-saml (1.1.2)
nokogiri (>= 1.5.10)
uuid (~> 2.3)
@ -837,7 +841,7 @@ GEM
unf (0.1.4)
unf_ext
unf_ext (0.0.7.2)
unicode-display_width (1.0.2)
unicode-display_width (1.0.5)
unicorn (4.9.0)
kgio (~> 2.6)
rack
@ -881,8 +885,7 @@ PLATFORMS
DEPENDENCIES
RedCloth (~> 4.2.9)
ace-rails-ap (~> 4.0.2)
activerecord-deprecated_finders (~> 1.0.3)
activerecord-session_store (~> 0.1.0)
activerecord-session_store (~> 1.0.0)
acts-as-taggable-on (~> 3.4)
addressable (~> 2.3.8)
after_commit_queue
@ -893,6 +896,7 @@ DEPENDENCIES
attr_encrypted (~> 1.3.4)
awesome_print (~> 1.2.0)
babosa (~> 1.0.2)
base32 (~> 0.3.0)
benchmark-ips
better_errors (~> 1.0.1)
binding_of_caller (~> 0.7.2)
@ -945,6 +949,7 @@ DEPENDENCIES
grape (~> 0.13.0)
grape-entity (~> 0.4.2)
haml-rails (~> 0.9.0)
health_check (~> 1.5.1)
hipchat (~> 1.5.0)
html-pipeline (~> 1.11.0)
httparty (~> 0.13.3)
@ -953,6 +958,7 @@ DEPENDENCIES
jquery-rails (~> 4.1.0)
jquery-turbolinks (~> 2.1.0)
jquery-ui-rails (~> 5.0.0)
jwt
kaminari (~> 0.16.3)
letter_opener_web (~> 1.3.0)
licensee (~> 8.0.0)
@ -1009,7 +1015,7 @@ DEPENDENCIES
rqrcode-rails3 (~> 0.1.7)
rspec-rails (~> 3.4.0)
rspec-retry
rubocop (~> 0.38.0)
rubocop (~> 0.40.0)
ruby-fogbugz (~> 0.2.1)
sanitize (~> 2.0)
sass-rails (~> 5.0.0)
@ -1054,4 +1060,4 @@ DEPENDENCIES
wikicloth (= 0.8.1)
BUNDLED WITH
1.12.3
1.12.4

Binary file not shown.

Before

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 74 KiB

View File

@ -1,14 +1,15 @@
@Api =
groups_path: "/api/:version/groups.json"
group_path: "/api/:version/groups/:id.json"
namespaces_path: "/api/:version/namespaces.json"
group_projects_path: "/api/:version/groups/:id/projects.json"
projects_path: "/api/:version/projects.json"
labels_path: "/api/:version/projects/:id/labels"
license_path: "/api/:version/licenses/:key"
groupsPath: "/api/:version/groups.json"
groupPath: "/api/:version/groups/:id.json"
namespacesPath: "/api/:version/namespaces.json"
groupProjectsPath: "/api/:version/groups/:id/projects.json"
projectsPath: "/api/:version/projects.json"
labelsPath: "/api/:version/projects/:id/labels"
licensePath: "/api/:version/licenses/:key"
gitignorePath: "/api/:version/gitignores/:key"
group: (group_id, callback) ->
url = Api.buildUrl(Api.group_path)
url = Api.buildUrl(Api.groupPath)
url = url.replace(':id', group_id)
$.ajax(
@ -22,7 +23,7 @@
# Return groups list. Filtered by query
# Only active groups retrieved
groups: (query, skip_ldap, callback) ->
url = Api.buildUrl(Api.groups_path)
url = Api.buildUrl(Api.groupsPath)
$.ajax(
url: url
@ -36,7 +37,7 @@
# Return namespaces list. Filtered by query
namespaces: (query, callback) ->
url = Api.buildUrl(Api.namespaces_path)
url = Api.buildUrl(Api.namespacesPath)
$.ajax(
url: url
@ -50,7 +51,7 @@
# Return projects list. Filtered by query
projects: (query, order, callback) ->
url = Api.buildUrl(Api.projects_path)
url = Api.buildUrl(Api.projectsPath)
$.ajax(
url: url
@ -64,7 +65,7 @@
callback(projects)
newLabel: (project_id, data, callback) ->
url = Api.buildUrl(Api.labels_path)
url = Api.buildUrl(Api.labelsPath)
url = url.replace(':id', project_id)
data.private_token = gon.api_token
@ -80,7 +81,7 @@
# Return group projects list. Filtered by query
groupProjects: (group_id, query, callback) ->
url = Api.buildUrl(Api.group_projects_path)
url = Api.buildUrl(Api.groupProjectsPath)
url = url.replace(':id', group_id)
$.ajax(
@ -95,7 +96,7 @@
# Return text for a specific license
licenseText: (key, data, callback) ->
url = Api.buildUrl(Api.license_path).replace(':key', key)
url = Api.buildUrl(Api.licensePath).replace(':key', key)
$.ajax(
url: url
@ -103,6 +104,12 @@
).done (license) ->
callback(license)
gitignoreText: (key, callback) ->
url = Api.buildUrl(Api.gitignorePath).replace(':key', key)
$.get url, (gitignore) ->
callback(gitignore)
buildUrl: (url) ->
url = gon.relative_url_root + url if gon.relative_url_root?
return url.replace(':version', gon.api_version)

View File

@ -0,0 +1,58 @@
class @BlobGitignoreSelector
constructor: (opts) ->
{
@dropdown
@editor
@$wrapper = @dropdown.closest('.gitignore-selector')
@$filenameInput = $('#file_name')
@data = @dropdown.data('filenames')
} = opts
@dropdown.glDropdown(
data: @data,
filterable: true,
selectable: true,
search:
fields: ['name']
clicked: @onClick
text: (gitignore) ->
gitignore.name
)
@toggleGitignoreSelector()
@bindEvents()
bindEvents: ->
@$filenameInput
.on 'keyup blur', (e) =>
@toggleGitignoreSelector()
toggleGitignoreSelector: ->
filename = @$filenameInput.val() or $('.editor-file-name').text().trim()
@$wrapper.toggleClass 'hidden', filename isnt '.gitignore'
onClick: (item, el, e) =>
e.preventDefault()
@requestIgnoreFile(item.name)
requestIgnoreFile: (name) ->
Api.gitignoreText name, @requestIgnoreFileSuccess.bind(@)
requestIgnoreFileSuccess: (gitignore) ->
@editor.setValue(gitignore.content, 1)
@editor.focus()
class @BlobGitignoreSelectors
constructor: (opts) ->
{
@$dropdowns = $('.js-gitignore-selector')
@editor
} = opts
@$dropdowns.each (i, dropdown) =>
$dropdown = $(dropdown)
new BlobGitignoreSelector(
dropdown: $dropdown,
editor: @editor
)

View File

@ -13,6 +13,7 @@ class @EditBlob
@initModePanesAndLinks()
new BlobLicenseSelector(@editor)
new BlobGitignoreSelectors(editor: @editor)
initModePanesAndLinks: ->
@$editModePanes = $(".js-edit-mode-pane")

View File

@ -1,9 +1,12 @@
class CiBuild
@interval: null
@state: null
constructor: (build_url, build_status) ->
constructor: (build_url, build_status, build_state) ->
clearInterval(CiBuild.interval)
@state = build_state
@initScrollButtonAffix()
if build_status == "running" || build_status == "pending"
@ -26,14 +29,18 @@ class CiBuild
CiBuild.interval = setInterval =>
if window.location.href.split("#").first() is build_url
$.ajax
url: build_url
url: build_url + "/trace.json?state=" + encodeURIComponent(@state)
dataType: "json"
success: (build) =>
if build.status == "running"
$('#build-trace code').html build.trace_html
$('#build-trace code').append '<i class="fa fa-refresh fa-spin"/>'
success: (log) =>
@state = log.state
if log.status is "running"
if log.append
$('.fa-refresh').before log.html
else
$('#build-trace code').html log.html
$('#build-trace code').append '<i class="fa fa-refresh fa-spin"/>'
@checkAutoscroll()
else if build.status != build_status
else if log.status isnt build_status
Turbolinks.visit build_url
, 4000

View File

@ -11,6 +11,7 @@ class @DueDateSelect
$block = $dropdown.closest('.block')
$selectbox = $dropdown.closest('.selectbox')
$value = $block.find('.value')
$valueContent = $block.find('.value-content')
$sidebarValue = $('.js-due-date-sidebar-value', $block)
fieldName = $dropdown.data('field-name')
@ -23,11 +24,15 @@ class @DueDateSelect
$value.removeAttr('style')
)
addDueDate = ->
addDueDate = (isDropdown) ->
# Create the post date
value = $("input[name='#{fieldName}']").val()
date = new Date value.replace(new RegExp('-', 'g'), ',')
mediumDate = $.datepicker.formatDate 'M d, yy', date
if value isnt ''
date = new Date value.replace(new RegExp('-', 'g'), ',')
mediumDate = $.datepicker.formatDate 'M d, yy', date
else
mediumDate = 'None'
data = {}
data[abilityName] = {}
@ -39,23 +44,35 @@ class @DueDateSelect
data: data
beforeSend: ->
$loading.fadeIn()
$dropdown.trigger('loading.gl.dropdown')
$selectbox.hide()
if isDropdown
$dropdown.trigger('loading.gl.dropdown')
$selectbox.hide()
$value.removeAttr('style')
$value.html(mediumDate)
$valueContent.html(mediumDate)
$sidebarValue.html(mediumDate)
if value isnt ''
$('.js-remove-due-date-holder').removeClass 'hidden'
else
$('.js-remove-due-date-holder').addClass 'hidden'
).done (data) ->
$dropdown.trigger('loaded.gl.dropdown')
$dropdown.dropdown('toggle')
if isDropdown
$dropdown.trigger('loaded.gl.dropdown')
$dropdown.dropdown('toggle')
$loading.fadeOut()
$block.on 'click', '.js-remove-due-date', (e) ->
e.preventDefault()
$("input[name='#{fieldName}']").val ''
addDueDate(false)
$datePicker.datepicker(
dateFormat: 'yy-mm-dd',
defaultDate: $("input[name='#{fieldName}']").val()
altField: "input[name='#{fieldName}']"
onSelect: ->
addDueDate()
addDueDate(true)
)
$(document)

View File

@ -18,6 +18,10 @@ GitLab.GfmAutoComplete =
Issues:
template: '<li><small>${id}</small> ${title}</li>'
# Milestones
Milestones:
template: '<li>${title}</li>'
# Add GFM auto-completion to all input fields, that accept GFM input.
setup: (wrap) ->
@input = $('.js-gfm-input')
@ -81,6 +85,19 @@ GitLab.GfmAutoComplete =
title: sanitize(i.title)
search: "#{i.iid} #{i.title}"
@input.atwho
at: '%'
alias: 'milestones'
searchKey: 'search'
displayTpl: @Milestones.template
insertTpl: '${atwho-at}"${title}"'
callbacks:
beforeSave: (milestones) ->
$.map milestones, (m) ->
id: m.iid
title: sanitize(m.title)
search: "#{m.title}"
@input.atwho
at: '!'
alias: 'mergerequests'
@ -105,6 +122,8 @@ GitLab.GfmAutoComplete =
@input.atwho 'load', '@', data.members
# load issues
@input.atwho 'load', 'issues', data.issues
# load milestones
@input.atwho 'load', 'milestones', data.milestones
# load merge requests
@input.atwho 'load', 'mergerequests', data.mergerequests
# load emojis

View File

@ -60,9 +60,36 @@ class GitLabDropdownFilter
results = data
if search_text isnt ''
results = fuzzaldrinPlus.filter(data, search_text,
key: @options.keys
)
# When data is an array of objects therefore [object Array] e.g.
# [
# { prop: 'foo' },
# { prop: 'baz' }
# ]
if _.isArray(data)
results = fuzzaldrinPlus.filter(data, search_text,
key: @options.keys
)
else
# If data is grouped therefore an [object Object]. e.g.
# {
# groupName1: [
# { prop: 'foo' },
# { prop: 'baz' }
# ],
# groupName2: [
# { prop: 'abc' },
# { prop: 'def' }
# ]
# }
if gl.utils.isObject data
results = {}
for key, group of data
tmp = fuzzaldrinPlus.filter(group, search_text,
key: @options.keys
)
if tmp.length
results[key] = tmp.map (item) -> item
@options.callback results
else
@ -141,8 +168,9 @@ class GitLabDropdown
searchFields = if @options.search then @options.search.fields else [];
if @options.data
# If data is an array
if _.isArray @options.data
# If we provided data
# data could be an array of objects or a group of arrays
if _.isObject(@options.data) and not _.isFunction(@options.data)
@fullData = @options.data
@parseData @options.data
else
@ -230,19 +258,33 @@ class GitLabDropdown
parseData: (data) ->
@renderedData = data
# Render each row
html = $.map data, (obj) =>
return @renderItem(obj)
if @options.filterable and data.length is 0
# render no matching results
html = [@noResults()]
else
# Handle array groups
if gl.utils.isObject data
html = []
for name, groupData of data
# Add header for each group
html.push(@renderItem(header: name, name))
@renderData(groupData, name)
.map (item) ->
html.push item
else
# Render each row
html = @renderData(data)
# Render the full menu
full_html = @renderMenu(html.join(""))
@appendMenu(full_html)
renderData: (data, group = false) ->
data.map (obj, index) =>
return @renderItem(obj, group, index)
shouldPropagate: (e) =>
if @options.multiSelect
$target = $(e.target)
@ -299,11 +341,10 @@ class GitLabDropdown
selector = '.dropdown-content'
if @dropdown.find(".dropdown-toggle-page").length
selector = ".dropdown-page-one .dropdown-content"
$(selector, @dropdown).html html
# Render the row
renderItem: (data) ->
renderItem: (data, group = false, index = false) ->
html = ""
# Divider
@ -346,8 +387,13 @@ class GitLabDropdown
if @highlight
text = @highlightTextMatches(text, @filterInput.val())
if group
groupAttrs = "data-group='#{group}' data-index='#{index}'"
else
groupAttrs = ''
html = "<li>
<a href='#{url}' class='#{cssClass}'>
<a href='#{url}' #{groupAttrs} class='#{cssClass}'>
#{text}
</a>
</li>"
@ -377,9 +423,15 @@ class GitLabDropdown
rowClicked: (el) ->
fieldName = @options.fieldName
selectedIndex = el.parent().index()
if @renderedData
selectedObject = @renderedData[selectedIndex]
groupName = el.data('group')
if groupName
selectedIndex = el.data('index')
selectedObject = @renderedData[groupName][selectedIndex]
else
selectedIndex = el.closest('li').index()
selectedObject = @renderedData[selectedIndex]
value = if @options.id then @options.id(selectedObject, el) else selectedObject.id
field = @dropdown.parent().find("input[name='#{fieldName}'][value='#{value}']")
if el.hasClass(ACTIVE_CLASS)
@ -460,7 +512,7 @@ class GitLabDropdown
return false
if currentKeyCode is 13
@selectRowAtIndex currentIndex
@selectRowAtIndex if currentIndex < 0 then 0 else currentIndex
removeArrayKeyEvent: ->
$('body').off 'keydown'

View File

@ -20,6 +20,15 @@ class @IssuableForm
@initWip()
$issuableDueDate = $('#issuable-due-date')
if $issuableDueDate.length
$('.datepicker').datepicker(
dateFormat: 'yy-mm-dd',
onSelect: (dateText, inst) ->
$issuableDueDate.val dateText
).datepicker 'setDate', $.datepicker.parseDate('yy-mm-dd', $issuableDueDate.val())
initAutosave: ->
new Autosave @titleField, [
document.location.pathname,

View File

@ -0,0 +1,9 @@
((w) ->
w.gl ?= {}
w.gl.utils ?= {}
w.gl.utils.isObject = (obj) ->
obj? and (obj.constructor is Object)
) window

View File

@ -113,7 +113,7 @@ class @MergeRequestWidget
switch state
when "failed", "canceled", "not_found"
@setMergeButtonClass('btn-danger')
when "running", "pending"
when "running"
@setMergeButtonClass('btn-warning')
when "success"
@setMergeButtonClass('btn-create')
@ -126,6 +126,6 @@ class @MergeRequestWidget
$('.ci_widget:visible .ci-coverage').text(text)
setMergeButtonClass: (css_class) ->
$('.accept_merge_request')
$('.js-merge-button')
.removeClass('btn-danger btn-warning btn-create')
.addClass(css_class)

View File

@ -285,6 +285,7 @@ class @Notes
form.addClass "js-main-target-form"
form.find("#note_line_code").remove()
form.find("#note_type").remove()
###
General note form setup.
@ -472,6 +473,7 @@ class @Notes
setupDiscussionNoteForm: (dataHolder, form) =>
# setup note target
form.attr 'id', "new-discussion-note-form-#{dataHolder.data("discussionId")}"
form.find("#note_type").val dataHolder.data("noteType")
form.find("#line_type").val dataHolder.data("lineType")
form.find("#note_commit_id").val dataHolder.data("commitId")
form.find("#note_line_code").val dataHolder.data("lineCode")

View File

@ -26,6 +26,10 @@
# Personal projects
# </a>
# </li>
# <li class="snippets-tab">
# <a data-action="snippets" data-target="#snippets" data-toggle="tab" href="/u/username/snippets">
# </a>
# </li>
# </ul>
#
# <div class="tab-content">
@ -41,6 +45,9 @@
# <div class="tab-pane" id="projects">
# Projects content
# </div>
# <div class="tab-pane" id="snippets">
# Snippets content
# </div>
# </div>
#
# <div class="loading-status">
@ -100,7 +107,7 @@ class @UserTabs
if action is 'activity'
@loadActivities(source)
if action in ['groups', 'contributed', 'projects']
if action in ['groups', 'contributed', 'projects', 'snippets']
@loadTab(source, action)
loadTab: (source, action) ->

View File

@ -10,7 +10,6 @@
*= require dropzone/basic
*= require cal-heatmap
*= require cropper.css
*= require animate
*/
/*

View File

@ -5,6 +5,7 @@
@import 'framework/tw_bootstrap';
@import "framework/layout";
@import "framework/animations.scss";
@import "framework/avatar.scss";
@import "framework/blocks.scss";
@import "framework/buttons.scss";

View File

@ -0,0 +1,72 @@
// This file is based off animate.css 3.5.1, available here:
// https://github.com/daneden/animate.css/blob/3.5.1/animate.css
//
// animate.css - http://daneden.me/animate
// Version - 3.5.1
// Licensed under the MIT license - http://opensource.org/licenses/MIT
//
// Copyright (c) 2016 Daniel Eden
.animated {
-webkit-animation-duration: 1s;
animation-duration: 1s;
-webkit-animation-fill-mode: both;
animation-fill-mode: both;
}
.animated.infinite {
-webkit-animation-iteration-count: infinite;
animation-iteration-count: infinite;
}
.animated.hinge {
-webkit-animation-duration: 2s;
animation-duration: 2s;
}
.animated.flipOutX,
.animated.flipOutY,
.animated.bounceIn,
.animated.bounceOut {
-webkit-animation-duration: .75s;
animation-duration: .75s;
}
@-webkit-keyframes pulse {
from {
-webkit-transform: scale3d(1, 1, 1);
transform: scale3d(1, 1, 1);
}
50% {
-webkit-transform: scale3d(1.05, 1.05, 1.05);
transform: scale3d(1.05, 1.05, 1.05);
}
to {
-webkit-transform: scale3d(1, 1, 1);
transform: scale3d(1, 1, 1);
}
}
@keyframes pulse {
from {
-webkit-transform: scale3d(1, 1, 1);
transform: scale3d(1, 1, 1);
}
50% {
-webkit-transform: scale3d(1.05, 1.05, 1.05);
transform: scale3d(1.05, 1.05, 1.05);
}
to {
-webkit-transform: scale3d(1, 1, 1);
transform: scale3d(1, 1, 1);
}
}
.pulse {
-webkit-animation-name: pulse;
animation-name: pulse;
}

View File

@ -289,7 +289,7 @@ table {
text-shadow: none;
@media (min-width: $screen-sm-min) {
margin-top: 11px;
margin-top: 8px;
}
}

View File

@ -36,22 +36,6 @@
}
}
.filename {
&.old {
display: inline-block;
span.idiff {
background-color: #f8cbcb;
}
}
&.new {
display: inline-block;
span.idiff {
background-color: #a6f3a6;
}
}
}
a:not(.btn) {
color: $gl-dark-link-color;
}

View File

@ -28,10 +28,6 @@ input[type='text'].danger {
}
label {
&.control-label {
@extend .col-sm-2;
}
&.inline-label {
margin: 0;
}
@ -41,6 +37,10 @@ label {
}
}
.control-label {
@extend .col-sm-2;
}
.inline-input-group {
width: 250px;
}

View File

@ -9,8 +9,7 @@
@mixin gitlab-theme($color-light, $color, $color-darker, $color-dark) {
.page-with-sidebar {
.header-logo {
background-color: $color;
border-color: $color;
background: $color-darker;
a {
color: $color-light;
@ -21,7 +20,7 @@
}
&:hover {
background-color: $color-darker;
background-color: $color-dark;
a {
color: #fff;
@ -91,8 +90,8 @@
}
$theme-blue: #2980b9;
$theme-charcoal: #333c47;
$theme-graphite: #888;
$theme-charcoal: #3d454d;
$theme-graphite: #666;
$theme-gray: #373737;
$theme-green: #019875;
$theme-violet: #548;
@ -103,11 +102,11 @@ body {
}
&.ui_charcoal {
@include gitlab-theme(#c5d0de, $theme-charcoal, #2b333d, #24272d);
@include gitlab-theme(#d6d7d9, #485157, $theme-charcoal, #353b41);
}
&.ui_graphite {
@include gitlab-theme(#ccc, $theme-graphite, #777, #666);
@include gitlab-theme(#ccc, #777, $theme-graphite, #555);
}
&.ui_gray {

View File

@ -6,12 +6,12 @@ header {
transition-duration: .3s;
&.navbar-empty {
height: 58px;
height: $header-height;
background: #fff;
border-bottom: 1px solid $btn-gray-hover;
.center-logo {
margin: 11px 0;
margin: 8px 0;
text-align: center;
#tanuki-logo, img {

View File

@ -209,6 +209,15 @@
float: right;
padding: 7px 0 0;
@media (max-width: $screen-xs-min) {
float: none;
padding: 0 9px;
.dropdown-new {
width: 100%;
}
}
i {
color: $layout-link-gray;
}
@ -225,6 +234,10 @@
.dropdown {
margin-left: 7px;
@media (max-width: $screen-xs-min) {
margin-left: 0;
}
}
}
@ -260,4 +273,10 @@
.page-with-layout-nav {
margin-top: 50px;
&.controls-dropdown-visible {
@media (max-width: $screen-xs-min) {
margin-top: 96px;
}
}
}

View File

@ -312,7 +312,7 @@
}
.nav-sidebar li a {
width: 230px;
width: $sidebar_width;
&.back-link {
i {

View File

@ -269,3 +269,11 @@ h1, h2, h3, h4 {
text-align: right;
}
}
.idiff.deletion {
background: $line-removed-dark;
}
.idiff.addition {
background: $line-added-dark;
}

View File

@ -2,7 +2,7 @@
* Layout
*/
$sidebar_collapsed_width: 62px;
$sidebar_width: 230px;
$sidebar_width: 220px;
$gutter_collapsed_width: 62px;
$gutter_width: 290px;
$gutter_inner_width: 258px;
@ -12,7 +12,7 @@ $gutter_inner_width: 258px;
*/
$border-color: #e5e5e5;
$focus-border-color: #3aabf0;
$table-border-color: #ececec;
$table-border-color: #f0f0f0;
$background-color: #fafafa;
/*
@ -178,6 +178,7 @@ $table-border-gray: #f0f0f0;
$line-target-blue: #eaf3fc;
$line-select-yellow: #fcf8e7;
$line-select-yellow-dark: #f0e2bd;
/*
* Fonts
*/

View File

@ -32,7 +32,7 @@
}
}
.zen-cotrol {
.zen-control {
padding: 0;
color: #555;
background: none;

View File

@ -0,0 +1,43 @@
@import "framework/variables";
table.code {
width: 100%;
font-family: monospace;
border: none;
border-collapse: separate;
margin: 0;
padding: 0;
-premailer-cellpadding: 0;
-premailer-cellspacing: 0;
-premailer-width: 100%;
td {
line-height: $code_line_height;
font-family: monospace;
font-size: $code_font_size;
}
td.diff-line-num {
margin: 0;
padding: 0;
border: none;
background: $background-color;
color: rgba(0, 0, 0, 0.3);
padding: 0 5px;
border-right: 1px solid $border-color;
text-align: right;
min-width: 35px;
max-width: 50px;
width: 35px;
}
td.line_content {
display: block;
margin: 0;
padding: 0 0.5em;
border: none;
white-space: pre;
}
}
@import "highlight/white";

View File

@ -23,7 +23,7 @@
.file-title {
@extend .monospace;
line-height: 42px;
line-height: 35px;
padding-top: 7px;
padding-bottom: 7px;
@ -43,7 +43,7 @@
.editor-file-name {
@extend .monospace;
float: left;
margin-right: 10px;
}
@ -59,7 +59,22 @@
}
.encoding-selector,
.license-selector {
.license-selector,
.gitignore-selector {
display: inline-block;
vertical-align: top;
font-family: $regular_font;
}
.gitignore-selector {
.dropdown {
line-height: 21px;
}
.dropdown-menu-toggle {
vertical-align: top;
width: 220px;
}
}
}

View File

@ -125,7 +125,7 @@
.right-sidebar {
position: fixed;
top: 50px;
top: $header-height;
bottom: 0;
right: 0;
z-index: 10;
@ -150,6 +150,10 @@
font-weight: 600;
}
.light {
font-weight: normal;
}
.sidebar-collapsed-icon {
display: none;
}

View File

@ -226,8 +226,7 @@ ul.notes {
}
}
.note-action-button,
.discussion-action-button {
.note-action-button {
display: inline-block;
margin-left: 10px;
line-height: 24px;

View File

@ -0,0 +1,4 @@
.pipeline-stage {
overflow: hidden;
text-overflow: ellipsis;
}

View File

@ -7,7 +7,7 @@
}
.no-ssh-key-message, .project-limit-message {
background-color: #f28d35;
margin-bottom: 16px;
margin-bottom: 0;
}
.new_project,
.edit_project {
@ -149,6 +149,10 @@
white-space: nowrap;
margin: 0 11px 0 4px;
a {
color: inherit;
}
&:hover {
background: #fff;
}
@ -161,7 +165,7 @@
display: inline-table;
margin-right: 12px;
a {
> a {
margin: -1px;
}
}

View File

@ -9,6 +9,6 @@ class Admin::AbuseReportsController < Admin::ApplicationController
abuse_report.remove_user(deleted_by: current_user) if params[:remove_user]
abuse_report.destroy
render nothing: true
head :ok
end
end

View File

@ -19,6 +19,12 @@ class Admin::ApplicationSettingsController < Admin::ApplicationController
redirect_to admin_runners_path
end
def reset_health_check_token
@application_setting.reset_health_check_access_token!
flash[:notice] = 'New health check access token has been generated!'
redirect_to :back
end
def clear_repository_check_states
RepositoryCheck::ClearWorker.perform_async
@ -53,6 +59,12 @@ class Admin::ApplicationSettingsController < Admin::ApplicationController
end
end
enabled_oauth_sign_in_sources = params[:application_setting].delete(:enabled_oauth_sign_in_sources)
params[:application_setting][:disabled_oauth_sign_in_sources] =
AuthHelper.button_based_providers.map(&:to_s) -
Array(enabled_oauth_sign_in_sources)
params.require(:application_setting).permit(
:default_projects_limit,
:default_branch_protection,
@ -94,8 +106,10 @@ class Admin::ApplicationSettingsController < Admin::ApplicationController
:email_author_in_body,
:repository_checks_enabled,
:metrics_packet_size,
:send_user_confirmation_email,
restricted_visibility_levels: [],
import_sources: []
import_sources: [],
disabled_oauth_sign_in_sources: []
)
end
end

View File

@ -32,7 +32,7 @@ class Admin::BroadcastMessagesController < Admin::ApplicationController
respond_to do |format|
format.html { redirect_back_or_default(default: { action: 'index' }) }
format.js { render nothing: true }
format.js { head :ok }
end
end

View File

@ -0,0 +1,5 @@
class Admin::HealthCheckController < Admin::ApplicationController
def show
@errors = HealthCheck::Utils.process_checks('standard')
end
end

View File

@ -6,7 +6,7 @@ class Admin::KeysController < Admin::ApplicationController
respond_to do |format|
format.html
format.js { render nothing: true }
format.js { head :ok }
end
end

View File

@ -9,23 +9,18 @@ class Admin::RunnersController < Admin::ApplicationController
end
def show
@builds = @runner.builds.order('id DESC').first(30)
@projects =
if params[:search].present?
::Project.search(params[:search])
else
Project.all
end
@projects = @projects.where.not(id: @runner.projects.select(:id)) if @runner.projects.any?
@projects = @projects.page(params[:page]).per(30)
assign_builds_and_projects
end
def update
@runner.update_attributes(runner_params)
respond_to do |format|
format.js
format.html { redirect_to admin_runner_path(@runner) }
if @runner.update_attributes(runner_params)
respond_to do |format|
format.js
format.html { redirect_to admin_runner_path(@runner) }
end
else
assign_builds_and_projects
render 'show'
end
end
@ -58,6 +53,18 @@ class Admin::RunnersController < Admin::ApplicationController
end
def runner_params
params.require(:runner).permit(:token, :description, :tag_list, :active)
params.require(:runner).permit(Ci::Runner::FORM_EDITABLE)
end
def assign_builds_and_projects
@builds = runner.builds.order('id DESC').first(30)
@projects =
if params[:search].present?
::Project.search(params[:search])
else
Project.all
end
@projects = @projects.where.not(id: runner.projects.select(:id)) if runner.projects.any?
@projects = @projects.page(params[:page]).per(30)
end
end

View File

@ -11,7 +11,7 @@ class Admin::SpamLogsController < Admin::ApplicationController
redirect_to admin_spam_logs_path, notice: "User #{spam_log.user.username} was successfully removed."
else
spam_log.destroy
render nothing: true
head :ok
end
end
end

View File

@ -119,6 +119,7 @@ class Admin::UsersController < Admin::ApplicationController
user_params_with_pass.merge!(
password: params[:user][:password],
password_confirmation: params[:user][:password_confirmation],
password_expires_at: Time.now
)
end
@ -153,7 +154,7 @@ class Admin::UsersController < Admin::ApplicationController
respond_to do |format|
format.html { redirect_back_or_admin_user(notice: "Successfully removed email.") }
format.js { render nothing: true }
format.js { head :ok }
end
end

View File

@ -176,7 +176,7 @@ class ApplicationController < ActionController::Base
end
def check_password_expiration
if current_user && current_user.password_expires_at && current_user.password_expires_at < Time.now && !current_user.ldap_user?
if current_user && current_user.password_expires_at && current_user.password_expires_at < Time.now && !current_user.ldap_user?
redirect_to new_profile_password_path and return
end
end

View File

@ -122,7 +122,7 @@ module CreatesCommit
# Merge request from fork to this project
@mr_source_project = @tree_edit_project
@mr_target_project = @project
@mr_target_branch ||= @ref
@mr_target_branch ||= @ref
end
end
end

View File

@ -6,7 +6,7 @@ module ToggleSubscriptionAction
subscribable_resource.toggle_subscription(current_user)
render nothing: true
head :ok
end
private

View File

@ -28,7 +28,7 @@ class Dashboard::ProjectsController < Dashboard::ApplicationController
end
def starred
@projects = current_user.starred_projects.sorted_by_activity
@projects = current_user.viewable_starred_projects.sorted_by_activity
@projects = filter_projects(@projects)
@projects = @projects.includes(:namespace, :forked_from_project, :tags)
@projects = @projects.sort(@sort = params[:sort])

View File

@ -12,7 +12,7 @@ class Dashboard::TodosController < Dashboard::ApplicationController
respond_to do |format|
format.html { redirect_to dashboard_todos_path, notice: todo_notice }
format.js { render nothing: true }
format.js { head :ok }
format.json do
render json: { count: @todos.size, done_count: current_user.todos.done.count }
end
@ -24,7 +24,7 @@ class Dashboard::TodosController < Dashboard::ApplicationController
respond_to do |format|
format.html { redirect_to dashboard_todos_path, notice: 'All todos were marked as done.' }
format.js { render nothing: true }
format.js { head :ok }
format.json do
find_todos
render json: { count: @todos.size, done_count: current_user.todos.done.count }

View File

@ -25,7 +25,7 @@ class DashboardController < Dashboard::ApplicationController
def load_events
projects =
if params[:filter] == "starred"
current_user.starred_projects
current_user.viewable_starred_projects
else
current_user.authorized_projects
end

View File

@ -40,7 +40,7 @@ class Groups::GroupMembersController < Groups::ApplicationController
respond_to do |format|
format.html { redirect_to group_group_members_path(@group), notice: 'User was successfully removed from group.' }
format.js { render nothing: true }
format.js { head :ok }
end
end

View File

@ -0,0 +1,22 @@
class HealthCheckController < HealthCheck::HealthCheckController
before_action :validate_health_check_access!
private
def validate_health_check_access!
render_404 unless token_valid?
end
def token_valid?
token = params[:token].presence || request.headers['TOKEN']
token.present? &&
ActiveSupport::SecurityUtils.variable_size_secure_compare(
token,
current_application_settings.health_check_access_token
)
end
def render_404
render file: Rails.root.join('public', '404'), layout: false, status: '404'
end
end

View File

@ -0,0 +1,87 @@
class JwtController < ApplicationController
skip_before_action :authenticate_user!
skip_before_action :verify_authenticity_token
before_action :authenticate_project_or_user
SERVICES = {
Auth::ContainerRegistryAuthenticationService::AUDIENCE => Auth::ContainerRegistryAuthenticationService,
}
def auth
service = SERVICES[params[:service]]
return head :not_found unless service
result = service.new(@project, @user, auth_params).execute
render json: result, status: result[:http_status]
end
private
def authenticate_project_or_user
authenticate_with_http_basic do |login, password|
# if it's possible we first try to authenticate project with login and password
@project = authenticate_project(login, password)
return if @project
@user = authenticate_user(login, password)
return if @user
render_403
end
end
def auth_params
params.permit(:service, :scope, :offline_token, :account, :client_id)
end
def authenticate_project(login, password)
if login == 'gitlab-ci-token'
Project.find_by(builds_enabled: true, runners_token: password)
end
end
def authenticate_user(login, password)
# TODO: this is a copy and paste from grack_auth,
# it should be refactored in the future
user = Gitlab::Auth.new.find(login, password)
# If the user authenticated successfully, we reset the auth failure count
# from Rack::Attack for that IP. A client may attempt to authenticate
# with a username and blank password first, and only after it receives
# a 401 error does it present a password. Resetting the count prevents
# false positives from occurring.
#
# Otherwise, we let Rack::Attack know there was a failed authentication
# attempt from this IP. This information is stored in the Rails cache
# (Redis) and will be used by the Rack::Attack middleware to decide
# whether to block requests from this IP.
config = Gitlab.config.rack_attack.git_basic_auth
if config.enabled
if user
# A successful login will reset the auth failure count from this IP
Rack::Attack::Allow2Ban.reset(request.ip, config)
else
banned = Rack::Attack::Allow2Ban.filter(request.ip, config) do
# Unless the IP is whitelisted, return true so that Allow2Ban
# increments the counter (stored in Rails.cache) for the IP
if config.ip_whitelist.include?(request.ip)
false
else
true
end
end
if banned
Rails.logger.info "IP #{request.ip} failed to login " \
"as #{login} but has been temporarily banned from Git auth"
return
end
end
end
user
end
end

View File

@ -24,7 +24,7 @@ class Profiles::EmailsController < Profiles::ApplicationController
respond_to do |format|
format.html { redirect_to profile_emails_url }
format.js { render nothing: true }
format.js { head :ok }
end
end

View File

@ -32,7 +32,7 @@ class Profiles::KeysController < Profiles::ApplicationController
respond_to do |format|
format.html { redirect_to profile_keys_url }
format.js { render nothing: true }
format.js { head :ok }
end
end

View File

@ -38,6 +38,14 @@ class Projects::BuildsController < Projects::ApplicationController
end
end
def trace
respond_to do |format|
format.json do
render json: @build.trace_with_state(params[:state]).merge!(id: @build.id, status: @build.status)
end
end
end
def retry
unless @build.retryable?
return render_404

View File

@ -17,12 +17,12 @@ class Projects::CommitController < Projects::ApplicationController
def show
apply_diff_view_cookie!
@line_notes = commit.notes.inline
@grouped_diff_notes = commit.notes.grouped_diff_notes
@note = @project.build_commit_note(commit)
@notes = commit.notes.not_inline.fresh
@notes = commit.notes.non_diff_notes.fresh
@noteable = @commit
@comments_allowed = @reply_allowed = true
@comments_target = {
@comments_target = {
noteable_type: 'Commit',
commit_id: @commit.id
}
@ -67,10 +67,10 @@ class Projects::CommitController < Projects::ApplicationController
create_commit(Commits::RevertService, success_notice: "The #{@commit.change_type_title} has been successfully reverted.",
success_path: successful_change_path, failure_path: failed_change_path)
end
def cherry_pick
assign_change_commit_vars(@commit.cherry_pick_branch_name)
return render_404 if @target_branch.blank?
create_commit(Commits::CherryPickService, success_notice: "The #{@commit.change_type_title} has been successfully cherry-picked.",

View File

@ -22,7 +22,8 @@ class Projects::CompareController < Projects::ApplicationController
@base_commit = @project.merge_base_commit(@base_ref, @head_ref)
@diffs = compare.diffs(diff_options)
@diff_refs = [@base_commit, @commit]
@line_notes = []
@diff_notes_disabled = true
@grouped_diff_notes = {}
end
end

View File

@ -0,0 +1,34 @@
class Projects::ContainerRegistryController < Projects::ApplicationController
before_action :verify_registry_enabled
before_action :authorize_read_container_image!
before_action :authorize_update_container_image!, only: [:destroy]
layout 'project'
def index
@tags = container_registry_repository.tags
end
def destroy
url = namespace_project_container_registry_index_path(project.namespace, project)
if tag.delete
redirect_to url
else
redirect_to url, alert: 'Failed to remove tag'
end
end
private
def verify_registry_enabled
render_404 unless Gitlab.config.registry.enabled
end
def container_registry_repository
@container_registry_repository ||= project.container_registry_repository
end
def tag
@tag ||= container_registry_repository.tag(params[:id])
end
end

View File

@ -27,8 +27,10 @@ class Projects::HooksController < Projects::ApplicationController
if !@project.empty_repo?
status, message = TestHookService.new.execute(hook, current_user)
if status
flash[:notice] = 'Hook successfully executed.'
if status && status >= 200 && status < 400
flash[:notice] = "Hook executed successfully: HTTP #{status}"
elsif status
flash[:alert] = "Hook executed successfully but returned HTTP #{status} #{message}"
else
flash[:alert] = "Hook execution failed: #{message}"
end

View File

@ -20,6 +20,7 @@ class Projects::ImportsController < Projects::ApplicationController
@project.import_retry
else
@project.import_start
@project.add_import_job
end
end

View File

@ -73,12 +73,12 @@ class Projects::MergeRequestsController < Projects::ApplicationController
# but we need it for the "View file @ ..." link by deleted files
@base_commit ||= @merge_request.first_commit.parent || @merge_request.first_commit
@comments_allowed = @reply_allowed = true
@comments_target = {
noteable_type: 'MergeRequest',
noteable_id: @merge_request.id
}
@line_notes = @merge_request.notes.where("line_code is not null")
@grouped_diff_notes = @merge_request.notes.grouped_diff_notes
respond_to do |format|
format.html
@ -117,6 +117,7 @@ class Projects::MergeRequestsController < Projects::ApplicationController
@commit = @merge_request.last_commit
@base_commit = @merge_request.diff_base_commit
@diffs = @merge_request.compare.diffs(diff_options) if @merge_request.compare
@diff_notes_disabled = true
@ci_commit = @merge_request.ci_commit
@statuses = @ci_commit.statuses if @ci_commit
@ -300,7 +301,7 @@ class Projects::MergeRequestsController < Projects::ApplicationController
# Build a note object for comment form
@note = @project.notes.new(noteable: @merge_request)
@notes = @merge_request.mr_and_commit_notes.nonawards.inc_author.fresh
@discussions = Note.discussions_from_notes(@notes)
@discussions = @notes.discussions
@noteable = @merge_request
# Get commits from repository
@ -333,7 +334,8 @@ class Projects::MergeRequestsController < Projects::ApplicationController
params.require(:merge_request).permit(
:title, :assignee_id, :source_project_id, :source_branch,
:target_project_id, :target_branch, :milestone_id,
:state_event, :description, :task_num, label_ids: []
:state_event, :description, :task_num, :force_remove_source_branch,
label_ids: []
)
end

View File

@ -75,7 +75,7 @@ class Projects::MilestonesController < Projects::ApplicationController
respond_to do |format|
format.html { redirect_to namespace_project_milestones_path }
format.js { render nothing: true }
format.js { head :ok }
end
end

View File

@ -43,7 +43,7 @@ class Projects::NotesController < Projects::ApplicationController
end
respond_to do |format|
format.js { render nothing: true }
format.js { head :ok }
end
end
@ -52,7 +52,7 @@ class Projects::NotesController < Projects::ApplicationController
note.update_attribute(:attachment, nil)
respond_to do |format|
format.js { render nothing: true }
format.js { head :ok }
end
end
@ -96,7 +96,7 @@ class Projects::NotesController < Projects::ApplicationController
end
def note_to_discussion_html(note)
return unless note.for_diff_line?
return unless note.diff_note?
if params[:view] == 'parallel'
template = "projects/notes/_diff_notes_with_reply_parallel"
@ -120,7 +120,7 @@ class Projects::NotesController < Projects::ApplicationController
end
def note_to_discussion_with_diff_html(note)
return unless note.for_diff_line?
return unless note.diff_note?
render_to_string(
"projects/notes/_discussion",
@ -158,7 +158,7 @@ class Projects::NotesController < Projects::ApplicationController
def note_params
params.require(:note).permit(
:note, :noteable, :noteable_id, :noteable_type, :project_id,
:attachment, :line_code, :commit_id
:attachment, :line_code, :commit_id, :type
)
end

View File

@ -0,0 +1,59 @@
class Projects::PipelinesController < Projects::ApplicationController
before_action :pipeline, except: [:index, :new, :create]
before_action :commit, only: [:show]
before_action :authorize_read_pipeline!
before_action :authorize_create_pipeline!, only: [:new, :create]
before_action :authorize_update_pipeline!, only: [:retry, :cancel]
def index
@scope = params[:scope]
all_pipelines = project.ci_commits
@pipelines_count = all_pipelines.count
@running_or_pending_count = all_pipelines.running_or_pending.count
@pipelines = PipelinesFinder.new(project).execute(all_pipelines, @scope)
@pipelines = @pipelines.order(id: :desc).page(params[:page]).per(30)
end
def new
@pipeline = project.ci_commits.new(ref: @project.default_branch)
end
def create
@pipeline = Ci::CreatePipelineService.new(project, current_user, create_params).execute
unless @pipeline.persisted?
render 'new'
return
end
redirect_to namespace_project_pipeline_path(project.namespace, project, @pipeline)
end
def show
end
def retry
pipeline.retry_failed
redirect_back_or_default default: namespace_project_pipelines_path(project.namespace, project)
end
def cancel
pipeline.cancel_running
redirect_back_or_default default: namespace_project_pipelines_path(project.namespace, project)
end
private
def create_params
params.require(:pipeline).permit(:ref)
end
def pipeline
@pipeline ||= project.ci_commits.find_by!(id: params[:id])
end
def commit
@commit ||= @pipeline.commit_data
end
end

View File

@ -55,7 +55,7 @@ class Projects::ProjectMembersController < Projects::ApplicationController
format.html do
redirect_to namespace_project_project_members_path(@project.namespace, @project)
end
format.js { render nothing: true }
format.js { head :ok }
end
end
@ -81,7 +81,7 @@ class Projects::ProjectMembersController < Projects::ApplicationController
respond_to do |format|
format.html { redirect_to dashboard_projects_path, notice: "You left the project." }
format.js { render nothing: true }
format.js { head :ok }
end
else
if current_user == @project.owner

View File

@ -39,7 +39,7 @@ class Projects::ProtectedBranchesController < Projects::ApplicationController
respond_to do |format|
format.html { redirect_to namespace_project_protected_branches_path }
format.js { render nothing: true }
format.js { head :ok }
end
end

View File

@ -20,7 +20,7 @@ class Projects::RunnersController < Projects::ApplicationController
if @runner.update_attributes(runner_params)
redirect_to runner_path(@runner), notice: 'Runner was successfully updated.'
else
redirect_to runner_path(@runner), alert: 'Runner was not updated.'
render 'edit'
end
end
@ -64,6 +64,6 @@ class Projects::RunnersController < Projects::ApplicationController
end
def runner_params
params.require(:runner).permit(:description, :tag_list, :active)
params.require(:runner).permit(Ci::Runner::FORM_EDITABLE)
end
end

View File

@ -3,20 +3,44 @@ class Projects::VariablesController < Projects::ApplicationController
layout 'project_settings'
def index
@variable = Ci::Variable.new
end
def show
@variable = @project.variables.find(params[:id])
end
def update
if project.update_attributes(project_params)
@variable = @project.variables.find(params[:id])
if @variable.update_attributes(project_params)
redirect_to namespace_project_variables_path(project.namespace, project), notice: 'Variable was successfully updated.'
else
render action: "show"
end
end
def create
@variable = Ci::Variable.new(project_params)
if @variable.valid? && @project.variables << @variable
redirect_to namespace_project_variables_path(project.namespace, project), notice: 'Variables were successfully updated.'
else
render action: 'show'
render action: "index"
end
end
def destroy
@key = @project.variables.find(params[:id])
@key.destroy
redirect_to namespace_project_variables_path(project.namespace, project), notice: 'Variable was successfully removed.'
end
private
def project_params
params.require(:project).permit({ variables_attributes: [:id, :key, :value, :_destroy] })
params.require(:variable).permit([:id, :key, :value, :_destroy])
end
end

View File

@ -101,13 +101,7 @@ class ProjectsController < Projects::ApplicationController
respond_to do |format|
format.html do
if current_user
@membership = @project.team.find_member(current_user.id)
if @membership
@notification_setting = current_user.notification_settings_for(@project)
end
end
@notification_setting = current_user.notification_settings_for(@project) if current_user
if @project.repository_exists?
if @project.empty_repo?
@ -147,6 +141,7 @@ class ProjectsController < Projects::ApplicationController
@suggestions = {
emojis: AwardEmoji.urls,
issues: autocomplete.issues,
milestones: autocomplete.milestones,
mergerequests: autocomplete.merge_requests,
members: participants
}
@ -235,7 +230,8 @@ class ProjectsController < Projects::ApplicationController
def project_params
params.require(:project).permit(
:name, :path, :description, :issues_tracker, :tag_list, :runners_token,
:issues_enabled, :merge_requests_enabled, :snippets_enabled, :issues_tracker_id, :default_branch,
:issues_enabled, :merge_requests_enabled, :snippets_enabled, :container_registry_enabled,
:issues_tracker_id, :default_branch,
:wiki_enabled, :visibility_level, :import_url, :last_activity_at, :namespace_id, :avatar,
:builds_enabled, :build_allow_git_fetch, :build_timeout_in_minutes, :build_coverage_regex,
:public_builds,

View File

@ -37,8 +37,8 @@ class RegistrationsController < Devise::RegistrationsController
super
end
def after_sign_up_path_for(_resource)
users_almost_there_path
def after_sign_up_path_for(user)
user.confirmed? ? dashboard_projects_path : users_almost_there_path
end
def after_inactive_sign_up_path_for(_resource)

View File

@ -10,7 +10,7 @@ class SnippetsController < ApplicationController
# Allow destroy snippet
before_action :authorize_admin_snippet!, only: [:destroy]
skip_before_action :authenticate_user!, only: [:index, :user_index, :show, :raw]
skip_before_action :authenticate_user!, only: [:index, :show, :raw]
layout 'snippets'
respond_to :html

View File

@ -58,6 +58,19 @@ class UsersController < ApplicationController
end
end
def snippets
load_snippets
respond_to do |format|
format.html { render 'show' }
format.json do
render json: {
html: view_to_html_string("snippets/_snippets", collection: @snippets)
}
end
end
end
def calendar
calendar = contributions_calendar
@timestamps = calendar.timestamps
@ -116,6 +129,15 @@ class UsersController < ApplicationController
@groups = JoinedGroupsFinder.new(user).execute(current_user)
end
def load_snippets
@snippets = SnippetsFinder.new.execute(
current_user,
filter: :by_user,
user: user,
scope: params[:scope]
).page(params[:page])
end
def projects_for_current_user
ProjectsFinder.new.execute(current_user)
end

View File

@ -252,8 +252,8 @@ class IssuableFinder
if filter_by_no_milestone?
items = items.where(milestone_id: [-1, nil])
elsif filter_by_upcoming_milestone?
upcoming = Milestone.where(project_id: projects).upcoming
items = items.joins(:milestone).where(milestones: { title: upcoming.try(:title) })
upcoming_ids = Milestone.upcoming_ids_by_projects(projects)
items = items.joins(:milestone).where(milestone_id: upcoming_ids)
else
items = items.joins(:milestone).where(milestones: { title: params[:milestone_title] })

View File

@ -10,7 +10,7 @@ class NotesFinder
notes =
case target_type
when "commit"
project.notes.for_commit_id(target_id).not_inline
project.notes.for_commit_id(target_id).non_diff_notes
when "issue"
project.issues.find(target_id).notes.nonawards.inc_author
when "merge_request"

View File

@ -0,0 +1,38 @@
class PipelinesFinder
attr_reader :project
def initialize(project)
@project = project
end
def execute(pipelines, scope)
case scope
when 'running'
pipelines.running_or_pending
when 'branches'
from_ids(pipelines, ids_for_ref(pipelines, branches))
when 'tags'
from_ids(pipelines, ids_for_ref(pipelines, tags))
else
pipelines
end
end
private
def ids_for_ref(pipelines, refs)
pipelines.where(ref: refs).group(:ref).select('max(id)')
end
def from_ids(pipelines, ids)
pipelines.unscoped.where(id: ids)
end
def branches
project.repository.branches.map(&:name)
end
def tags
project.repository.tags.map(&:name)
end
end

View File

@ -36,7 +36,7 @@ class TodosFinder
private
def action_id?
action_id.present? && [Todo::ASSIGNED, Todo::MENTIONED].include?(action_id.to_i)
action_id.present? && [Todo::ASSIGNED, Todo::MENTIONED, Todo::BUILD_FAILED].include?(action_id.to_i)
end
def action_id

View File

@ -110,8 +110,7 @@ module ApplicationHelper
]
# If reference is commit id - we should add it to branch/tag selectbox
if(@ref && !options.flatten.include?(@ref) &&
@ref =~ /\A[0-9a-zA-Z]{6,52}\z/)
if @ref && !options.flatten.include?(@ref) && @ref =~ /\A[0-9a-zA-Z]{6,52}\z/
options << ['Commit', [@ref]]
end

View File

@ -60,4 +60,18 @@ module ApplicationSettingsHelper
end
end
end
def oauth_providers_checkboxes
button_based_providers.map do |source|
disabled = current_application_settings.disabled_oauth_sign_in_sources.include?(source.to_s)
css_class = 'btn'
css_class << ' active' unless disabled
checkbox_name = 'application_setting[enabled_oauth_sign_in_sources][]'
label_tag(checkbox_name, class: css_class) do
check_box_tag(checkbox_name, source, !disabled,
autocomplete: 'off') + Gitlab::OAuth::Provider.label_for(source)
end
end
end
end

View File

@ -38,6 +38,16 @@ module AuthHelper
auth_providers.reject { |provider| form_based_provider?(provider) }
end
def enabled_button_based_providers
disabled_providers = current_application_settings.disabled_oauth_sign_in_sources || []
button_based_providers.map(&:to_s) - disabled_providers
end
def button_based_providers_enabled?
enabled_button_based_providers.any?
end
def provider_image_tag(provider, size = 64)
label = label_for_provider(provider)

View File

@ -184,4 +184,14 @@ module BlobHelper
Other: licenses.reject(&:featured).map { |license| [license.name, license.key] }
}
end
def gitignore_names
return @gitignore_names if defined?(@gitignore_names)
@gitignore_names = {
Global: Gitlab::Gitignore.global.map { |gitignore| { name: gitignore.name } },
# Note that the key here doesn't cover it really
Languages: Gitlab::Gitignore.languages_frameworks.map{ |gitignore| { name: gitignore.name } }
}
end
end

View File

@ -38,19 +38,30 @@ module CiStatusHelper
icon(icon_name + ' fw')
end
def render_ci_status(ci_commit, tooltip_placement: 'auto left')
# TODO: split this method into
# - render_commit_status
# - render_pipeline_status
link_to ci_icon_for_status(ci_commit.status),
ci_status_path(ci_commit),
class: "ci-status-link ci-status-icon-#{ci_commit.status.dasherize}",
title: "Build #{ci_label_for_status(ci_commit.status)}",
data: { toggle: 'tooltip', placement: tooltip_placement }
def render_commit_status(commit, tooltip_placement: 'auto left')
project = commit.project
path = builds_namespace_project_commit_path(project.namespace, project, commit)
render_status_with_link('commit', commit.status, path, tooltip_placement)
end
def render_pipeline_status(pipeline, tooltip_placement: 'auto left')
project = pipeline.project
path = namespace_project_pipeline_path(project.namespace, project, pipeline)
render_status_with_link('pipeline', pipeline.status, path, tooltip_placement)
end
def no_runners_for_project?(project)
project.runners.blank? &&
Ci::Runner.shared.blank?
end
private
def render_status_with_link(type, status, path, tooltip_placement)
link_to ci_icon_for_status(status),
path,
class: "ci-status-link ci-status-icon-#{status.dasherize}",
title: "#{type.titleize}: #{ci_label_for_status(status)}",
data: { toggle: 'tooltip', placement: tooltip_placement }
end
end

View File

@ -2,8 +2,8 @@ module DiffHelper
def mark_inline_diffs(old_line, new_line)
old_diffs, new_diffs = Gitlab::Diff::InlineDiff.new(old_line, new_line).inline_diffs
marked_old_line = Gitlab::Diff::InlineDiffMarker.new(old_line).mark(old_diffs)
marked_new_line = Gitlab::Diff::InlineDiffMarker.new(new_line).mark(new_diffs)
marked_old_line = Gitlab::Diff::InlineDiffMarker.new(old_line).mark(old_diffs, mode: :deletion)
marked_new_line = Gitlab::Diff::InlineDiffMarker.new(new_line).mark(new_diffs, mode: :addition)
[marked_old_line, marked_new_line]
end
@ -55,22 +55,18 @@ module DiffHelper
end
end
def line_comments
@line_comments ||= @line_notes.select(&:active?).sort_by(&:created_at).group_by(&:line_code)
end
def organize_comments(left, right)
notes_left = notes_right = nil
def organize_comments(type_left, type_right, line_code_left, line_code_right)
comments_left = comments_right = nil
unless type_left.nil? && type_right == 'new'
comments_left = line_comments[line_code_left]
unless left[:type].nil? && right[:type] == 'new'
notes_left = @grouped_diff_notes[left[:line_code]]
end
unless type_left.nil? && type_right.nil?
comments_right = line_comments[line_code_right]
unless left[:type].nil? && right[:type].nil?
notes_right = @grouped_diff_notes[right[:line_code]]
end
[comments_left, comments_right]
[notes_left, notes_right]
end
def inline_diff_btn
@ -96,8 +92,8 @@ module DiffHelper
].join(' ').html_safe
end
def commit_for_diff(diff)
if diff.deleted_file
def commit_for_diff(diff_file)
if diff_file.deleted_file
@base_commit || @commit.parent || @commit
else
@commit

View File

@ -32,12 +32,6 @@ module EmailsHelper
nil
end
def color_email_diff(diffcontent)
formatter = Rouge::Formatters::HTML.new(css_class: 'highlight', inline_theme: 'github')
lexer = Rouge::Lexers::Diff
raw formatter.format(lexer.lex(diffcontent))
end
def password_reset_token_valid_time
valid_hours = Devise.reset_password_within / 60 / 60
if valid_hours >= 24

View File

@ -3,7 +3,7 @@ module EventsHelper
author = event.author
if author
link_to author.name, user_path(author.username), title: h(author.name)
link_to author.name, user_path(author.username), title: author.name
else
event.author_name
end
@ -39,15 +39,6 @@ module EventsHelper
end
end
def icon_for_event
{
EventFilter.push => 'upload',
EventFilter.merged => 'check-square-o',
EventFilter.comments => 'comments',
EventFilter.team => 'user',
}
end
def event_preposition(event)
if event.push? || event.commented? || event.target
"at"
@ -66,11 +57,7 @@ module EventsHelper
words << event.ref_name
words << "at"
elsif event.commented?
if event.note_commit?
words << event.note_short_commit_id
else
words << "##{truncate event.note_target_iid}"
end
words << event.note_target_reference
words << "at"
elsif event.milestone?
words << "##{event.target_iid}" if event.target_iid
@ -93,21 +80,12 @@ module EventsHelper
elsif event.merge_request?
namespace_project_merge_request_url(event.project.namespace,
event.project, event.merge_request)
elsif event.note? && event.note_commit?
elsif event.note? && event.commit_note?
namespace_project_commit_url(event.project.namespace, event.project,
event.note_target)
elsif event.note?
if event.note_target
if event.note_commit?
namespace_project_commit_path(event.project.namespace, event.project,
event.note_commit_id,
anchor: dom_id(event.target))
elsif event.note_project_snippet?
namespace_project_snippet_path(event.project.namespace,
event.project, event.note_target)
else
event_note_target_path(event)
end
event_note_target_path(event)
end
elsif event.push?
push_event_feed_url(event)
@ -143,42 +121,30 @@ module EventsHelper
end
def event_note_target_path(event)
if event.note? && event.note_commit?
namespace_project_commit_path(event.project.namespace, event.project,
event.note_target)
if event.note? && event.commit_note?
namespace_project_commit_path(event.project.namespace,
event.project,
event.note_target,
anchor: dom_id(event.target))
elsif event.project_snippet_note?
namespace_project_snippet_path(event.project.namespace,
event.project,
event.note_target,
anchor: dom_id(event.target))
else
polymorphic_path([event.project.namespace.becomes(Namespace),
event.project, event.note_target],
anchor: dom_id(event.target))
anchor: dom_id(event.target))
end
end
def event_note_title_html(event)
if event.note_target
if event.note_commit?
link_to(
namespace_project_commit_path(event.project.namespace, event.project,
event.note_commit_id,
anchor: dom_id(event.target), title: h(event.target_title)),
class: "commit_short_id"
) do
"#{event.note_target_type} #{event.note_short_commit_id}"
end
elsif event.note_project_snippet?
link_to(namespace_project_snippet_path(event.project.namespace,
event.project,
event.note_target), title: h(event.project.name)) do
"#{event.note_target_type} #{truncate event.note_target.to_reference}"
end
else
link_to event_note_target_path(event) do
"#{event.note_target_type} #{truncate event.note_target.to_reference}"
end
link_to(event_note_target_path(event), title: event.target_title, class: 'has-tooltip') do
"#{event.note_target_type} #{event.note_target_reference}"
end
else
content_tag :strong do
"(deleted)"
end
content_tag(:strong, '(deleted)')
end
end

View File

@ -13,7 +13,7 @@ module GitlabMarkdownHelper
def link_to_gfm(body, url, html_options = {})
return "" if body.blank?
escaped_body = if body =~ /\A\<img/
escaped_body = if body.start_with?('<img')
body
else
escape_once(body)

View File

@ -33,6 +33,10 @@ module GitlabRoutingHelper
namespace_project_builds_path(project.namespace, project, *args)
end
def project_container_registry_path(project, *args)
namespace_project_container_registry_index_path(project.namespace, project, *args)
end
def activity_project_path(project, *args)
activity_namespace_project_path(project.namespace, project, *args)
end

View File

@ -43,4 +43,12 @@ module NavHelper
class_name += " with-horizontal-nav" if defined?(nav) && nav
class_name
end
def layout_nav_class
"page-with-layout-nav" if defined?(nav) && nav
end
def layout_dropdown_class
"controls-dropdown-visible" if current_user
end
end

View File

@ -1,7 +1,7 @@
module NotesHelper
# Helps to distinguish e.g. commit notes in mr notes list
def note_for_main_target?(note)
(@noteable.class.name == note.noteable_type && !note.for_diff_line?)
@noteable.class.name == note.noteable_type && !note.diff_note?
end
def note_target_fields(note)
@ -15,16 +15,6 @@ module NotesHelper
note.editable? && can?(current_user, :admin_note, note)
end
def link_to_commit_diff_line_note(note)
if note.for_commit_diff_line?
link_to(
"#{note.diff_file_name}:L#{note.diff_new_line}",
namespace_project_commit_path(@project.namespace, @project,
note.noteable, anchor: note.line_code)
)
end
end
def noteable_json(noteable)
{
id: noteable.id,
@ -35,7 +25,7 @@ module NotesHelper
end
def link_to_new_diff_note(line_code, line_type = nil)
discussion_id = Note.build_discussion_id(
discussion_id = LegacyDiffNote.build_discussion_id(
@comments_target[:noteable_type],
@comments_target[:noteable_id] || @comments_target[:commit_id],
line_code
@ -45,9 +35,10 @@ module NotesHelper
noteable_type: @comments_target[:noteable_type],
noteable_id: @comments_target[:noteable_id],
commit_id: @comments_target[:commit_id],
line_type: line_type,
line_code: line_code,
discussion_id: discussion_id,
line_type: line_type
note_type: LegacyDiffNote.name,
discussion_id: discussion_id
}
button_tag(class: 'btn add-diff-note js-add-diff-note-button',
@ -57,18 +48,24 @@ module NotesHelper
end
end
def link_to_reply_diff(note, line_type = nil)
def link_to_reply_discussion(note, line_type = nil)
return unless current_user
data = {
noteable_type: note.noteable_type,
noteable_id: note.noteable_id,
commit_id: note.commit_id,
line_code: note.line_code,
discussion_id: note.discussion_id,
line_type: line_type
}
if note.diff_note?
data.merge!(
line_code: note.line_code,
note_type: LegacyDiffNote.name
)
end
button_tag 'Reply...', class: 'btn btn-text-field js-discussion-reply-button',
data: data, title: 'Add a reply'
end

View File

@ -124,11 +124,7 @@ module ProjectsHelper
end
def license_short_name(project)
no_license_key = project.repository.license_key.nil? ||
# Back-compat if cache contains 'no-license', can be removed in a few weeks
project.repository.license_key == 'no-license'
return 'LICENSE' if no_license_key
return 'LICENSE' if project.repository.license_key.nil?
license = Licensee::License.new(project.repository.license_key)
@ -138,20 +134,28 @@ module ProjectsHelper
private
def get_project_nav_tabs(project, current_user)
nav_tabs = [:home, :forks]
nav_tabs = [:home]
if !project.empty_repo? && can?(current_user, :download_code, project)
nav_tabs << [:files, :commits, :network, :graphs]
nav_tabs << [:files, :commits, :network, :graphs, :forks]
end
if project.repo_exists? && can?(current_user, :read_merge_request, project)
nav_tabs << :merge_requests
end
if can?(current_user, :read_pipeline, project)
nav_tabs << :pipelines
end
if can?(current_user, :read_build, project)
nav_tabs << :builds
end
if Gitlab.config.registry.enabled && can?(current_user, :read_container_image, project)
nav_tabs << :container_registry
end
if can?(current_user, :admin_project, project)
nav_tabs << :settings
end

View File

@ -59,7 +59,7 @@ module SearchHelper
# Autocomplete results for the current project, if it's defined
def project_autocomplete
if @project && @project.repository.exists? && @project.repository.root_ref
ref = @ref || @project.repository.root_ref
ref = @ref || @project.repository.root_ref
[
{ category: "Current Project", label: "Files", url: namespace_project_tree_path(@project.namespace, @project, ref) },

View File

@ -18,7 +18,7 @@ module SelectsHelper
first_user: first_user,
current_user: opts[:current_user] || false,
"push-code-to-protected-branches" => opts[:push_code_to_protected_branches],
author_id: opts[:author_id] || ''
author_id: opts[:author_id] || ''
}
}

View File

@ -112,7 +112,7 @@ module TabHelper
end
def profile_tab_class
if controller.controller_path =~ /\Aprofiles/
if controller.controller_path.start_with?('profiles')
return 'active'
end

View File

@ -11,6 +11,7 @@ module TodosHelper
case todo.action
when Todo::ASSIGNED then 'assigned you'
when Todo::MENTIONED then 'mentioned you on'
when Todo::BUILD_FAILED then 'The build failed for your'
end
end
@ -28,8 +29,11 @@ module TodosHelper
namespace_project_commit_path(todo.project.namespace.becomes(Namespace), todo.project,
todo.target, anchor: anchor)
else
polymorphic_path([todo.project.namespace.becomes(Namespace),
todo.project, todo.target], anchor: anchor)
path = [todo.project.namespace.becomes(Namespace), todo.project, todo.target]
path.unshift(:builds) if todo.build_failed?
polymorphic_path(path, anchor: anchor)
end
end

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