Merge branch 'master' of gitlab.com:gitlab-org/gitlab-ce into store-variables-and-when-in-builds-table
# Conflicts: # db/schema.rb
This commit is contained in:
commit
ffea9c4600
111 changed files with 1980 additions and 1674 deletions
361
.rubocop.yml
361
.rubocop.yml
|
@ -2,6 +2,8 @@ require:
|
|||
- rubocop-rspec
|
||||
- ./rubocop/rubocop
|
||||
|
||||
inherit_from: .rubocop_todo.yml
|
||||
|
||||
AllCops:
|
||||
TargetRubyVersion: 2.1
|
||||
# Cop names are not displayed in offense messages by default. Change behavior
|
||||
|
@ -52,14 +54,6 @@ Style/AlignArray:
|
|||
Style/AlignHash:
|
||||
Enabled: true
|
||||
|
||||
# Align the parameters of a method call if they span more than one line.
|
||||
Style/AlignParameters:
|
||||
Enabled: false
|
||||
|
||||
# Use &&/|| instead of and/or.
|
||||
Style/AndOr:
|
||||
Enabled: false
|
||||
|
||||
# Use `Array#join` instead of `Array#*`.
|
||||
Style/ArrayJoin:
|
||||
Enabled: true
|
||||
|
@ -80,10 +74,6 @@ Style/Attr:
|
|||
Style/BeginBlock:
|
||||
Enabled: true
|
||||
|
||||
# Checks if usage of %() or %Q() matches configuration.
|
||||
Style/BarePercentLiterals:
|
||||
Enabled: false
|
||||
|
||||
# Do not use block comments.
|
||||
Style/BlockComments:
|
||||
Enabled: true
|
||||
|
@ -97,14 +87,6 @@ Style/BlockEndNewline:
|
|||
Style/BlockDelimiters:
|
||||
Enabled: true
|
||||
|
||||
# Enforce braces style around hash parameters.
|
||||
Style/BracesAroundHashParameters:
|
||||
Enabled: false
|
||||
|
||||
# Avoid explicit use of the case equality operator(===).
|
||||
Style/CaseEquality:
|
||||
Enabled: false
|
||||
|
||||
# Indentation of when in a case/when/[else/]end.
|
||||
Style/CaseIndentation:
|
||||
Enabled: true
|
||||
|
@ -133,24 +115,10 @@ Style/ClassMethods:
|
|||
Style/ClassVars:
|
||||
Enabled: true
|
||||
|
||||
# Do not use :: for method call.
|
||||
Style/ColonMethodCall:
|
||||
Enabled: false
|
||||
|
||||
# Checks formatting of special comments (TODO, FIXME, OPTIMIZE, HACK, REVIEW).
|
||||
Style/CommentAnnotation:
|
||||
Enabled: false
|
||||
|
||||
# Indentation of comments.
|
||||
Style/CommentIndentation:
|
||||
Enabled: true
|
||||
|
||||
# Use the return value of `if` and `case` statements for assignment to a
|
||||
# variable and variable comparison instead of assigning that variable
|
||||
# inside of each branch.
|
||||
Style/ConditionalAssignment:
|
||||
Enabled: false
|
||||
|
||||
# Constants should use SCREAMING_SNAKE_CASE.
|
||||
Style/ConstantName:
|
||||
Enabled: true
|
||||
|
@ -159,34 +127,14 @@ Style/ConstantName:
|
|||
Style/DefWithParentheses:
|
||||
Enabled: true
|
||||
|
||||
# Checks for use of deprecated Hash methods.
|
||||
Style/DeprecatedHashMethods:
|
||||
Enabled: false
|
||||
|
||||
# Document classes and non-namespace modules.
|
||||
Style/Documentation:
|
||||
Enabled: false
|
||||
|
||||
# Checks the position of the dot in multi-line method calls.
|
||||
Style/DotPosition:
|
||||
Enabled: false
|
||||
|
||||
# Checks for uses of double negation (!!).
|
||||
Style/DoubleNegation:
|
||||
Enabled: false
|
||||
|
||||
# Prefer `each_with_object` over `inject` or `reduce`.
|
||||
Style/EachWithObject:
|
||||
Enabled: false
|
||||
|
||||
# Align elses and elsifs correctly.
|
||||
Style/ElseAlignment:
|
||||
Enabled: true
|
||||
|
||||
# Avoid empty else-clauses.
|
||||
Style/EmptyElse:
|
||||
Enabled: false
|
||||
|
||||
# Use empty lines between defs.
|
||||
Style/EmptyLineBetweenDefs:
|
||||
Enabled: false
|
||||
|
@ -215,10 +163,6 @@ Style/EmptyLinesAroundModuleBody:
|
|||
Style/EmptyLinesAroundMethodBody:
|
||||
Enabled: false
|
||||
|
||||
# Prefer literals to Array.new/Hash.new/String.new.
|
||||
Style/EmptyLiteral:
|
||||
Enabled: false
|
||||
|
||||
# Avoid the use of END blocks.
|
||||
Style/EndBlock:
|
||||
Enabled: true
|
||||
|
@ -231,10 +175,6 @@ Style/EndOfLine:
|
|||
Style/EvenOdd:
|
||||
Enabled: true
|
||||
|
||||
# Do not use unnecessary spacing.
|
||||
Style/ExtraSpacing:
|
||||
Enabled: false
|
||||
|
||||
# Use snake_case for source file names.
|
||||
Style/FileName:
|
||||
Enabled: true
|
||||
|
@ -252,31 +192,15 @@ Style/FlipFlop:
|
|||
Style/For:
|
||||
Enabled: true
|
||||
|
||||
# Enforce the use of Kernel#sprintf, Kernel#format or String#%.
|
||||
Style/FormatString:
|
||||
Enabled: false
|
||||
|
||||
# Do not introduce global variables.
|
||||
Style/GlobalVars:
|
||||
Enabled: true
|
||||
|
||||
# Check for conditionals that can be replaced with guard clauses.
|
||||
Style/GuardClause:
|
||||
Enabled: false
|
||||
|
||||
# Prefer Ruby 1.9 hash syntax `{ a: 1, b: 2 }`
|
||||
# over 1.8 syntax `{ :a => 1, :b => 2 }`.
|
||||
Style/HashSyntax:
|
||||
Enabled: true
|
||||
|
||||
# Finds if nodes inside else, which can be converted to elsif.
|
||||
Style/IfInsideElse:
|
||||
Enabled: false
|
||||
|
||||
# Favor modifier if/unless usage when you have a single-line body.
|
||||
Style/IfUnlessModifier:
|
||||
Enabled: false
|
||||
|
||||
# Do not use if x; .... Use the ternary operator instead.
|
||||
Style/IfWithSemicolon:
|
||||
Enabled: true
|
||||
|
@ -299,22 +223,10 @@ Style/IndentationConsistency:
|
|||
Style/IndentationWidth:
|
||||
Enabled: true
|
||||
|
||||
# Checks the indentation of the first element in an array literal.
|
||||
Style/IndentArray:
|
||||
Enabled: false
|
||||
|
||||
# Checks the indentation of the first key in a hash literal.
|
||||
Style/IndentHash:
|
||||
Enabled: false
|
||||
|
||||
# Use Kernel#loop for infinite loops.
|
||||
Style/InfiniteLoop:
|
||||
Enabled: true
|
||||
|
||||
# Use the new lambda literal syntax for single-line blocks.
|
||||
Style/Lambda:
|
||||
Enabled: false
|
||||
|
||||
# Use lambda.call(...) instead of lambda.(...).
|
||||
Style/LambdaCall:
|
||||
Enabled: true
|
||||
|
@ -323,14 +235,6 @@ Style/LambdaCall:
|
|||
Style/LeadingCommentSpace:
|
||||
Enabled: true
|
||||
|
||||
# Use \ instead of + or << to concatenate two string literals at line end.
|
||||
Style/LineEndConcatenation:
|
||||
Enabled: false
|
||||
|
||||
# Do not use parentheses for method calls with no arguments.
|
||||
Style/MethodCallParentheses:
|
||||
Enabled: false
|
||||
|
||||
# Checks if the method definitions have or don't have parentheses.
|
||||
Style/MethodDefParentheses:
|
||||
Enabled: true
|
||||
|
@ -387,39 +291,18 @@ Style/MultilineMethodDefinitionBraceLayout:
|
|||
Style/MultilineOperationIndentation:
|
||||
Enabled: false
|
||||
|
||||
# Avoid multi-line `? :` (the ternary operator), use if/unless instead.
|
||||
Style/MultilineTernaryOperator:
|
||||
Enabled: false
|
||||
|
||||
# Do not assign mutable objects to constants.
|
||||
Style/MutableConstant:
|
||||
Enabled: false
|
||||
|
||||
# Favor unless over if for negative conditions (or control flow or).
|
||||
Style/NegatedIf:
|
||||
Enabled: true
|
||||
|
||||
# Favor until over while for negative conditions.
|
||||
Style/NegatedWhile:
|
||||
Enabled: false
|
||||
|
||||
# Avoid using nested modifiers.
|
||||
Style/NestedModifier:
|
||||
Enabled: true
|
||||
|
||||
# Parenthesize method calls which are nested inside the argument list of
|
||||
# another parenthesized method call.
|
||||
Style/NestedParenthesizedCalls:
|
||||
Enabled: false
|
||||
|
||||
# Use one expression per branch in a ternary operator.
|
||||
Style/NestedTernaryOperator:
|
||||
Enabled: true
|
||||
|
||||
# Use `next` to skip iteration instead of a condition at the end.
|
||||
Style/Next:
|
||||
Enabled: false
|
||||
|
||||
# Prefer x.nil? to x == nil.
|
||||
Style/NilComparison:
|
||||
Enabled: true
|
||||
|
@ -444,51 +327,10 @@ Style/OneLineConditional:
|
|||
Style/OpMethod:
|
||||
Enabled: true
|
||||
|
||||
# Check for simple usages of parallel assignment. It will only warn when
|
||||
# the number of variables matches on both sides of the assignment.
|
||||
Style/ParallelAssignment:
|
||||
Enabled: false
|
||||
|
||||
# Don't use parentheses around the condition of an if/unless/while.
|
||||
Style/ParenthesesAroundCondition:
|
||||
Enabled: true
|
||||
|
||||
# Use `%`-literal delimiters consistently.
|
||||
Style/PercentLiteralDelimiters:
|
||||
Enabled: false
|
||||
|
||||
# Checks if uses of %Q/%q match the configured preference.
|
||||
Style/PercentQLiterals:
|
||||
Enabled: false
|
||||
|
||||
# Avoid Perl-style regex back references.
|
||||
Style/PerlBackrefs:
|
||||
Enabled: false
|
||||
|
||||
# Check the names of predicate methods.
|
||||
Style/PredicateName:
|
||||
Enabled: false
|
||||
|
||||
# Use proc instead of Proc.new.
|
||||
Style/Proc:
|
||||
Enabled: false
|
||||
|
||||
# Checks the arguments passed to raise/fail.
|
||||
Style/RaiseArgs:
|
||||
Enabled: false
|
||||
|
||||
# Don't use begin blocks when they are not needed.
|
||||
Style/RedundantBegin:
|
||||
Enabled: false
|
||||
|
||||
# Checks for an obsolete RuntimeException argument in raise/fail.
|
||||
Style/RedundantException:
|
||||
Enabled: false
|
||||
|
||||
# Checks usages of Object#freeze on immutable objects.
|
||||
Style/RedundantFreeze:
|
||||
Enabled: false
|
||||
|
||||
# Checks for parentheses that seem not to serve any purpose.
|
||||
Style/RedundantParentheses:
|
||||
Enabled: true
|
||||
|
@ -497,24 +339,6 @@ Style/RedundantParentheses:
|
|||
Style/RedundantReturn:
|
||||
Enabled: true
|
||||
|
||||
# Don't use self where it's not needed.
|
||||
Style/RedundantSelf:
|
||||
Enabled: false
|
||||
|
||||
# Use %r for regular expressions matching more than `MaxSlashes` '/'
|
||||
# characters. Use %r only for regular expressions matching more
|
||||
# than `MaxSlashes` '/' character.
|
||||
Style/RegexpLiteral:
|
||||
Enabled: false
|
||||
|
||||
# Avoid using rescue in its modifier form.
|
||||
Style/RescueModifier:
|
||||
Enabled: false
|
||||
|
||||
# Checks for places where self-assignment shorthand should have been used.
|
||||
Style/SelfAssignment:
|
||||
Enabled: false
|
||||
|
||||
# Don't use semicolons to terminate expressions.
|
||||
Style/Semicolon:
|
||||
Enabled: true
|
||||
|
@ -524,14 +348,6 @@ Style/SignalException:
|
|||
EnforcedStyle: only_raise
|
||||
Enabled: true
|
||||
|
||||
# Enforces the names of some block params.
|
||||
Style/SingleLineBlockParams:
|
||||
Enabled: false
|
||||
|
||||
# Avoid single-line methods.
|
||||
Style/SingleLineMethods:
|
||||
Enabled: false
|
||||
|
||||
# Use spaces after colons.
|
||||
Style/SpaceAfterColon:
|
||||
Enabled: true
|
||||
|
@ -553,11 +369,6 @@ Style/SpaceAfterNot:
|
|||
Style/SpaceAfterSemicolon:
|
||||
Enabled: true
|
||||
|
||||
# Checks that the equals signs in parameter default assignments have or don't
|
||||
# have surrounding space depending on configuration.
|
||||
Style/SpaceAroundEqualsInParameterDefault:
|
||||
Enabled: false
|
||||
|
||||
# Use a space around keywords if appropriate.
|
||||
Style/SpaceAroundKeyword:
|
||||
Enabled: true
|
||||
|
@ -566,10 +377,6 @@ Style/SpaceAroundKeyword:
|
|||
Style/SpaceAroundOperators:
|
||||
Enabled: true
|
||||
|
||||
# Checks that the left block brace has or doesn't have space before it.
|
||||
Style/SpaceBeforeBlockBraces:
|
||||
Enabled: false
|
||||
|
||||
# No spaces before commas.
|
||||
Style/SpaceBeforeComma:
|
||||
Enabled: true
|
||||
|
@ -578,33 +385,14 @@ Style/SpaceBeforeComma:
|
|||
Style/SpaceBeforeComment:
|
||||
Enabled: true
|
||||
|
||||
# Checks that exactly one space is used between a method name and the first
|
||||
# argument for method calls without parentheses.
|
||||
Style/SpaceBeforeFirstArg:
|
||||
Enabled: false
|
||||
|
||||
# No spaces before semicolons.
|
||||
Style/SpaceBeforeSemicolon:
|
||||
Enabled: true
|
||||
|
||||
# Checks that block braces have or don't have surrounding space.
|
||||
# For blocks taking parameters, checks that the left brace has or doesn't
|
||||
# have trailing space.
|
||||
Style/SpaceInsideBlockBraces:
|
||||
Enabled: false
|
||||
|
||||
# No spaces after [ or before ].
|
||||
Style/SpaceInsideBrackets:
|
||||
Enabled: false
|
||||
|
||||
# Use spaces inside hash literal braces - or don't.
|
||||
Style/SpaceInsideHashLiteralBraces:
|
||||
Enabled: true
|
||||
|
||||
# No spaces after ( or before ).
|
||||
Style/SpaceInsideParens:
|
||||
Enabled: false
|
||||
|
||||
# No spaces inside range literals.
|
||||
Style/SpaceInsideRangeLiteral:
|
||||
Enabled: true
|
||||
|
@ -614,10 +402,6 @@ Style/SpaceInsideStringInterpolation:
|
|||
EnforcedStyle: no_space
|
||||
Enabled: true
|
||||
|
||||
# Avoid Perl-style global variables.
|
||||
Style/SpecialGlobalVars:
|
||||
Enabled: false
|
||||
|
||||
# Check for the usage of parentheses around stabby lambda arguments.
|
||||
Style/StabbyLambdaParentheses:
|
||||
EnforcedStyle: require_parentheses
|
||||
|
@ -627,25 +411,12 @@ Style/StabbyLambdaParentheses:
|
|||
Style/StringLiterals:
|
||||
Enabled: false
|
||||
|
||||
# Checks if uses of quotes inside expressions in interpolated strings match the
|
||||
# configured preference.
|
||||
Style/StringLiteralsInInterpolation:
|
||||
Enabled: false
|
||||
|
||||
# Checks if configured preferred methods are used over non-preferred.
|
||||
Style/StringMethods:
|
||||
PreferredMethods:
|
||||
intern: to_sym
|
||||
Enabled: true
|
||||
|
||||
# Use %i or %I for arrays of symbols.
|
||||
Style/SymbolArray:
|
||||
Enabled: false
|
||||
|
||||
# Use symbols as procs instead of blocks when possible.
|
||||
Style/SymbolProc:
|
||||
Enabled: false
|
||||
|
||||
# No hard tabs.
|
||||
Style/Tab:
|
||||
Enabled: true
|
||||
|
@ -654,40 +425,10 @@ Style/Tab:
|
|||
Style/TrailingBlankLines:
|
||||
Enabled: true
|
||||
|
||||
# Checks for trailing comma in array and hash literals.
|
||||
Style/TrailingCommaInLiteral:
|
||||
Enabled: false
|
||||
|
||||
# Checks for trailing comma in argument lists.
|
||||
Style/TrailingCommaInArguments:
|
||||
Enabled: false
|
||||
|
||||
# Avoid trailing whitespace.
|
||||
Style/TrailingWhitespace:
|
||||
Enabled: false
|
||||
|
||||
# Checks for the usage of unneeded trailing underscores at the end of
|
||||
# parallel variable assignment.
|
||||
Style/TrailingUnderscoreVariable:
|
||||
Enabled: false
|
||||
|
||||
# Prefer attr_* methods to trivial readers/writers.
|
||||
Style/TrivialAccessors:
|
||||
Enabled: false
|
||||
|
||||
# Do not use unless with else. Rewrite these with the positive case first.
|
||||
Style/UnlessElse:
|
||||
Enabled: false
|
||||
|
||||
# Checks for %W when interpolation is not needed.
|
||||
Style/UnneededCapitalW:
|
||||
Enabled: true
|
||||
|
||||
# TODO: Enable UnneededInterpolation Cop.
|
||||
# Checks for strings that are just an interpolated expression.
|
||||
Style/UnneededInterpolation:
|
||||
Enabled: false
|
||||
|
||||
# Checks for %q/%Q when single quotes or double quotes would do.
|
||||
Style/UnneededPercentQ:
|
||||
Enabled: false
|
||||
|
@ -717,12 +458,6 @@ Style/WhileUntilModifier:
|
|||
Style/WordArray:
|
||||
Enabled: false
|
||||
|
||||
# TODO: Enable ZeroLengthPredicate Cop.
|
||||
# Use #empty? when testing for objects of length 0.
|
||||
Style/ZeroLengthPredicate:
|
||||
Enabled: false
|
||||
|
||||
|
||||
#################### Metrics ################################
|
||||
|
||||
# A calculated magnitude based on number of assignments,
|
||||
|
@ -776,15 +511,6 @@ Metrics/PerceivedComplexity:
|
|||
Lint/AmbiguousOperator:
|
||||
Enabled: true
|
||||
|
||||
# Checks for ambiguous regexp literals in the first argument of a method
|
||||
# invocation without parentheses.
|
||||
Lint/AmbiguousRegexpLiteral:
|
||||
Enabled: false
|
||||
|
||||
# Don't use assignment in conditions.
|
||||
Lint/AssignmentInCondition:
|
||||
Enabled: false
|
||||
|
||||
# Align block ends correctly.
|
||||
Lint/BlockAlignment:
|
||||
Enabled: true
|
||||
|
@ -810,14 +536,6 @@ Lint/DefEndAlignment:
|
|||
Lint/DeprecatedClassMethods:
|
||||
Enabled: true
|
||||
|
||||
# Check for duplicate method definitions.
|
||||
Lint/DuplicateMethods:
|
||||
Enabled: false
|
||||
|
||||
# Check for duplicate keys in hash literals.
|
||||
Lint/DuplicatedKey:
|
||||
Enabled: false
|
||||
|
||||
# Check for immutable argument given to each_with_object.
|
||||
Lint/EachWithObjectArgument:
|
||||
Enabled: true
|
||||
|
@ -830,10 +548,6 @@ Lint/ElseLayout:
|
|||
Lint/EmptyEnsure:
|
||||
Enabled: true
|
||||
|
||||
# Checks for empty string interpolation.
|
||||
Lint/EmptyInterpolation:
|
||||
Enabled: false
|
||||
|
||||
# Align ends correctly.
|
||||
Lint/EndAlignment:
|
||||
Enabled: true
|
||||
|
@ -858,21 +572,11 @@ Lint/FloatOutOfRange:
|
|||
Lint/FormatParameterMismatch:
|
||||
Enabled: true
|
||||
|
||||
# Don't suppress exception.
|
||||
Lint/HandleExceptions:
|
||||
Enabled: false
|
||||
|
||||
# Checks for adjacent string literals on the same line, which could better be
|
||||
# represented as a single string literal.
|
||||
Lint/ImplicitStringConcatenation:
|
||||
Enabled: true
|
||||
|
||||
# TODO: Enable IneffectiveAccessModifier Cop.
|
||||
# Checks for attempts to use `private` or `protected` to set the visibility
|
||||
# of a class method, which does not work.
|
||||
Lint/IneffectiveAccessModifier:
|
||||
Enabled: false
|
||||
|
||||
# Checks for invalid character literals with a non-escaped whitespace
|
||||
# character.
|
||||
Lint/InvalidCharacterLiteral:
|
||||
|
@ -886,11 +590,6 @@ Lint/LiteralInCondition:
|
|||
Lint/LiteralInInterpolation:
|
||||
Enabled: true
|
||||
|
||||
# Use Kernel#loop with break rather than begin/end/until or begin/end/while
|
||||
# for post-loop tests.
|
||||
Lint/Loop:
|
||||
Enabled: false
|
||||
|
||||
# Do not use nested method definitions.
|
||||
Lint/NestedMethodDefinition:
|
||||
Enabled: true
|
||||
|
@ -916,13 +615,8 @@ Lint/RequireParentheses:
|
|||
Lint/RescueException:
|
||||
Enabled: true
|
||||
|
||||
# Do not use the same name as outer local variable for block arguments
|
||||
# or block local variables.
|
||||
Lint/ShadowingOuterLocalVariable:
|
||||
Enabled: false
|
||||
|
||||
# 'Checks for Object#to_s usage in string interpolation.
|
||||
Lint/StringConversionInInterpolation:
|
||||
# Checks for the order which exceptions are rescued to avoid rescueing a less specific exception before a more specific exception.
|
||||
Lint/ShadowedException:
|
||||
Enabled: false
|
||||
|
||||
# Do not use prefix `_` for a variable that is used.
|
||||
|
@ -935,22 +629,10 @@ Lint/UnderscorePrefixedVariableName:
|
|||
Lint/UnneededDisable:
|
||||
Enabled: false
|
||||
|
||||
# Checks for unused block arguments.
|
||||
Lint/UnusedBlockArgument:
|
||||
Enabled: false
|
||||
|
||||
# Checks for unused method arguments.
|
||||
Lint/UnusedMethodArgument:
|
||||
Enabled: false
|
||||
|
||||
# Unreachable code.
|
||||
Lint/UnreachableCode:
|
||||
Enabled: true
|
||||
|
||||
# Checks for useless access modifiers.
|
||||
Lint/UselessAccessModifier:
|
||||
Enabled: false
|
||||
|
||||
# Checks for useless assignment to a local variable.
|
||||
Lint/UselessAssignment:
|
||||
Enabled: true
|
||||
|
@ -983,11 +665,6 @@ Performance/Casecmp:
|
|||
Performance/DoubleStartEndWith:
|
||||
Enabled: true
|
||||
|
||||
# TODO: Enable EndWith Cop.
|
||||
# Use `end_with?` instead of a regex match anchored to the end of a string.
|
||||
Performance/EndWith:
|
||||
Enabled: false
|
||||
|
||||
# Use `strip` instead of `lstrip.rstrip`.
|
||||
Performance/LstripRstrip:
|
||||
Enabled: true
|
||||
|
@ -996,24 +673,6 @@ Performance/LstripRstrip:
|
|||
Performance/RangeInclude:
|
||||
Enabled: true
|
||||
|
||||
# TODO: Enable RedundantBlockCall Cop.
|
||||
# Use `yield` instead of `block.call`.
|
||||
Performance/RedundantBlockCall:
|
||||
Enabled: false
|
||||
|
||||
# TODO: Enable RedundantMatch Cop.
|
||||
# Use `=~` instead of `String#match` or `Regexp#match` in a context where the
|
||||
# returned `MatchData` is not needed.
|
||||
Performance/RedundantMatch:
|
||||
Enabled: false
|
||||
|
||||
# TODO: Enable RedundantMerge Cop.
|
||||
# Use `Hash#[]=`, rather than `Hash#merge!` with a single key-value pair.
|
||||
Performance/RedundantMerge:
|
||||
# Max number of key-value pairs to consider an offense
|
||||
MaxKeyValuePairs: 2
|
||||
Enabled: false
|
||||
|
||||
# Use `sort` instead of `sort_by { |x| x }`.
|
||||
Performance/RedundantSortBy:
|
||||
Enabled: true
|
||||
|
@ -1082,18 +741,6 @@ Rails/ReadWriteAttribute:
|
|||
Rails/ScopeArgs:
|
||||
Enabled: true
|
||||
|
||||
# Checks the correct usage of time zone aware methods.
|
||||
# http://danilenko.org/2012/7/6/rails_timezones
|
||||
Rails/TimeZone:
|
||||
Enabled: false
|
||||
|
||||
# Use validates :attribute, hash of validations.
|
||||
Rails/Validation:
|
||||
Enabled: false
|
||||
|
||||
Rails/UniqBeforePluck:
|
||||
Enabled: false
|
||||
|
||||
##################### RSpec ##################################
|
||||
|
||||
# Check that instances are not being stubbed globally.
|
||||
|
|
462
.rubocop_todo.yml
Normal file
462
.rubocop_todo.yml
Normal file
|
@ -0,0 +1,462 @@
|
|||
# This configuration was generated by
|
||||
# `rubocop --auto-gen-config --exclude-limit 0`
|
||||
# on 2016-07-13 12:36:08 -0600 using RuboCop version 0.41.2.
|
||||
# The point is for the user to remove these configuration records
|
||||
# one by one as the offenses are removed from the code base.
|
||||
# Note that changes in the inspected code, or installation of new
|
||||
# versions of RuboCop, may require this file to be generated again.
|
||||
|
||||
# Offense count: 154
|
||||
Lint/AmbiguousRegexpLiteral:
|
||||
Enabled: false
|
||||
|
||||
# Offense count: 43
|
||||
# Configuration parameters: AllowSafeAssignment.
|
||||
Lint/AssignmentInCondition:
|
||||
Enabled: false
|
||||
|
||||
# Offense count: 14
|
||||
Lint/HandleExceptions:
|
||||
Enabled: false
|
||||
|
||||
# Offense count: 21
|
||||
Lint/IneffectiveAccessModifier:
|
||||
Enabled: false
|
||||
|
||||
# Offense count: 2
|
||||
Lint/Loop:
|
||||
Enabled: false
|
||||
|
||||
# Offense count: 15
|
||||
Lint/ShadowingOuterLocalVariable:
|
||||
Enabled: false
|
||||
|
||||
# Offense count: 3
|
||||
# Cop supports --auto-correct.
|
||||
Lint/StringConversionInInterpolation:
|
||||
Enabled: false
|
||||
|
||||
# Offense count: 44
|
||||
# Cop supports --auto-correct.
|
||||
# Configuration parameters: IgnoreEmptyBlocks, AllowUnusedKeywordArguments.
|
||||
Lint/UnusedBlockArgument:
|
||||
Enabled: false
|
||||
|
||||
# Offense count: 129
|
||||
# Cop supports --auto-correct.
|
||||
# Configuration parameters: AllowUnusedKeywordArguments, IgnoreEmptyMethods.
|
||||
Lint/UnusedMethodArgument:
|
||||
Enabled: false
|
||||
|
||||
# Offense count: 11
|
||||
Lint/UselessAccessModifier:
|
||||
Enabled: false
|
||||
|
||||
# Offense count: 12
|
||||
# Cop supports --auto-correct.
|
||||
Performance/PushSplat:
|
||||
Enabled: false
|
||||
|
||||
# Offense count: 2
|
||||
# Cop supports --auto-correct.
|
||||
Performance/RedundantBlockCall:
|
||||
Enabled: false
|
||||
|
||||
# Offense count: 4
|
||||
# Cop supports --auto-correct.
|
||||
Performance/RedundantMatch:
|
||||
Enabled: false
|
||||
|
||||
# Offense count: 24
|
||||
# Cop supports --auto-correct.
|
||||
# Configuration parameters: MaxKeyValuePairs.
|
||||
Performance/RedundantMerge:
|
||||
Enabled: false
|
||||
|
||||
# Offense count: 60
|
||||
Rails/OutputSafety:
|
||||
Enabled: false
|
||||
|
||||
# Offense count: 128
|
||||
# Configuration parameters: EnforcedStyle, SupportedStyles.
|
||||
# SupportedStyles: strict, flexible
|
||||
Rails/TimeZone:
|
||||
Enabled: false
|
||||
|
||||
# Offense count: 12
|
||||
# Cop supports --auto-correct.
|
||||
# Configuration parameters: Include.
|
||||
# Include: app/models/**/*.rb
|
||||
Rails/Validation:
|
||||
Enabled: false
|
||||
|
||||
# Offense count: 217
|
||||
# Cop supports --auto-correct.
|
||||
# Configuration parameters: EnforcedStyle, SupportedStyles, IndentationWidth.
|
||||
# SupportedStyles: with_first_parameter, with_fixed_indentation
|
||||
Style/AlignParameters:
|
||||
Enabled: false
|
||||
|
||||
# Offense count: 32
|
||||
# Cop supports --auto-correct.
|
||||
# Configuration parameters: EnforcedStyle, SupportedStyles.
|
||||
# SupportedStyles: always, conditionals
|
||||
Style/AndOr:
|
||||
Enabled: false
|
||||
|
||||
# Offense count: 47
|
||||
# Cop supports --auto-correct.
|
||||
# Configuration parameters: EnforcedStyle, SupportedStyles.
|
||||
# SupportedStyles: percent_q, bare_percent
|
||||
Style/BarePercentLiterals:
|
||||
Enabled: false
|
||||
|
||||
# Offense count: 258
|
||||
# Cop supports --auto-correct.
|
||||
# Configuration parameters: EnforcedStyle, SupportedStyles.
|
||||
# SupportedStyles: braces, no_braces, context_dependent
|
||||
Style/BracesAroundHashParameters:
|
||||
Enabled: false
|
||||
|
||||
# Offense count: 5
|
||||
Style/CaseEquality:
|
||||
Enabled: false
|
||||
|
||||
# Offense count: 19
|
||||
# Cop supports --auto-correct.
|
||||
Style/ColonMethodCall:
|
||||
Enabled: false
|
||||
|
||||
# Offense count: 3
|
||||
# Cop supports --auto-correct.
|
||||
# Configuration parameters: Keywords.
|
||||
# Keywords: TODO, FIXME, OPTIMIZE, HACK, REVIEW
|
||||
Style/CommentAnnotation:
|
||||
Enabled: false
|
||||
|
||||
# Offense count: 34
|
||||
# Cop supports --auto-correct.
|
||||
# Configuration parameters: EnforcedStyle, SupportedStyles, SingleLineConditionsOnly.
|
||||
# SupportedStyles: assign_to_condition, assign_inside_condition
|
||||
Style/ConditionalAssignment:
|
||||
Enabled: false
|
||||
|
||||
# Offense count: 789
|
||||
# Cop supports --auto-correct.
|
||||
# Configuration parameters: EnforcedStyle, SupportedStyles.
|
||||
# SupportedStyles: leading, trailing
|
||||
Style/DotPosition:
|
||||
Enabled: false
|
||||
|
||||
# Offense count: 13
|
||||
Style/DoubleNegation:
|
||||
Enabled: false
|
||||
|
||||
# Offense count: 3
|
||||
Style/EachWithObject:
|
||||
Enabled: false
|
||||
|
||||
# Offense count: 30
|
||||
# Cop supports --auto-correct.
|
||||
# Configuration parameters: EnforcedStyle, SupportedStyles.
|
||||
# SupportedStyles: empty, nil, both
|
||||
Style/EmptyElse:
|
||||
Enabled: false
|
||||
|
||||
# Offense count: 3
|
||||
# Cop supports --auto-correct.
|
||||
Style/EmptyLiteral:
|
||||
Enabled: false
|
||||
|
||||
# Offense count: 123
|
||||
# Cop supports --auto-correct.
|
||||
# Configuration parameters: AllowForAlignment, ForceEqualSignAlignment.
|
||||
Style/ExtraSpacing:
|
||||
Enabled: false
|
||||
|
||||
# Offense count: 7
|
||||
# Configuration parameters: EnforcedStyle, SupportedStyles.
|
||||
# SupportedStyles: format, sprintf, percent
|
||||
Style/FormatString:
|
||||
Enabled: false
|
||||
|
||||
# Offense count: 48
|
||||
# Configuration parameters: MinBodyLength.
|
||||
Style/GuardClause:
|
||||
Enabled: false
|
||||
|
||||
# Offense count: 11
|
||||
Style/IfInsideElse:
|
||||
Enabled: false
|
||||
|
||||
# Offense count: 177
|
||||
# Cop supports --auto-correct.
|
||||
# Configuration parameters: MaxLineLength.
|
||||
Style/IfUnlessModifier:
|
||||
Enabled: false
|
||||
|
||||
# Offense count: 52
|
||||
# Cop supports --auto-correct.
|
||||
# Configuration parameters: EnforcedStyle, SupportedStyles, IndentationWidth.
|
||||
# SupportedStyles: special_inside_parentheses, consistent, align_brackets
|
||||
Style/IndentArray:
|
||||
Enabled: false
|
||||
|
||||
# Offense count: 89
|
||||
# Cop supports --auto-correct.
|
||||
# Configuration parameters: EnforcedStyle, SupportedStyles, IndentationWidth.
|
||||
# SupportedStyles: special_inside_parentheses, consistent, align_braces
|
||||
Style/IndentHash:
|
||||
Enabled: false
|
||||
|
||||
# Offense count: 12
|
||||
# Cop supports --auto-correct.
|
||||
# Configuration parameters: EnforcedStyle, SupportedStyles.
|
||||
# SupportedStyles: line_count_dependent, lambda, literal
|
||||
Style/Lambda:
|
||||
Enabled: false
|
||||
|
||||
# Offense count: 6
|
||||
# Cop supports --auto-correct.
|
||||
Style/LineEndConcatenation:
|
||||
Enabled: false
|
||||
|
||||
# Offense count: 13
|
||||
# Cop supports --auto-correct.
|
||||
Style/MethodCallParentheses:
|
||||
Enabled: false
|
||||
|
||||
# Offense count: 3
|
||||
Style/MultilineTernaryOperator:
|
||||
Enabled: false
|
||||
|
||||
# Offense count: 62
|
||||
# Cop supports --auto-correct.
|
||||
Style/MutableConstant:
|
||||
Enabled: false
|
||||
|
||||
# Offense count: 10
|
||||
# Cop supports --auto-correct.
|
||||
Style/NestedParenthesizedCalls:
|
||||
Enabled: false
|
||||
|
||||
# Offense count: 12
|
||||
# Cop supports --auto-correct.
|
||||
# Configuration parameters: EnforcedStyle, MinBodyLength, SupportedStyles.
|
||||
# SupportedStyles: skip_modifier_ifs, always
|
||||
Style/Next:
|
||||
Enabled: false
|
||||
|
||||
# Offense count: 8
|
||||
# Cop supports --auto-correct.
|
||||
# Configuration parameters: EnforcedOctalStyle, SupportedOctalStyles.
|
||||
# SupportedOctalStyles: zero_with_o, zero_only
|
||||
Style/NumericLiteralPrefix:
|
||||
Enabled: false
|
||||
|
||||
# Offense count: 29
|
||||
# Cop supports --auto-correct.
|
||||
Style/ParallelAssignment:
|
||||
Enabled: false
|
||||
|
||||
# Offense count: 208
|
||||
# Cop supports --auto-correct.
|
||||
# Configuration parameters: PreferredDelimiters.
|
||||
Style/PercentLiteralDelimiters:
|
||||
Enabled: false
|
||||
|
||||
# Offense count: 11
|
||||
# Cop supports --auto-correct.
|
||||
# Configuration parameters: EnforcedStyle, SupportedStyles.
|
||||
# SupportedStyles: lower_case_q, upper_case_q
|
||||
Style/PercentQLiterals:
|
||||
Enabled: false
|
||||
|
||||
# Offense count: 13
|
||||
# Cop supports --auto-correct.
|
||||
Style/PerlBackrefs:
|
||||
Enabled: false
|
||||
|
||||
# Offense count: 32
|
||||
# Configuration parameters: NamePrefix, NamePrefixBlacklist, NameWhitelist.
|
||||
# NamePrefix: is_, has_, have_
|
||||
# NamePrefixBlacklist: is_, has_, have_
|
||||
# NameWhitelist: is_a?
|
||||
Style/PredicateName:
|
||||
Enabled: false
|
||||
|
||||
# Offense count: 28
|
||||
# Cop supports --auto-correct.
|
||||
Style/PreferredHashMethods:
|
||||
Enabled: false
|
||||
|
||||
# Offense count: 6
|
||||
# Cop supports --auto-correct.
|
||||
Style/Proc:
|
||||
Enabled: false
|
||||
|
||||
# Offense count: 20
|
||||
# Cop supports --auto-correct.
|
||||
# Configuration parameters: EnforcedStyle, SupportedStyles.
|
||||
# SupportedStyles: compact, exploded
|
||||
Style/RaiseArgs:
|
||||
Enabled: false
|
||||
|
||||
# Offense count: 3
|
||||
# Cop supports --auto-correct.
|
||||
Style/RedundantBegin:
|
||||
Enabled: false
|
||||
|
||||
# Offense count: 1
|
||||
# Cop supports --auto-correct.
|
||||
Style/RedundantException:
|
||||
Enabled: false
|
||||
|
||||
# Offense count: 23
|
||||
# Cop supports --auto-correct.
|
||||
Style/RedundantFreeze:
|
||||
Enabled: false
|
||||
|
||||
# Offense count: 377
|
||||
# Cop supports --auto-correct.
|
||||
Style/RedundantSelf:
|
||||
Enabled: false
|
||||
|
||||
# Offense count: 94
|
||||
# Cop supports --auto-correct.
|
||||
# Configuration parameters: EnforcedStyle, SupportedStyles, AllowInnerSlashes.
|
||||
# SupportedStyles: slashes, percent_r, mixed
|
||||
Style/RegexpLiteral:
|
||||
Enabled: false
|
||||
|
||||
# Offense count: 17
|
||||
# Cop supports --auto-correct.
|
||||
Style/RescueModifier:
|
||||
Enabled: false
|
||||
|
||||
# Offense count: 2
|
||||
# Cop supports --auto-correct.
|
||||
Style/SelfAssignment:
|
||||
Enabled: false
|
||||
|
||||
# Offense count: 2
|
||||
# Configuration parameters: Methods.
|
||||
# Methods: {"reduce"=>["a", "e"]}, {"inject"=>["a", "e"]}
|
||||
Style/SingleLineBlockParams:
|
||||
Enabled: false
|
||||
|
||||
# Offense count: 50
|
||||
# Cop supports --auto-correct.
|
||||
# Configuration parameters: AllowIfMethodIsEmpty.
|
||||
Style/SingleLineMethods:
|
||||
Enabled: false
|
||||
|
||||
# Offense count: 14
|
||||
# Cop supports --auto-correct.
|
||||
# Configuration parameters: EnforcedStyle, SupportedStyles.
|
||||
# SupportedStyles: space, no_space
|
||||
Style/SpaceAroundEqualsInParameterDefault:
|
||||
Enabled: false
|
||||
|
||||
# Offense count: 119
|
||||
# Cop supports --auto-correct.
|
||||
# Configuration parameters: EnforcedStyle, SupportedStyles.
|
||||
# SupportedStyles: space, no_space
|
||||
Style/SpaceBeforeBlockBraces:
|
||||
Enabled: false
|
||||
|
||||
# Offense count: 11
|
||||
# Cop supports --auto-correct.
|
||||
# Configuration parameters: AllowForAlignment.
|
||||
Style/SpaceBeforeFirstArg:
|
||||
Enabled: false
|
||||
|
||||
# Offense count: 130
|
||||
# Cop supports --auto-correct.
|
||||
# Configuration parameters: EnforcedStyle, SupportedStyles, EnforcedStyleForEmptyBraces, SpaceBeforeBlockParameters.
|
||||
# SupportedStyles: space, no_space
|
||||
Style/SpaceInsideBlockBraces:
|
||||
Enabled: false
|
||||
|
||||
# Offense count: 98
|
||||
# Cop supports --auto-correct.
|
||||
Style/SpaceInsideBrackets:
|
||||
Enabled: false
|
||||
|
||||
# Offense count: 60
|
||||
# Cop supports --auto-correct.
|
||||
Style/SpaceInsideParens:
|
||||
Enabled: false
|
||||
|
||||
# Offense count: 5
|
||||
# Cop supports --auto-correct.
|
||||
Style/SpaceInsidePercentLiteralDelimiters:
|
||||
Enabled: false
|
||||
|
||||
# Offense count: 36
|
||||
# Cop supports --auto-correct.
|
||||
# Configuration parameters: SupportedStyles.
|
||||
# SupportedStyles: use_perl_names, use_english_names
|
||||
Style/SpecialGlobalVars:
|
||||
EnforcedStyle: use_perl_names
|
||||
|
||||
# Offense count: 30
|
||||
# Cop supports --auto-correct.
|
||||
# Configuration parameters: EnforcedStyle, SupportedStyles.
|
||||
# SupportedStyles: single_quotes, double_quotes
|
||||
Style/StringLiteralsInInterpolation:
|
||||
Enabled: false
|
||||
|
||||
# Offense count: 24
|
||||
# Cop supports --auto-correct.
|
||||
# Configuration parameters: IgnoredMethods.
|
||||
# IgnoredMethods: respond_to, define_method
|
||||
Style/SymbolProc:
|
||||
Enabled: false
|
||||
|
||||
# Offense count: 23
|
||||
# Cop supports --auto-correct.
|
||||
# Configuration parameters: EnforcedStyleForMultiline, SupportedStyles.
|
||||
# SupportedStyles: comma, consistent_comma, no_comma
|
||||
Style/TrailingCommaInArguments:
|
||||
Enabled: false
|
||||
|
||||
# Offense count: 113
|
||||
# Cop supports --auto-correct.
|
||||
# Configuration parameters: EnforcedStyleForMultiline, SupportedStyles.
|
||||
# SupportedStyles: comma, consistent_comma, no_comma
|
||||
Style/TrailingCommaInLiteral:
|
||||
Enabled: false
|
||||
|
||||
# Offense count: 7
|
||||
# Cop supports --auto-correct.
|
||||
# Configuration parameters: AllowNamedUnderscoreVariables.
|
||||
Style/TrailingUnderscoreVariable:
|
||||
Enabled: false
|
||||
|
||||
# Offense count: 90
|
||||
# Cop supports --auto-correct.
|
||||
Style/TrailingWhitespace:
|
||||
Enabled: false
|
||||
|
||||
# Offense count: 2
|
||||
# Cop supports --auto-correct.
|
||||
# Configuration parameters: ExactNameMatch, AllowPredicates, AllowDSLWriters, IgnoreClassMethods, Whitelist.
|
||||
# Whitelist: to_ary, to_a, to_c, to_enum, to_h, to_hash, to_i, to_int, to_io, to_open, to_path, to_proc, to_r, to_regexp, to_str, to_s, to_sym
|
||||
Style/TrivialAccessors:
|
||||
Enabled: false
|
||||
|
||||
# Offense count: 3
|
||||
# Cop supports --auto-correct.
|
||||
Style/UnlessElse:
|
||||
Enabled: false
|
||||
|
||||
# Offense count: 13
|
||||
# Cop supports --auto-correct.
|
||||
Style/UnneededInterpolation:
|
||||
Enabled: false
|
||||
|
||||
# Offense count: 8
|
||||
# Cop supports --auto-correct.
|
||||
Style/ZeroLengthPredicate:
|
||||
Enabled: false
|
16
CHANGELOG
16
CHANGELOG
|
@ -2,6 +2,7 @@ Please view this file on the master branch, on stable branches it's out of date.
|
|||
|
||||
v 8.10.0 (unreleased)
|
||||
- Expose {should,force}_remove_source_branch (Ben Boeckel)
|
||||
- Disable PostgreSQL statement timeout during migrations
|
||||
- Fix projects dropdown loading performance with a simplified api cal. !5113 (tiagonbotelho)
|
||||
- Fix commit builds API, return all builds for all pipelines for given commit. !4849
|
||||
- Replace Haml with Hamlit to make view rendering faster. !3666
|
||||
|
@ -23,12 +24,15 @@ v 8.10.0 (unreleased)
|
|||
- Add Sidekiq queue duration to transaction metrics.
|
||||
- Add a new column `artifacts_size` to table `ci_builds` !4964
|
||||
- Let Workhorse serve format-patch diffs
|
||||
- Display tooltip for mentioned users and groups !5261 (winniehell)
|
||||
- Added day name to contribution calendar tooltips
|
||||
- Make images fit to the size of the viewport !4810
|
||||
- Fix check for New Branch button on Issue page !4630 (winniehell)
|
||||
- Fix MR-auto-close text added to description. !4836
|
||||
- Support U2F devices in Firefox. !5177
|
||||
- Fix issue, preventing users w/o push access to sort tags !5105 (redetection)
|
||||
- Add Spring EmojiOne updates.
|
||||
- Fix fetching LFS objects for private CI projects
|
||||
- Add syntax for multiline blockquote using `>>>` fence !3954
|
||||
- Fix viewing notification settings when a project is pending deletion
|
||||
- Updated compare dropdown menus to use GL dropdown
|
||||
|
@ -53,12 +57,16 @@ v 8.10.0 (unreleased)
|
|||
- 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
|
||||
- Track a user who created a pipeline
|
||||
- Actually render old and new sections of parallel diff next to each other
|
||||
- Throttle the update of `project.pushes_since_gc` to 1 minute.
|
||||
- Allow expanding and collapsing files in diff view (!4990)
|
||||
- Collapse large diffs by default (!4990)
|
||||
- Fix mentioned users list on diff notes
|
||||
- Fix creation of deployment on build that is retried, redeployed or rollback
|
||||
- Check for conflicts with existing Project's wiki path when creating a new project.
|
||||
- Show last push widget in upstream after push to fork
|
||||
- Fix stage status shown for pipelines
|
||||
- Cache todos pending/done dashboard query counts.
|
||||
- Don't instantiate a git tree on Projects show default view
|
||||
- Bump Rinku to 2.0.0
|
||||
|
@ -79,7 +87,9 @@ v 8.10.0 (unreleased)
|
|||
- Add basic system information like memory and disk usage to the admin panel
|
||||
- Don't garbage collect commits that have related DB records like comments
|
||||
- More descriptive message for git hooks and file locks
|
||||
- Aliases of award emoji should be stored as original name. !5060 (dixpac)
|
||||
- Handle custom Git hook result in GitLab UI
|
||||
- Allow to access Container Registry for Public and Internal projects
|
||||
- Allow '?', or '&' for label names
|
||||
- Fix importer for GitHub Pull Requests when a branch was reused across Pull Requests
|
||||
- Add date when user joined the team on the member page
|
||||
|
@ -95,6 +105,12 @@ v 8.10.0 (unreleased)
|
|||
- Redesign Builds and Pipelines pages
|
||||
- Change status color and icon for running builds
|
||||
- Fix markdown rendering for: consecutive labels references, label references that begin with a digit or contains `.`
|
||||
- Project export filename now includes the project and namespace path
|
||||
- Fix last update timestamp on issues not preserved on gitlab.com and project imports
|
||||
- Fix issues importing projects from EE to CE
|
||||
- Fix creating group with space in group path
|
||||
- Create Todos for Issue author when assign or mention himself (Katarzyna Kobierska)
|
||||
- Limit the number of retries on error to 3 for exporting projects
|
||||
|
||||
v 8.9.6
|
||||
- Fix importing of events under notes for GitLab projects. !5154
|
||||
|
|
8
Gemfile
8
Gemfile
|
@ -61,7 +61,7 @@ gem 'gitlab_omniauth-ldap', '~> 1.2.1', require: 'omniauth-ldap'
|
|||
|
||||
# Git Wiki
|
||||
# Required manually in config/initializers/gollum.rb to control load order
|
||||
gem 'gollum-lib', '~> 4.1.0', require: false
|
||||
gem 'gollum-lib', '~> 4.2', require: false
|
||||
gem 'gollum-rugged_adapter', '~> 0.4.2', require: false
|
||||
|
||||
# Language detection
|
||||
|
@ -105,7 +105,7 @@ gem 'seed-fu', '~> 2.3.5'
|
|||
# Markdown and HTML processing
|
||||
gem 'html-pipeline', '~> 1.11.0'
|
||||
gem 'task_list', '~> 1.0.2', require: 'task_list/railtie'
|
||||
gem 'github-markup', '~> 1.3.1'
|
||||
gem 'github-markup', '~> 1.4'
|
||||
gem 'redcarpet', '~> 3.3.3'
|
||||
gem 'RedCloth', '~> 4.3.2'
|
||||
gem 'rdoc', '~>3.6'
|
||||
|
@ -113,7 +113,7 @@ gem 'org-ruby', '~> 0.9.12'
|
|||
gem 'creole', '~> 0.5.0'
|
||||
gem 'wikicloth', '0.8.1'
|
||||
gem 'asciidoctor', '~> 1.5.2'
|
||||
gem 'rouge', '~> 1.11'
|
||||
gem 'rouge', '~> 2.0'
|
||||
|
||||
# See https://groups.google.com/forum/#!topic/ruby-security-ann/aSbgDiwb24s
|
||||
# and https://groups.google.com/forum/#!topic/ruby-security-ann/Dy7YiKb_pMM
|
||||
|
@ -299,7 +299,7 @@ group :development, :test do
|
|||
gem 'spring-commands-spinach', '~> 1.1.0'
|
||||
gem 'spring-commands-teaspoon', '~> 0.0.2'
|
||||
|
||||
gem 'rubocop', '~> 0.40.0', require: false
|
||||
gem 'rubocop', '~> 0.41.2', require: false
|
||||
gem 'rubocop-rspec', '~> 1.5.0', require: false
|
||||
gem 'scss_lint', '~> 0.47.0', require: false
|
||||
gem 'simplecov', '~> 0.11.0', require: false
|
||||
|
|
30
Gemfile.lock
30
Gemfile.lock
|
@ -58,7 +58,7 @@ GEM
|
|||
faraday_middleware-multi_json (~> 0.0)
|
||||
oauth2 (~> 1.0)
|
||||
asciidoctor (1.5.3)
|
||||
ast (2.2.0)
|
||||
ast (2.3.0)
|
||||
attr_encrypted (3.0.1)
|
||||
encryptor (~> 3.0.0)
|
||||
attr_required (1.0.0)
|
||||
|
@ -264,7 +264,7 @@ GEM
|
|||
escape_utils (~> 1.1.0)
|
||||
mime-types (>= 1.19)
|
||||
rugged (>= 0.23.0b)
|
||||
github-markup (1.3.3)
|
||||
github-markup (1.4.0)
|
||||
gitlab-flowdock-git-hook (1.0.1)
|
||||
flowdock (~> 0.7)
|
||||
gitlab-grit (>= 2.4.1)
|
||||
|
@ -287,13 +287,13 @@ GEM
|
|||
rubyntlm (~> 0.3)
|
||||
globalid (0.3.6)
|
||||
activesupport (>= 4.1.0)
|
||||
gollum-grit_adapter (1.0.0)
|
||||
gollum-grit_adapter (1.0.1)
|
||||
gitlab-grit (~> 2.7, >= 2.7.1)
|
||||
gollum-lib (4.1.0)
|
||||
github-markup (~> 1.3.3)
|
||||
gollum-lib (4.2.1)
|
||||
github-markup (~> 1.4.0)
|
||||
gollum-grit_adapter (~> 1.0)
|
||||
nokogiri (~> 1.6.4)
|
||||
rouge (~> 1.9)
|
||||
rouge (~> 2.0)
|
||||
sanitize (~> 2.1.0)
|
||||
stringex (~> 2.5.1)
|
||||
gollum-rugged_adapter (0.4.2)
|
||||
|
@ -473,7 +473,7 @@ GEM
|
|||
orm_adapter (0.5.0)
|
||||
paranoia (2.1.4)
|
||||
activerecord (~> 4.0)
|
||||
parser (2.3.1.0)
|
||||
parser (2.3.1.2)
|
||||
ast (~> 2.2)
|
||||
pg (0.18.4)
|
||||
pkg-config (1.1.7)
|
||||
|
@ -578,7 +578,7 @@ GEM
|
|||
railties (>= 4.2.0, < 5.1)
|
||||
rinku (2.0.0)
|
||||
rotp (2.1.2)
|
||||
rouge (1.11.0)
|
||||
rouge (2.0.3)
|
||||
rqrcode (0.7.0)
|
||||
chunky_png
|
||||
rqrcode-rails3 (0.1.7)
|
||||
|
@ -606,8 +606,8 @@ GEM
|
|||
rspec-retry (0.4.5)
|
||||
rspec-core
|
||||
rspec-support (3.5.0)
|
||||
rubocop (0.40.0)
|
||||
parser (>= 2.3.1.0, < 3.0)
|
||||
rubocop (0.41.2)
|
||||
parser (>= 2.3.1.1, < 3.0)
|
||||
powerpack (~> 0.1)
|
||||
rainbow (>= 1.99.1, < 3.0)
|
||||
ruby-progressbar (~> 1.7)
|
||||
|
@ -758,7 +758,7 @@ GEM
|
|||
unf (0.1.4)
|
||||
unf_ext
|
||||
unf_ext (0.0.7.2)
|
||||
unicode-display_width (1.0.5)
|
||||
unicode-display_width (1.1.0)
|
||||
unicorn (4.9.0)
|
||||
kgio (~> 2.6)
|
||||
rack
|
||||
|
@ -859,12 +859,12 @@ DEPENDENCIES
|
|||
gemnasium-gitlab-service (~> 0.2)
|
||||
gemojione (~> 2.6)
|
||||
github-linguist (~> 4.7.0)
|
||||
github-markup (~> 1.3.1)
|
||||
github-markup (~> 1.4)
|
||||
gitlab-flowdock-git-hook (~> 1.0.1)
|
||||
gitlab_git (~> 10.2)
|
||||
gitlab_meta (= 7.0)
|
||||
gitlab_omniauth-ldap (~> 1.2.1)
|
||||
gollum-lib (~> 4.1.0)
|
||||
gollum-lib (~> 4.2)
|
||||
gollum-rugged_adapter (~> 0.4.2)
|
||||
gon (~> 6.0.1)
|
||||
grape (~> 0.13.0)
|
||||
|
@ -933,11 +933,11 @@ DEPENDENCIES
|
|||
request_store (~> 1.3.0)
|
||||
rerun (~> 0.11.0)
|
||||
responders (~> 2.0)
|
||||
rouge (~> 1.11)
|
||||
rouge (~> 2.0)
|
||||
rqrcode-rails3 (~> 0.1.7)
|
||||
rspec-rails (~> 3.5.0)
|
||||
rspec-retry (~> 0.4.5)
|
||||
rubocop (~> 0.40.0)
|
||||
rubocop (~> 0.41.2)
|
||||
rubocop-rspec (~> 1.5.0)
|
||||
ruby-fogbugz (~> 0.2.1)
|
||||
sanitize (~> 2.0)
|
||||
|
|
|
@ -53,7 +53,6 @@
|
|||
#= require_directory ./u2f
|
||||
#= require_directory .
|
||||
#= require fuzzaldrin-plus
|
||||
#= require u2f
|
||||
|
||||
window.slugify = (text) ->
|
||||
text.replace(/[^-a-zA-Z0-9]+/g, '_').toLowerCase()
|
||||
|
|
|
@ -39,8 +39,6 @@ class Dispatcher
|
|||
shortcut_handler = new ShortcutsNavigation()
|
||||
new GLForm($('.issue-form'))
|
||||
new IssuableForm($('.issue-form'))
|
||||
new LabelsSelect()
|
||||
new MilestoneSelect()
|
||||
when 'projects:merge_requests:new', 'projects:merge_requests:edit'
|
||||
new Diff()
|
||||
shortcut_handler = new ShortcutsNavigation()
|
||||
|
|
|
@ -184,22 +184,20 @@ class @LabelsSelect
|
|||
.value()
|
||||
|
||||
if $dropdown.hasClass 'js-extra-options'
|
||||
extraData = []
|
||||
if showAny
|
||||
extraData.push(
|
||||
isAny: true
|
||||
title: 'Any Label'
|
||||
)
|
||||
|
||||
if showNo
|
||||
extraData.push(
|
||||
data.unshift(
|
||||
id: 0
|
||||
title: 'No Label'
|
||||
)
|
||||
|
||||
if extraData.length
|
||||
extraData.push 'divider'
|
||||
data = extraData.concat(data)
|
||||
if showAny
|
||||
data.unshift(
|
||||
isAny: true
|
||||
title: 'Any Label'
|
||||
)
|
||||
|
||||
if data.length > 2
|
||||
data.splice 2, 0, 'divider'
|
||||
|
||||
callback data
|
||||
|
||||
|
@ -289,12 +287,6 @@ class @LabelsSelect
|
|||
defaultLabel
|
||||
fieldName: $dropdown.data('field-name')
|
||||
id: (label) ->
|
||||
if $dropdown.hasClass('js-issuable-form-dropdown')
|
||||
if label.id is 0
|
||||
return
|
||||
else
|
||||
return label.id
|
||||
|
||||
if $dropdown.hasClass("js-filter-submit") and not label.isAny?
|
||||
label.title
|
||||
else
|
||||
|
@ -308,9 +300,6 @@ class @LabelsSelect
|
|||
$selectbox.hide()
|
||||
# display:block overrides the hide-collapse rule
|
||||
$value.removeAttr('style')
|
||||
|
||||
return if $dropdown.hasClass('js-issuable-form-dropdown')
|
||||
|
||||
if $dropdown.hasClass 'js-multiselect'
|
||||
if $dropdown.hasClass('js-filter-submit') and (isIssueIndex or isMRIndex)
|
||||
selectedLabels = $dropdown
|
||||
|
@ -332,7 +321,7 @@ class @LabelsSelect
|
|||
clicked: (label) ->
|
||||
_this.enableBulkLabelDropdown()
|
||||
|
||||
if $dropdown.hasClass('js-filter-bulk-update') or $dropdown.hasClass('js-issuable-form-dropdown')
|
||||
if $dropdown.hasClass('js-filter-bulk-update')
|
||||
return
|
||||
|
||||
page = $('body').data 'page'
|
||||
|
|
|
@ -62,7 +62,7 @@ class @MilestoneSelect
|
|||
title: 'Upcoming'
|
||||
)
|
||||
|
||||
if extraOptions.length > 0
|
||||
if extraOptions.length > 2
|
||||
extraOptions.push 'divider'
|
||||
|
||||
callback(extraOptions.concat(data))
|
||||
|
|
|
@ -6,8 +6,20 @@
|
|||
class @U2FAuthenticate
|
||||
constructor: (@container, u2fParams) ->
|
||||
@appId = u2fParams.app_id
|
||||
@challenges = u2fParams.challenges
|
||||
@signRequests = u2fParams.sign_requests
|
||||
@challenge = u2fParams.challenge
|
||||
|
||||
# The U2F Javascript API v1.1 requires a single challenge, with
|
||||
# _no challenges per-request_. The U2F Javascript API v1.0 requires a
|
||||
# challenge per-request, which is done by copying the single challenge
|
||||
# into every request.
|
||||
#
|
||||
# In either case, we don't need the per-request challenges that the server
|
||||
# has generated, so we can remove them.
|
||||
#
|
||||
# Note: The server library fixes this behaviour in (unreleased) version 1.0.0.
|
||||
# This can be removed once we upgrade.
|
||||
# https://github.com/castle/ruby-u2f/commit/103f428071a81cd3d5f80c2e77d522d5029946a4
|
||||
@signRequests = u2fParams.sign_requests.map (request) -> _(request).omit('challenge')
|
||||
|
||||
start: () =>
|
||||
if U2FUtil.isU2FSupported()
|
||||
|
@ -16,7 +28,7 @@ class @U2FAuthenticate
|
|||
@renderNotSupported()
|
||||
|
||||
authenticate: () =>
|
||||
u2f.sign(@appId, @challenges, @signRequests, (response) =>
|
||||
u2f.sign(@appId, @challenge, @signRequests, (response) =>
|
||||
if response.errorCode
|
||||
error = new U2FError(response.errorCode)
|
||||
@renderError(error);
|
||||
|
|
3
app/assets/javascripts/u2f/util.js.coffee
Normal file
3
app/assets/javascripts/u2f/util.js.coffee
Normal file
|
@ -0,0 +1,3 @@
|
|||
class @U2FUtil
|
||||
@isU2FSupported: ->
|
||||
window.u2f
|
|
@ -1,15 +0,0 @@
|
|||
# Helper class for U2F (universal 2nd factor) device registration and authentication.
|
||||
|
||||
class @U2FUtil
|
||||
@isU2FSupported: ->
|
||||
if @testMode
|
||||
true
|
||||
else
|
||||
gon.u2f.browser_supports_u2f
|
||||
|
||||
@enableTestMode: ->
|
||||
@testMode = true
|
||||
|
||||
<% if Rails.env.test? %>
|
||||
U2FUtil.enableTestMode();
|
||||
<% end %>
|
|
@ -155,13 +155,11 @@ class @UsersSelect
|
|||
# display:block overrides the hide-collapse rule
|
||||
$value.css('display', '')
|
||||
|
||||
clicked: (user, $el, e) ->
|
||||
clicked: (user) ->
|
||||
page = $('body').data 'page'
|
||||
isIssueIndex = page is 'projects:issues:index'
|
||||
isMRIndex = page is page is 'projects:merge_requests:index'
|
||||
if $dropdown.hasClass('js-filter-bulk-update') or $dropdown.hasClass('js-issuable-form-dropdown')
|
||||
e.preventDefault()
|
||||
selectedId = user.id
|
||||
if $dropdown.hasClass('js-filter-bulk-update')
|
||||
return
|
||||
|
||||
if $dropdown.hasClass('js-filter-submit') and (isIssueIndex or isMRIndex)
|
||||
|
@ -174,8 +172,7 @@ class @UsersSelect
|
|||
.closest('.selectbox')
|
||||
.find("input[name='#{$dropdown.data('field-name')}']").val()
|
||||
assignTo(selected)
|
||||
id: (user) ->
|
||||
user.id
|
||||
|
||||
renderRow: (user) ->
|
||||
username = if user.username then "@#{user.username}" else ""
|
||||
avatar = if user.avatar_url then user.avatar_url else false
|
||||
|
|
|
@ -56,7 +56,7 @@
|
|||
position: absolute;
|
||||
top: 50%;
|
||||
right: 6px;
|
||||
margin-top: -6px;
|
||||
margin-top: -4px;
|
||||
color: $dropdown-toggle-icon-color;
|
||||
font-size: 10px;
|
||||
}
|
||||
|
|
|
@ -324,10 +324,6 @@
|
|||
.issuable-form-select-holder {
|
||||
display: inline-block;
|
||||
width: 250px;
|
||||
|
||||
.dropdown-menu-toggle {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.table-holder {
|
||||
|
|
|
@ -129,6 +129,8 @@
|
|||
}
|
||||
|
||||
.cancel-retry-btns {
|
||||
vertical-align: middle;
|
||||
|
||||
.btn:not(:first-child) {
|
||||
margin-left: 8px;
|
||||
}
|
||||
|
|
|
@ -344,10 +344,6 @@ class ApplicationController < ActionController::Base
|
|||
session[:skip_tfa] && session[:skip_tfa] > Time.current
|
||||
end
|
||||
|
||||
def browser_supports_u2f?
|
||||
browser.chrome? && browser.version.to_i >= 41 && !browser.device.mobile?
|
||||
end
|
||||
|
||||
def redirect_to_home_page_url?
|
||||
# If user is not signed-in and tries to access root_path - redirect him to landing page
|
||||
# Don't redirect to the default URL to prevent endless redirections
|
||||
|
|
|
@ -57,7 +57,7 @@ module AuthenticatesWithTwoFactor
|
|||
|
||||
# Authenticate using the response from a U2F (universal 2nd factor) device
|
||||
def authenticate_with_two_factor_via_u2f(user)
|
||||
if U2fRegistration.authenticate(user, u2f_app_id, user_params[:device_response], session[:challenges])
|
||||
if U2fRegistration.authenticate(user, u2f_app_id, user_params[:device_response], session[:challenge])
|
||||
# Remove any lingering user data from login
|
||||
session.delete(:otp_user_id)
|
||||
session.delete(:challenges)
|
||||
|
@ -77,11 +77,9 @@ module AuthenticatesWithTwoFactor
|
|||
|
||||
if key_handles.present?
|
||||
sign_requests = u2f.authentication_requests(key_handles)
|
||||
challenges = sign_requests.map(&:challenge)
|
||||
session[:challenges] = challenges
|
||||
gon.push(u2f: { challenges: challenges, app_id: u2f_app_id,
|
||||
sign_requests: sign_requests,
|
||||
browser_supports_u2f: browser_supports_u2f? })
|
||||
session[:challenge] ||= u2f.challenge
|
||||
gon.push(u2f: { challenge: session[:challenge], app_id: u2f_app_id,
|
||||
sign_requests: sign_requests })
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -100,7 +100,6 @@ class Profiles::TwoFactorAuthsController < Profiles::ApplicationController
|
|||
|
||||
gon.push(u2f: { challenges: session[:challenges], app_id: u2f_app_id,
|
||||
register_requests: registration_requests,
|
||||
sign_requests: sign_requests,
|
||||
browser_supports_u2f: browser_supports_u2f? })
|
||||
sign_requests: sign_requests })
|
||||
end
|
||||
end
|
||||
|
|
|
@ -119,10 +119,6 @@ class Projects::IssuesController < Projects::ApplicationController
|
|||
render json: @issue.to_json(include: { milestone: {}, assignee: { methods: :avatar_url }, labels: { methods: :text_color } })
|
||||
end
|
||||
end
|
||||
|
||||
rescue ActiveRecord::StaleObjectError
|
||||
@conflict = true
|
||||
render :edit
|
||||
end
|
||||
|
||||
def referenced_merge_requests
|
||||
|
@ -220,7 +216,7 @@ class Projects::IssuesController < Projects::ApplicationController
|
|||
def issue_params
|
||||
params.require(:issue).permit(
|
||||
:title, :assignee_id, :position, :description, :confidential,
|
||||
:milestone_id, :due_date, :state_event, :task_num, :lock_version, label_ids: []
|
||||
:milestone_id, :due_date, :state_event, :task_num, label_ids: []
|
||||
)
|
||||
end
|
||||
|
||||
|
|
|
@ -196,9 +196,6 @@ class Projects::MergeRequestsController < Projects::ApplicationController
|
|||
else
|
||||
render "edit"
|
||||
end
|
||||
rescue ActiveRecord::StaleObjectError
|
||||
@conflict = true
|
||||
render :edit
|
||||
end
|
||||
|
||||
def remove_wip
|
||||
|
@ -427,7 +424,7 @@ class Projects::MergeRequestsController < Projects::ApplicationController
|
|||
:title, :assignee_id, :source_project_id, :source_branch,
|
||||
:target_project_id, :target_branch, :milestone_id,
|
||||
:state_event, :description, :task_num, :force_remove_source_branch,
|
||||
:lock_version, label_ids: []
|
||||
label_ids: []
|
||||
)
|
||||
end
|
||||
|
||||
|
|
|
@ -1,10 +1,7 @@
|
|||
module BlobHelper
|
||||
def highlighter(blob_name, blob_content, repository: nil, nowrap: false)
|
||||
Gitlab::Highlight.new(blob_name, blob_content, nowrap: nowrap, repository: repository)
|
||||
end
|
||||
|
||||
def highlight(blob_name, blob_content, repository: nil, nowrap: false, plain: false)
|
||||
Gitlab::Highlight.highlight(blob_name, blob_content, nowrap: nowrap, plain: plain, repository: repository)
|
||||
def highlight(blob_name, blob_content, repository: nil, plain: false)
|
||||
highlighted = Gitlab::Highlight.highlight(blob_name, blob_content, plain: plain, repository: repository)
|
||||
raw %(<pre class="code highlight"><code>#{highlighted}</code></pre>)
|
||||
end
|
||||
|
||||
def no_highlight_files
|
||||
|
|
|
@ -9,7 +9,7 @@ module IssuablesHelper
|
|||
|
||||
def multi_label_name(current_labels, default_label)
|
||||
# current_labels may be a string from before
|
||||
if current_labels.is_a?(Array) && current_labels.any?
|
||||
if current_labels.is_a?(Array)
|
||||
if current_labels.count > 1
|
||||
"#{current_labels[0]} +#{current_labels.count - 1} more"
|
||||
else
|
||||
|
|
5
app/helpers/u2f_helper.rb
Normal file
5
app/helpers/u2f_helper.rb
Normal file
|
@ -0,0 +1,5 @@
|
|||
module U2fHelper
|
||||
def inject_u2f_api?
|
||||
browser.chrome? && browser.version.to_i >= 41 && !browser.device.mobile?
|
||||
end
|
||||
end
|
|
@ -204,7 +204,8 @@ class Ability
|
|||
:download_code,
|
||||
:fork_project,
|
||||
:read_commit_status,
|
||||
:read_pipeline
|
||||
:read_pipeline,
|
||||
:read_container_image
|
||||
]
|
||||
end
|
||||
|
||||
|
|
|
@ -56,6 +56,7 @@ module Ci
|
|||
new_build.yaml_variables = build.yaml_variables
|
||||
new_build.when = build.when
|
||||
new_build.user = user
|
||||
new_build.environment = build.environment
|
||||
new_build.save
|
||||
MergeRequests::AddTodoWhenBuildFailsService.new(build.project, nil).close(new_build)
|
||||
new_build
|
||||
|
|
|
@ -6,6 +6,8 @@ module Ci
|
|||
self.table_name = 'ci_commits'
|
||||
|
||||
belongs_to :project, class_name: '::Project', foreign_key: :gl_project_id
|
||||
belongs_to :user
|
||||
|
||||
has_many :statuses, class_name: 'CommitStatus', foreign_key: :commit_id
|
||||
has_many :builds, class_name: 'Ci::Build', foreign_key: :commit_id
|
||||
has_many :trigger_requests, dependent: :destroy, class_name: 'Ci::TriggerRequest', foreign_key: :commit_id
|
||||
|
@ -215,6 +217,8 @@ module Ci
|
|||
end
|
||||
|
||||
def keep_around_commits
|
||||
return unless project
|
||||
|
||||
project.repository.keep_around(self.sha)
|
||||
project.repository.keep_around(self.before_sha)
|
||||
end
|
||||
|
|
|
@ -65,8 +65,7 @@ module Awardable
|
|||
|
||||
def create_award_emoji(name, current_user)
|
||||
return unless emoji_awardable?
|
||||
|
||||
award_emoji.create(name: name, user: current_user)
|
||||
award_emoji.create(name: normalize_name(name), user: current_user)
|
||||
end
|
||||
|
||||
def remove_award_emoji(name, current_user)
|
||||
|
@ -80,4 +79,10 @@ module Awardable
|
|||
create_award_emoji(emoji_name, current_user)
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def normalize_name(name)
|
||||
Gitlab::AwardEmoji.normalize_emoji_name(name)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -87,12 +87,6 @@ module Issuable
|
|||
User.find(assignee_id_was).update_cache_counts if assignee_id_was
|
||||
assignee.update_cache_counts if assignee
|
||||
end
|
||||
|
||||
# We want to use optimistic lock for cases when only title or description are involved
|
||||
# http://api.rubyonrails.org/classes/ActiveRecord/Locking/Optimistic.html
|
||||
def locking_enabled?
|
||||
title_changed? || description_changed?
|
||||
end
|
||||
end
|
||||
|
||||
module ClassMethods
|
||||
|
|
|
@ -14,14 +14,14 @@ module Mentionable
|
|||
attr = attr.to_s
|
||||
mentionable_attrs << [attr, options]
|
||||
end
|
||||
|
||||
# Accessor for attributes marked mentionable.
|
||||
def mentionable_attrs
|
||||
@mentionable_attrs ||= []
|
||||
end
|
||||
end
|
||||
|
||||
included do
|
||||
# Accessor for attributes marked mentionable.
|
||||
cattr_accessor :mentionable_attrs, instance_accessor: false do
|
||||
[]
|
||||
end
|
||||
|
||||
if self < Participable
|
||||
participant -> (user, ext) { all_references(user, extractor: ext) }
|
||||
end
|
||||
|
|
|
@ -41,9 +41,12 @@ module Participable
|
|||
def participant(attr)
|
||||
participant_attrs << attr
|
||||
end
|
||||
end
|
||||
|
||||
def participant_attrs
|
||||
@participant_attrs ||= []
|
||||
included do
|
||||
# Accessor for participant attributes.
|
||||
cattr_accessor :participant_attrs, instance_accessor: false do
|
||||
[]
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -38,7 +38,7 @@ class LegacyDiffNote < Note
|
|||
end
|
||||
|
||||
def diff_line
|
||||
@diff_line ||= diff_file.line_for_line_code(self.line_code)
|
||||
@diff_line ||= diff_file.line_for_line_code(self.line_code) if diff_file
|
||||
end
|
||||
|
||||
def for_line?(line)
|
||||
|
@ -55,7 +55,7 @@ class LegacyDiffNote < Note
|
|||
def active?
|
||||
return @active if defined?(@active)
|
||||
return true if for_commit?
|
||||
return true unless self.diff
|
||||
return true unless diff_line
|
||||
return false unless noteable
|
||||
|
||||
noteable_diff = find_noteable_diff
|
||||
|
|
|
@ -229,8 +229,7 @@ class Note < ActiveRecord::Base
|
|||
end
|
||||
|
||||
def award_emoji_name
|
||||
original_name = note.match(Banzai::Filter::EmojiFilter.emoji_pattern)[1]
|
||||
Gitlab::AwardEmoji.normalize_emoji_name(original_name)
|
||||
note.match(Banzai::Filter::EmojiFilter.emoji_pattern)[1]
|
||||
end
|
||||
|
||||
private
|
||||
|
|
|
@ -162,7 +162,7 @@ class Project < ActiveRecord::Base
|
|||
validates :namespace, presence: true
|
||||
validates_uniqueness_of :name, scope: :namespace_id
|
||||
validates_uniqueness_of :path, scope: :namespace_id
|
||||
validates :import_url, addressable_url: true, if: :import_url
|
||||
validates :import_url, addressable_url: true, if: :external_import?
|
||||
validates :star_count, numericality: { greater_than_or_equal_to: 0 }
|
||||
validate :check_limit, on: :create
|
||||
validate :avatar_type,
|
||||
|
@ -482,7 +482,7 @@ class Project < ActiveRecord::Base
|
|||
end
|
||||
|
||||
def create_or_update_import_data(data: nil, credentials: nil)
|
||||
return unless valid_import_url?
|
||||
return unless import_url.present? && valid_import_url?
|
||||
|
||||
project_import_data = import_data || build_import_data
|
||||
if data
|
||||
|
@ -1038,8 +1038,8 @@ class Project < ActiveRecord::Base
|
|||
pipelines.order(id: :desc).find_by(sha: sha, ref: ref)
|
||||
end
|
||||
|
||||
def ensure_pipeline(sha, ref)
|
||||
pipeline(sha, ref) || pipelines.create(sha: sha, ref: ref)
|
||||
def ensure_pipeline(sha, ref, current_user = nil)
|
||||
pipeline(sha, ref) || pipelines.create(sha: sha, ref: ref, user: current_user)
|
||||
end
|
||||
|
||||
def enable_ci
|
||||
|
|
|
@ -85,6 +85,7 @@ class User < ActiveRecord::Base
|
|||
has_one :abuse_report, dependent: :destroy
|
||||
has_many :spam_logs, dependent: :destroy
|
||||
has_many :builds, dependent: :nullify, class_name: 'Ci::Build'
|
||||
has_many :pipelines, dependent: :nullify, class_name: 'Ci::Pipeline'
|
||||
has_many :todos, dependent: :destroy
|
||||
has_many :notification_settings, dependent: :destroy
|
||||
has_many :award_emoji, dependent: :destroy
|
||||
|
|
|
@ -2,6 +2,7 @@ module Ci
|
|||
class CreatePipelineService < BaseService
|
||||
def execute
|
||||
pipeline = project.pipelines.new(params)
|
||||
pipeline.user = current_user
|
||||
|
||||
unless ref_names.include?(params[:ref])
|
||||
pipeline.errors.add(:base, 'Reference not found')
|
||||
|
|
|
@ -14,7 +14,13 @@ class CreateCommitBuildsService
|
|||
return false
|
||||
end
|
||||
|
||||
@pipeline = Ci::Pipeline.new(project: project, sha: sha, ref: ref, before_sha: before_sha, tag: tag)
|
||||
@pipeline = Ci::Pipeline.new(
|
||||
project: project,
|
||||
sha: sha,
|
||||
ref: ref,
|
||||
before_sha: before_sha,
|
||||
tag: tag,
|
||||
user: user)
|
||||
|
||||
##
|
||||
# Skip creating pipeline if no gitlab-ci.yml is found
|
||||
|
|
|
@ -8,7 +8,6 @@ module Notes
|
|||
if note.award_emoji?
|
||||
noteable = note.noteable
|
||||
todo_service.new_award_emoji(noteable, current_user)
|
||||
|
||||
return noteable.create_award_emoji(note.award_emoji_name, current_user)
|
||||
end
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@ module Projects
|
|||
|
||||
def save_all
|
||||
if [version_saver, project_tree_saver, uploads_saver, repo_saver, wiki_repo_saver].all?(&:save)
|
||||
Gitlab::ImportExport::Saver.save(shared: @shared)
|
||||
Gitlab::ImportExport::Saver.save(project: project, shared: @shared)
|
||||
notify_success
|
||||
else
|
||||
cleanup_and_notify
|
||||
|
|
|
@ -194,7 +194,7 @@ class TodoService
|
|||
end
|
||||
|
||||
def create_assignment_todo(issuable, author)
|
||||
if issuable.assignee && issuable.assignee != author
|
||||
if issuable.assignee
|
||||
attributes = attributes_for_todo(issuable.project, issuable, author, Todo::ASSIGNED)
|
||||
create_todos(issuable.assignee, attributes)
|
||||
end
|
||||
|
@ -239,7 +239,6 @@ class TodoService
|
|||
def filter_mentioned_users(project, target, author)
|
||||
mentioned_users = target.mentioned_users(author)
|
||||
mentioned_users = reject_users_without_access(mentioned_users, project, target)
|
||||
mentioned_users.delete(author)
|
||||
mentioned_users.uniq
|
||||
end
|
||||
|
||||
|
|
|
@ -1,3 +1,7 @@
|
|||
- if inject_u2f_api?
|
||||
- content_for :page_specific_javascripts do
|
||||
= page_specific_javascript_tag('u2f.js')
|
||||
|
||||
%div
|
||||
.login-box
|
||||
.login-heading
|
||||
|
|
|
@ -44,7 +44,7 @@
|
|||
name: "#{j(@project.name)}"
|
||||
};
|
||||
|
||||
- if @group and @group.path
|
||||
- if @group && @group.persisted? && @group.path
|
||||
:javascript
|
||||
gl.groupOptions = gl.groupOptions || {};
|
||||
gl.groupOptions["#{j(@group.path)}"] = {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
- if @note.diff_note?
|
||||
- if @note.diff_note? && @note.diff_file
|
||||
%p.details
|
||||
New comment on diff for
|
||||
= link_to @note.diff_file.file_path, @target_url
|
||||
|
|
|
@ -2,6 +2,10 @@
|
|||
- header_title "Two-Factor Authentication", profile_two_factor_auth_path
|
||||
= render 'profiles/head'
|
||||
|
||||
- if inject_u2f_api?
|
||||
- content_for :page_specific_javascripts do
|
||||
= page_specific_javascript_tag('u2f.js')
|
||||
|
||||
.row.prepend-top-default
|
||||
.col-lg-3
|
||||
%h4.prepend-top-0
|
||||
|
|
|
@ -32,7 +32,7 @@
|
|||
Cant find HEAD commit for this branch
|
||||
|
||||
|
||||
- stages_status = pipeline.statuses.stages_status
|
||||
- stages_status = pipeline.statuses.latest.stages_status
|
||||
- stages.each do |stage|
|
||||
%td
|
||||
- status = stages_status[stage]
|
||||
|
@ -58,16 +58,7 @@
|
|||
.controls.hidden-xs.pull-right
|
||||
- artifacts = pipeline.builds.latest.select { |b| b.artifacts? }
|
||||
- if artifacts.present?
|
||||
.btn-group.inline
|
||||
.btn-group
|
||||
%a.dropdown-toggle.btn.btn-default{type: 'button', 'data-toggle' => 'dropdown'}
|
||||
= icon("play")
|
||||
%b.caret
|
||||
%ul.dropdown-menu.dropdown-menu-align-right
|
||||
%li
|
||||
= link_to '#' do
|
||||
= icon("play")
|
||||
%span Deploy to production
|
||||
.inline
|
||||
.btn-group
|
||||
%a.dropdown-toggle.btn.btn-default.build-artifacts{type: 'button', 'data-toggle' => 'dropdown'}
|
||||
= icon("download")
|
||||
|
@ -80,7 +71,7 @@
|
|||
%span Download '#{build.name}' artifacts
|
||||
|
||||
- if can?(current_user, :update_pipeline, @project)
|
||||
.cancel-retry-btns
|
||||
.cancel-retry-btns.inline
|
||||
- if pipeline.retryable?
|
||||
= link_to retry_namespace_project_pipeline_path(@project.namespace, @project, pipeline.id), class: 'btn has-tooltip', title: "Retry", method: :post do
|
||||
= icon("repeat")
|
||||
|
|
|
@ -21,10 +21,10 @@
|
|||
placeholder: "Search assignee", data: { any_user: "Any Assignee", first_user: (current_user.username if current_user), null_user: true, current_user: true, project_id: (@project.id if @project), selected: params[:assignee_id], field_name: "assignee_id", default_label: "Assignee" } })
|
||||
|
||||
.filter-item.inline.milestone-filter
|
||||
= render "shared/issuable/milestone_dropdown", selected: params[:milestone_title], name: :milestone_title, show_any: true, show_upcoming: true
|
||||
= render "shared/issuable/milestone_dropdown"
|
||||
|
||||
.filter-item.inline.labels-filter
|
||||
= render "shared/issuable/label_dropdown", selected: params[:label_name], data_options: { field_name: "label_name[]" }
|
||||
= render "shared/issuable/label_dropdown"
|
||||
|
||||
.pull-right
|
||||
= render 'shared/sort_dropdown'
|
||||
|
|
|
@ -1,12 +1,5 @@
|
|||
= form_errors(issuable)
|
||||
|
||||
- if @conflict
|
||||
.alert.alert-danger
|
||||
Someone edited the #{issuable.class.model_name.human.downcase} the same time you did.
|
||||
Please check out
|
||||
= link_to "the #{issuable.class.model_name.human.downcase}", polymorphic_path([@project.namespace.becomes(Namespace), @project, issuable]), target: "_blank"
|
||||
and make sure your changes will not unintentionally remove theirs
|
||||
|
||||
.form-group
|
||||
= f.label :title, class: 'control-label'
|
||||
.col-sm-10
|
||||
|
@ -59,24 +52,38 @@
|
|||
= f.label :assignee_id, "Assignee", class: "control-label #{"col-lg-4" if has_due_date}"
|
||||
.col-sm-10{ class: ("col-lg-8" if has_due_date) }
|
||||
.issuable-form-select-holder
|
||||
- project = @target_project || @project
|
||||
- if issuable.assignee_id
|
||||
= hidden_field_tag("#{issuable.class.model_name.param_key}[assignee_id]", issuable.assignee_id)
|
||||
= dropdown_tag(user_dropdown_label(issuable.assignee_id, "Assignee"), options: { toggle_class: "js-user-search js-issuable-form-dropdown js-assignee-search", title: "Filter by assignee", filter: true, dropdown_class: "dropdown-menu-user dropdown-menu-selectable dropdown-menu-assignee js-filter-submit",
|
||||
placeholder: "Search assignee", data: { first_user: (current_user.username if current_user), null_user: true, current_user: true, project_id: (project.id if project), selected: issuable.assignee_id, field_name: "#{issuable.class.model_name.param_key}[assignee_id]", default_label: "Assignee" } })
|
||||
= users_select_tag("#{issuable.class.model_name.param_key}[assignee_id]",
|
||||
placeholder: 'Select assignee', class: 'custom-form-control', null_user: true,
|
||||
selected: issuable.assignee_id, project: @target_project || @project,
|
||||
first_user: true, current_user: true, include_blank: true)
|
||||
%div
|
||||
= link_to 'Assign to me', '#', class: 'assign-to-me-link prepend-top-5 inline'
|
||||
.form-group.issue-milestone
|
||||
= f.label :milestone_id, "Milestone", class: "control-label #{"col-lg-4" if has_due_date}"
|
||||
.col-sm-10{ class: ("col-lg-8" if has_due_date) }
|
||||
.issuable-form-select-holder
|
||||
= render "shared/issuable/milestone_dropdown", selected: issuable.milestone_id, name: "#{issuable.class.model_name.param_key}[milestone_id]", show_any: false, show_upcoming: false
|
||||
- if milestone_options(issuable).present?
|
||||
.issuable-form-select-holder
|
||||
= f.select(:milestone_id, milestone_options(issuable),
|
||||
{ include_blank: true }, { class: 'select2', data: { placeholder: 'Select milestone' } })
|
||||
- else
|
||||
.prepend-top-10
|
||||
%span.light No open milestones available.
|
||||
- if can? current_user, :admin_milestone, issuable.project
|
||||
%div
|
||||
= link_to 'Create new milestone', new_namespace_project_milestone_path(issuable.project.namespace, issuable.project), target: :blank, class: "prepend-top-5 inline"
|
||||
.form-group
|
||||
- has_labels = issuable.project.labels.any?
|
||||
- selected_labels = issuable.label_ids.any? ? issuable.label_ids : nil
|
||||
- label_dropdown_toggle = issuable.labels.map { |label| label.title }
|
||||
= f.label :label_ids, "Labels", class: "control-label #{"col-lg-4" if has_due_date}"
|
||||
.col-sm-10{ class: "#{"col-lg-8" if has_due_date} #{'issuable-form-padding-top' if !has_labels}" }
|
||||
.issuable-form-select-holder
|
||||
= render "shared/issuable/label_dropdown", classes: ["js-issuable-form-dropdown"], selected: selected_labels, selected_toggle: label_dropdown_toggle, data_options: { field_name: "#{issuable.class.model_name.param_key}[label_ids][]", show_any: "false" }
|
||||
- if has_labels
|
||||
.issuable-form-select-holder
|
||||
= f.collection_select :label_ids, issuable.project.labels.all, :id, :name,
|
||||
{ selected: issuable.label_ids }, multiple: true, class: 'select2', data: { placeholder: "Select labels" }
|
||||
- else
|
||||
%span.light No labels yet.
|
||||
- if can? current_user, :admin_label, issuable.project
|
||||
%div
|
||||
= link_to 'Create new label', new_namespace_project_label_path(issuable.project.namespace, issuable.project), target: :blank, class: "prepend-top-5 inline"
|
||||
- if has_due_date
|
||||
.col-lg-6
|
||||
.form-group
|
||||
|
@ -142,5 +149,3 @@
|
|||
= link_to 'Delete', polymorphic_path([@project.namespace.becomes(Namespace), @project, issuable]), data: { confirm: "#{issuable.class.name.titleize} will be removed! Are you sure?" },
|
||||
method: :delete, class: 'btn btn-danger btn-grouped'
|
||||
= link_to 'Cancel', polymorphic_path([@project.namespace.becomes(Namespace), @project, issuable]), class: 'btn btn-grouped btn-cancel'
|
||||
|
||||
= f.hidden_field :lock_version
|
||||
|
|
|
@ -4,21 +4,19 @@
|
|||
- show_footer = local_assigns.fetch(:show_footer, true)
|
||||
- data_options = local_assigns.fetch(:data_options, {})
|
||||
- classes = local_assigns.fetch(:classes, [])
|
||||
- selected = local_assigns.fetch(:selected, nil)
|
||||
- selected_toggle = local_assigns.fetch(:selected_toggle, nil)
|
||||
- dropdown_data = {toggle: 'dropdown', field_name: "label_name[]", show_no: "true", show_any: "true", selected: selected, project_id: @project.try(:id), labels: labels_filter_path, default_label: "Label"}
|
||||
- dropdown_data = {toggle: 'dropdown', field_name: 'label_name[]', show_no: "true", show_any: "true", selected: params[:label_name], project_id: @project.try(:id), labels: labels_filter_path, default_label: "Label"}
|
||||
- dropdown_data.merge!(data_options)
|
||||
- classes << 'js-extra-options' if extra_options
|
||||
- classes << 'js-filter-submit' if filter_submit
|
||||
|
||||
- if selected.present?
|
||||
- if selected.respond_to?('any?')
|
||||
- selected.each do |label|
|
||||
= hidden_field_tag data_options[:field_name], label, id: nil
|
||||
- if params[:label_name].present?
|
||||
- if params[:label_name].respond_to?('any?')
|
||||
- params[:label_name].each do |label|
|
||||
= hidden_field_tag "label_name[]", label, id: nil
|
||||
.dropdown
|
||||
%button.dropdown-menu-toggle.js-label-select.js-multiselect{class: classes.join(' '), type: "button", data: dropdown_data}
|
||||
%span.dropdown-toggle-text
|
||||
= h(multi_label_name(selected_toggle || selected, "Label"))
|
||||
= h(multi_label_name(params[:label_name], "Label"))
|
||||
= icon('chevron-down')
|
||||
.dropdown-menu.dropdown-select.dropdown-menu-paging.dropdown-menu-labels.dropdown-menu-selectable
|
||||
= render partial: "shared/issuable/label_page_default", locals: { title: "Filter by label", show_footer: show_footer, show_create: show_create }
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
- if selected.present?
|
||||
= hidden_field_tag(name, selected)
|
||||
= dropdown_tag(milestone_dropdown_label(selected), options: { title: "Filter by milestone", toggle_class: 'js-milestone-select js-filter-submit', filter: true, dropdown_class: "dropdown-menu-selectable",
|
||||
placeholder: "Search milestones", footer_content: @project.present?, data: { show_no: true, show_any: show_any, show_upcoming: show_upcoming, field_name: name, selected: selected, project_id: @project.try(:id), milestones: milestones_filter_dropdown_path, default_label: "Milestone" } }) do
|
||||
- if params[:milestone_title].present?
|
||||
= hidden_field_tag(:milestone_title, params[:milestone_title])
|
||||
= dropdown_tag(milestone_dropdown_label(params[:milestone_title]), options: { title: "Filter by milestone", toggle_class: 'js-milestone-select js-filter-submit', filter: true, dropdown_class: "dropdown-menu-selectable",
|
||||
placeholder: "Search milestones", footer_content: @project.present?, data: { show_no: true, show_any: true, show_upcoming: true, field_name: "milestone_title", selected: params[:milestone_title], project_id: @project.try(:id), milestones: milestones_filter_dropdown_path, default_label: "Milestone" } }) do
|
||||
- if @project
|
||||
%ul.dropdown-footer-list
|
||||
- if can? current_user, :admin_milestone, @project
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
class ProjectExportWorker
|
||||
include Sidekiq::Worker
|
||||
|
||||
sidekiq_options queue: :gitlab_shell, retry: true
|
||||
sidekiq_options queue: :gitlab_shell, retry: 3
|
||||
|
||||
def perform(current_user_id, project_id)
|
||||
current_user = User.find(current_user_id)
|
||||
|
|
|
@ -87,6 +87,7 @@ module Gitlab
|
|||
config.assets.precompile << "profile/application.js"
|
||||
config.assets.precompile << "lib/utils/*.js"
|
||||
config.assets.precompile << "lib/*.js"
|
||||
config.assets.precompile << "u2f.js"
|
||||
|
||||
# Version of your assets, change this if you want to expire all your assets
|
||||
config.assets.version = '1.0'
|
||||
|
|
|
@ -1,17 +0,0 @@
|
|||
# See http://doc.gitlab.com/ce/development/migration_style_guide.html
|
||||
# for more information on how to write migrations for GitLab.
|
||||
|
||||
class AddLockToIssuables < ActiveRecord::Migration
|
||||
include Gitlab::Database::MigrationHelpers
|
||||
disable_ddl_transaction!
|
||||
|
||||
def up
|
||||
add_column_with_default :issues, :lock_version, :integer, default: 0
|
||||
add_column_with_default :merge_requests, :lock_version, :integer, default: 0
|
||||
end
|
||||
|
||||
def down
|
||||
remove_column :issues, :lock_version
|
||||
remove_column :merge_requests, :lock_version
|
||||
end
|
||||
end
|
7
db/migrate/20160715132507_add_user_id_to_pipeline.rb
Normal file
7
db/migrate/20160715132507_add_user_id_to_pipeline.rb
Normal file
|
@ -0,0 +1,7 @@
|
|||
class AddUserIdToPipeline < ActiveRecord::Migration
|
||||
include Gitlab::Database::MigrationHelpers
|
||||
|
||||
def change
|
||||
add_column :ci_commits, :user_id, :integer
|
||||
end
|
||||
end
|
|
@ -0,0 +1,7 @@
|
|||
class AddIndexForPipelineUserId < ActiveRecord::Migration
|
||||
include Gitlab::Database::MigrationHelpers
|
||||
|
||||
def change
|
||||
add_concurrent_index :ci_commits, :user_id
|
||||
end
|
||||
end
|
24
db/schema.rb
24
db/schema.rb
|
@ -70,11 +70,11 @@ ActiveRecord::Schema.define(version: 20160716115710) do
|
|||
t.string "recaptcha_site_key"
|
||||
t.string "recaptcha_private_key"
|
||||
t.integer "metrics_port", default: 8089
|
||||
t.boolean "akismet_enabled", default: false
|
||||
t.string "akismet_api_key"
|
||||
t.integer "metrics_sample_interval", default: 15
|
||||
t.boolean "sentry_enabled", default: false
|
||||
t.string "sentry_dsn"
|
||||
t.boolean "akismet_enabled", default: false
|
||||
t.string "akismet_api_key"
|
||||
t.boolean "email_author_in_body", default: false
|
||||
t.integer "default_group_visibility"
|
||||
t.boolean "repository_checks_enabled", default: false
|
||||
|
@ -84,10 +84,10 @@ ActiveRecord::Schema.define(version: 20160716115710) do
|
|||
t.string "health_check_access_token"
|
||||
t.boolean "send_user_confirmation_email", default: false
|
||||
t.integer "container_registry_token_expire_delay", default: 5
|
||||
t.boolean "user_default_external", default: false, null: false
|
||||
t.text "after_sign_up_text"
|
||||
t.string "repository_storage", default: "default"
|
||||
t.string "enabled_git_access_protocol"
|
||||
t.boolean "user_default_external", default: false, null: false
|
||||
end
|
||||
|
||||
create_table "audit_events", force: :cascade do |t|
|
||||
|
@ -165,8 +165,8 @@ ActiveRecord::Schema.define(version: 20160716115710) do
|
|||
t.text "artifacts_metadata"
|
||||
t.integer "erased_by_id"
|
||||
t.datetime "erased_at"
|
||||
t.datetime "artifacts_expire_at"
|
||||
t.string "environment"
|
||||
t.datetime "artifacts_expire_at"
|
||||
t.integer "artifacts_size"
|
||||
t.string "when"
|
||||
t.text "yaml_variables"
|
||||
|
@ -201,6 +201,7 @@ ActiveRecord::Schema.define(version: 20160716115710) do
|
|||
t.datetime "started_at"
|
||||
t.datetime "finished_at"
|
||||
t.integer "duration"
|
||||
t.integer "user_id"
|
||||
end
|
||||
|
||||
add_index "ci_commits", ["gl_project_id", "sha"], name: "index_ci_commits_on_gl_project_id_and_sha", using: :btree
|
||||
|
@ -212,6 +213,7 @@ ActiveRecord::Schema.define(version: 20160716115710) do
|
|||
add_index "ci_commits", ["project_id"], name: "index_ci_commits_on_project_id", using: :btree
|
||||
add_index "ci_commits", ["sha"], name: "index_ci_commits_on_sha", using: :btree
|
||||
add_index "ci_commits", ["status"], name: "index_ci_commits_on_status", using: :btree
|
||||
add_index "ci_commits", ["user_id"], name: "index_ci_commits_on_user_id", using: :btree
|
||||
|
||||
create_table "ci_events", force: :cascade do |t|
|
||||
t.integer "project_id"
|
||||
|
@ -483,11 +485,10 @@ ActiveRecord::Schema.define(version: 20160716115710) do
|
|||
t.string "state"
|
||||
t.integer "iid"
|
||||
t.integer "updated_by_id"
|
||||
t.integer "moved_to_id"
|
||||
t.boolean "confidential", default: false
|
||||
t.datetime "deleted_at"
|
||||
t.date "due_date"
|
||||
t.integer "lock_version", default: 0, null: false
|
||||
t.integer "moved_to_id"
|
||||
end
|
||||
|
||||
add_index "issues", ["assignee_id"], name: "index_issues_on_assignee_id", using: :btree
|
||||
|
@ -627,7 +628,6 @@ ActiveRecord::Schema.define(version: 20160716115710) do
|
|||
t.integer "merge_user_id"
|
||||
t.string "merge_commit_sha"
|
||||
t.datetime "deleted_at"
|
||||
t.integer "lock_version", default: 0, null: false
|
||||
end
|
||||
|
||||
add_index "merge_requests", ["assignee_id"], name: "index_merge_requests_on_assignee_id", using: :btree
|
||||
|
@ -777,10 +777,10 @@ ActiveRecord::Schema.define(version: 20160716115710) do
|
|||
t.integer "user_id", null: false
|
||||
t.string "token", null: false
|
||||
t.string "name", null: false
|
||||
t.boolean "revoked", default: false
|
||||
t.datetime "expires_at"
|
||||
t.datetime "created_at", null: false
|
||||
t.datetime "updated_at", null: false
|
||||
t.boolean "revoked", default: false
|
||||
t.datetime "expires_at"
|
||||
end
|
||||
|
||||
add_index "personal_access_tokens", ["token"], name: "index_personal_access_tokens_on_token", unique: true, using: :btree
|
||||
|
@ -900,9 +900,9 @@ ActiveRecord::Schema.define(version: 20160716115710) do
|
|||
t.string "type"
|
||||
t.string "title"
|
||||
t.integer "project_id"
|
||||
t.datetime "created_at", null: false
|
||||
t.datetime "updated_at", null: false
|
||||
t.boolean "active", null: false
|
||||
t.datetime "created_at"
|
||||
t.datetime "updated_at"
|
||||
t.boolean "active", default: false, null: false
|
||||
t.text "properties"
|
||||
t.boolean "template", default: false
|
||||
t.boolean "push_events", default: true
|
||||
|
|
|
@ -985,11 +985,11 @@ directive defined in `.postgres_services` and `.mysql_services` respectively:
|
|||
- ruby
|
||||
|
||||
test:postgres:
|
||||
<< *job_definition
|
||||
<<: *job_definition
|
||||
services: *postgres_definition
|
||||
|
||||
test:mysql:
|
||||
<< *job_definition
|
||||
<<: *job_definition
|
||||
services: *mysql_definition
|
||||
```
|
||||
|
||||
|
|
|
@ -44,7 +44,7 @@ it organized and easy to find.
|
|||
- When introducing a new document, be careful for the headings to be
|
||||
grammatically and syntactically correct. It is advised to mention one or all
|
||||
of the following GitLab members for a review: `@axil`, `@rspeicher`,
|
||||
`@dblessing`, `@ashleys`, `@nearlythere`. This is to ensure that no document
|
||||
`@dblessing`, `@ashleys`. This is to ensure that no document
|
||||
with wrong heading is going live without an audit, thus preventing dead links
|
||||
and redirection issues when corrected
|
||||
- Leave exactly one newline after a heading
|
||||
|
|
|
@ -37,7 +37,6 @@ Feature: Project Issues
|
|||
And I submit new issue "500 error on profile"
|
||||
Then I should see issue "500 error on profile"
|
||||
|
||||
@javascript
|
||||
Scenario: I submit new unassigned issue with labels
|
||||
Given project "Shop" has labels: "bug", "feature", "enhancement"
|
||||
And I click link "New Issue"
|
||||
|
|
|
@ -89,7 +89,7 @@ Feature: Project Merge Requests
|
|||
Then The list should be sorted by "Oldest updated"
|
||||
|
||||
@javascript
|
||||
Scenario: Visiting Merge Requests from a different Project after sorting
|
||||
Scenario: Visiting Merge Requests from a differente Project after sorting
|
||||
Given I visit project "Shop" merge requests page
|
||||
And I sort the list by "Oldest updated"
|
||||
And I visit dashboard merge requests page
|
||||
|
|
|
@ -135,17 +135,19 @@ class Spinach::Features::ProjectForkedMergeRequests < Spinach::FeatureSteps
|
|||
end
|
||||
|
||||
step 'I click "Assign to" dropdown"' do
|
||||
click_button 'Assignee'
|
||||
first('.ajax-users-select').click
|
||||
end
|
||||
|
||||
step 'I should see the target project ID in the input selector' do
|
||||
expect(find('.js-assignee-search')["data-project-id"]).to eq "#{@project.id}"
|
||||
expect(page).to have_selector("input[data-project-id=\"#{@project.id}\"]")
|
||||
end
|
||||
|
||||
step 'I should see the users from the target project ID' do
|
||||
expect(page).to have_content 'Unassigned'
|
||||
expect(page).to have_content current_user.name
|
||||
expect(page).to have_content @project.users.first.name
|
||||
expect(page).to have_selector('.user-result', visible: true, count: 3)
|
||||
users = page.all('.user-name')
|
||||
expect(users[0].text).to eq 'Unassigned'
|
||||
expect(users[1].text).to eq current_user.name
|
||||
expect(users[2].text).to eq @project.users.first.name
|
||||
end
|
||||
|
||||
# Verify a link is generated against the correct project
|
||||
|
|
|
@ -82,8 +82,7 @@ class Spinach::Features::ProjectIssues < Spinach::FeatureSteps
|
|||
|
||||
step 'I submit new issue "500 error on profile" with label \'bug\'' do
|
||||
fill_in "issue_title", with: "500 error on profile"
|
||||
click_button "Label"
|
||||
click_link "bug"
|
||||
select 'bug', from: "Labels"
|
||||
click_button "Submit issue"
|
||||
end
|
||||
|
||||
|
|
|
@ -56,9 +56,9 @@ module API
|
|||
|
||||
not_found!('Award Emoji') unless can_read_awardable?
|
||||
|
||||
award = awardable.award_emoji.new(name: params[:name], user: current_user)
|
||||
award = awardable.create_award_emoji(params[:name], current_user)
|
||||
|
||||
if award.save
|
||||
if award.persisted?
|
||||
present award, with: Entities::AwardEmoji
|
||||
else
|
||||
not_found!("Award Emoji #{award.errors.messages}")
|
||||
|
|
|
@ -64,7 +64,7 @@ module API
|
|||
ref = branches.first
|
||||
end
|
||||
|
||||
pipeline = @project.ensure_pipeline(commit.sha, ref)
|
||||
pipeline = @project.ensure_pipeline(commit.sha, ref, current_user)
|
||||
|
||||
name = params[:name] || params[:context]
|
||||
status = GenericCommitStatus.running_or_pending.find_by(pipeline: pipeline, name: name, ref: params[:ref])
|
||||
|
|
|
@ -63,7 +63,12 @@ module API
|
|||
if access_status.status
|
||||
# Return the repository full path so that gitlab-shell has it when
|
||||
# handling ssh commands
|
||||
response[:repository_path] = project.repository.path_to_repo
|
||||
response[:repository_path] =
|
||||
if wiki?
|
||||
project.wiki.repository.path_to_repo
|
||||
else
|
||||
project.repository.path_to_repo
|
||||
end
|
||||
end
|
||||
|
||||
response
|
||||
|
|
|
@ -19,14 +19,22 @@ module Banzai
|
|||
language = node.attr('class')
|
||||
code = node.text
|
||||
|
||||
css_classes = "code highlight"
|
||||
|
||||
lexer = Rouge::Lexer.find_fancy(language) || Rouge::Lexers::PlainText
|
||||
formatter = Rouge::Formatters::HTML.new
|
||||
|
||||
begin
|
||||
highlighted = block_code(code, language)
|
||||
code = formatter.format(lexer.lex(code))
|
||||
|
||||
css_classes << " js-syntax-highlight #{lexer.tag}"
|
||||
rescue
|
||||
# Gracefully handle syntax highlighter bugs/errors to ensure
|
||||
# users can still access an issue/comment/etc.
|
||||
highlighted = "<pre>#{code}</pre>"
|
||||
end
|
||||
|
||||
highlighted = %(<pre class="#{css_classes}"><code>#{code}</code></pre>)
|
||||
|
||||
# Extracted to a method to measure it
|
||||
replace_parent_pre_element(node, highlighted)
|
||||
end
|
||||
|
@ -40,8 +48,7 @@ module Banzai
|
|||
|
||||
# Override Rouge::Plugins::Redcarpet#rouge_formatter
|
||||
def rouge_formatter(lexer)
|
||||
Rouge::Formatters::HTMLGitlab.new(
|
||||
cssclass: "code highlight js-syntax-highlight #{lexer.tag}")
|
||||
Rouge::Formatters::HTML.new
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -112,7 +112,7 @@ module Banzai
|
|||
data = data_attribute(project: project.id, author: author.try(:id))
|
||||
text = link_text || User.reference_prefix + 'all'
|
||||
|
||||
link_tag(url, data, text)
|
||||
link_tag(url, data, text, 'All Project and Group Members')
|
||||
end
|
||||
|
||||
def link_to_namespace(namespace, link_text: nil)
|
||||
|
@ -128,7 +128,7 @@ module Banzai
|
|||
data = data_attribute(group: namespace.id)
|
||||
text = link_text || Group.reference_prefix + group
|
||||
|
||||
link_tag(url, data, text)
|
||||
link_tag(url, data, text, namespace.name)
|
||||
end
|
||||
|
||||
def link_to_user(user, namespace, link_text: nil)
|
||||
|
@ -136,11 +136,11 @@ module Banzai
|
|||
data = data_attribute(user: namespace.owner_id)
|
||||
text = link_text || User.reference_prefix + user
|
||||
|
||||
link_tag(url, data, text)
|
||||
link_tag(url, data, text, namespace.owner_name)
|
||||
end
|
||||
|
||||
def link_tag(url, data, text)
|
||||
%(<a href="#{url}" #{data} class="#{link_class}">#{escape_once(text)}</a>)
|
||||
def link_tag(url, data, text, title)
|
||||
%(<a href="#{url}" #{data} class="#{link_class}" title="#{escape_once(title)}">#{escape_once(text)}</a>)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -63,7 +63,7 @@ module Grack
|
|||
def ci_request?(login, password)
|
||||
matched_login = /(?<s>^[a-zA-Z]*-ci)-token$/.match(login)
|
||||
|
||||
if project && matched_login.present? && git_cmd == 'git-upload-pack'
|
||||
if project && matched_login.present?
|
||||
underscored_service = matched_login['s'].underscore
|
||||
|
||||
if underscored_service == 'gitlab_ci'
|
||||
|
|
|
@ -20,11 +20,19 @@ module Gitlab
|
|||
|
||||
if Database.postgresql?
|
||||
options = options.merge({ algorithm: :concurrently })
|
||||
disable_statement_timeout
|
||||
end
|
||||
|
||||
add_index(table_name, column_name, options)
|
||||
end
|
||||
|
||||
# Long-running migrations may take more than the timeout allowed by
|
||||
# the database. Disable the session's statement timeout to ensure
|
||||
# migrations don't get killed prematurely. (PostgreSQL only)
|
||||
def disable_statement_timeout
|
||||
ActiveRecord::Base.connection.execute('SET statement_timeout TO 0') if Database.postgresql?
|
||||
end
|
||||
|
||||
# Updates the value of a column in batches.
|
||||
#
|
||||
# This method updates the table in batches of 5% of the total row count.
|
||||
|
@ -133,6 +141,8 @@ module Gitlab
|
|||
'in the body of your migration class'
|
||||
end
|
||||
|
||||
disable_statement_timeout
|
||||
|
||||
transaction do
|
||||
add_column(table, column, type, default: nil)
|
||||
|
||||
|
|
|
@ -15,32 +15,35 @@ module Gitlab
|
|||
end
|
||||
|
||||
def execute
|
||||
project_identifier = CGI.escape(project.import_source)
|
||||
ActiveRecord::Base.no_touching do
|
||||
project_identifier = CGI.escape(project.import_source)
|
||||
|
||||
# Issues && Comments
|
||||
issues = client.issues(project_identifier)
|
||||
# Issues && Comments
|
||||
issues = client.issues(project_identifier)
|
||||
|
||||
issues.each do |issue|
|
||||
body = @formatter.author_line(issue["author"]["name"])
|
||||
body += issue["description"]
|
||||
issues.each do |issue|
|
||||
body = @formatter.author_line(issue["author"]["name"])
|
||||
body += issue["description"]
|
||||
|
||||
comments = client.issue_comments(project_identifier, issue["id"])
|
||||
comments = client.issue_comments(project_identifier, issue["id"])
|
||||
|
||||
if comments.any?
|
||||
body += @formatter.comments_header
|
||||
if comments.any?
|
||||
body += @formatter.comments_header
|
||||
end
|
||||
|
||||
comments.each do |comment|
|
||||
body += @formatter.comment(comment["author"]["name"], comment["created_at"], comment["body"])
|
||||
end
|
||||
|
||||
project.issues.create!(
|
||||
iid: issue["iid"],
|
||||
description: body,
|
||||
title: issue["title"],
|
||||
state: issue["state"],
|
||||
updated_at: issue["updated_at"],
|
||||
author_id: gl_user_id(project, issue["author"]["id"])
|
||||
)
|
||||
end
|
||||
|
||||
comments.each do |comment|
|
||||
body += @formatter.comment(comment["author"]["name"], comment["created_at"], comment["body"])
|
||||
end
|
||||
|
||||
project.issues.create!(
|
||||
iid: issue["iid"],
|
||||
description: body,
|
||||
title: issue["title"],
|
||||
state: issue["state"],
|
||||
author_id: gl_user_id(project, issue["author"]["id"])
|
||||
)
|
||||
end
|
||||
|
||||
true
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
module Gitlab
|
||||
class Highlight
|
||||
def self.highlight(blob_name, blob_content, repository: nil, nowrap: true, plain: false)
|
||||
new(blob_name, blob_content, nowrap: nowrap, repository: repository).
|
||||
def self.highlight(blob_name, blob_content, repository: nil, plain: false)
|
||||
new(blob_name, blob_content, repository: repository).
|
||||
highlight(blob_content, continue: false, plain: plain)
|
||||
end
|
||||
|
||||
|
@ -13,30 +13,34 @@ module Gitlab
|
|||
highlight(file_name, blob.data, repository: repository).lines.map!(&:html_safe)
|
||||
end
|
||||
|
||||
attr_reader :lexer
|
||||
def initialize(blob_name, blob_content, repository: nil, nowrap: true)
|
||||
def initialize(blob_name, blob_content, repository: nil)
|
||||
@formatter = Rouge::Formatters::HTMLGitlab.new
|
||||
@repository = repository
|
||||
@blob_name = blob_name
|
||||
@blob_content = blob_content
|
||||
@repository = repository
|
||||
@formatter = rouge_formatter(nowrap: nowrap)
|
||||
|
||||
@lexer = custom_language || begin
|
||||
Rouge::Lexer.guess(filename: blob_name, source: blob_content).new
|
||||
rescue Rouge::Lexer::AmbiguousGuess => e
|
||||
e.alternatives.sort_by(&:tag).first
|
||||
end
|
||||
end
|
||||
|
||||
def highlight(text, continue: true, plain: false)
|
||||
if plain
|
||||
@formatter.format(Rouge::Lexers::PlainText.lex(text)).html_safe
|
||||
hl_lexer = Rouge::Lexers::PlainText
|
||||
continue = false
|
||||
else
|
||||
@formatter.format(@lexer.lex(text, continue: continue)).html_safe
|
||||
hl_lexer = self.lexer
|
||||
end
|
||||
|
||||
@formatter.format(hl_lexer.lex(text, continue: continue)).html_safe
|
||||
rescue
|
||||
@formatter.format(Rouge::Lexers::PlainText.lex(text)).html_safe
|
||||
end
|
||||
|
||||
def lexer
|
||||
@lexer ||= custom_language || begin
|
||||
Rouge::Lexer.guess(filename: @blob_name, source: @blob_content).new
|
||||
rescue Rouge::Guesser::Ambiguous => e
|
||||
e.alternatives.sort_by(&:tag).first
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def custom_language
|
||||
|
@ -46,16 +50,5 @@ module Gitlab
|
|||
|
||||
Rouge::Lexer.find_fancy(language_name)
|
||||
end
|
||||
|
||||
def rouge_formatter(options = {})
|
||||
options = options.reverse_merge(
|
||||
nowrap: true,
|
||||
cssclass: 'code highlight',
|
||||
lineanchors: true,
|
||||
lineanchorsid: 'LC'
|
||||
)
|
||||
|
||||
Rouge::Formatters::HTMLGitlab.new(options)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -3,6 +3,7 @@ module Gitlab
|
|||
extend self
|
||||
|
||||
VERSION = '0.1.1'
|
||||
FILENAME_LIMIT = 50
|
||||
|
||||
def export_path(relative_path:)
|
||||
File.join(storage_path, relative_path)
|
||||
|
@ -28,6 +29,12 @@ module Gitlab
|
|||
'VERSION'
|
||||
end
|
||||
|
||||
def export_filename(project:)
|
||||
basename = "#{Time.now.strftime('%Y-%m-%d_%H-%M-%3N')}_#{project.namespace.path}_#{project.path}"
|
||||
|
||||
"#{basename[0..FILENAME_LIMIT]}_export.tar.gz"
|
||||
end
|
||||
|
||||
def version
|
||||
VERSION
|
||||
end
|
||||
|
|
|
@ -12,7 +12,10 @@ module Gitlab
|
|||
json = IO.read(@path)
|
||||
@tree_hash = ActiveSupport::JSON.decode(json)
|
||||
@project_members = @tree_hash.delete('project_members')
|
||||
create_relations
|
||||
|
||||
ActiveRecord::Base.no_touching do
|
||||
create_relations
|
||||
end
|
||||
rescue => e
|
||||
@shared.error(e)
|
||||
false
|
||||
|
|
|
@ -87,7 +87,7 @@ module Gitlab
|
|||
project_id = @relation_hash.delete('project_id')
|
||||
|
||||
# project_id may not be part of the export, but we always need to populate it if required.
|
||||
@relation_hash['project_id'] = project_id if relation_class.column_names.include?('project_id')
|
||||
@relation_hash['project_id'] = project_id
|
||||
@relation_hash['gl_project_id'] = project_id if @relation_hash['gl_project_id']
|
||||
@relation_hash['target_project_id'] = project_id if @relation_hash['target_project_id']
|
||||
@relation_hash['source_project_id'] = -1 if @relation_hash['source_project_id']
|
||||
|
@ -111,7 +111,7 @@ module Gitlab
|
|||
end
|
||||
|
||||
def imported_object
|
||||
imported_object = relation_class.new(@relation_hash)
|
||||
imported_object = relation_class.new(parsed_relation_hash)
|
||||
yield(imported_object) if block_given?
|
||||
imported_object.importing = true if imported_object.respond_to?(:importing)
|
||||
imported_object
|
||||
|
@ -125,6 +125,10 @@ module Gitlab
|
|||
def admin_user?
|
||||
@user.is_admin?
|
||||
end
|
||||
|
||||
def parsed_relation_hash
|
||||
@relation_hash.reject { |k, _v| !relation_class.attribute_method?(k) }
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -7,7 +7,8 @@ module Gitlab
|
|||
new(*args).save
|
||||
end
|
||||
|
||||
def initialize(shared:)
|
||||
def initialize(project:, shared:)
|
||||
@project = project
|
||||
@shared = shared
|
||||
end
|
||||
|
||||
|
@ -36,7 +37,7 @@ module Gitlab
|
|||
end
|
||||
|
||||
def archive_file
|
||||
@archive_file ||= File.join(@shared.export_path, '..', "#{Time.now.strftime('%Y-%m-%d_%H-%M-%3N')}_project_export.tar.gz")
|
||||
@archive_file ||= File.join(@shared.export_path, '..', Gitlab::ImportExport.export_filename(project: @project))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -47,6 +47,8 @@ module Gitlab
|
|||
end
|
||||
|
||||
def render_storage_upload_store_response(oid, size, tmp_file_name)
|
||||
return render_forbidden unless tmp_file_name
|
||||
|
||||
render_response_to_push do
|
||||
render_lfs_upload_ok(oid, size, tmp_file_name)
|
||||
end
|
||||
|
|
|
@ -74,8 +74,6 @@ module Gitlab
|
|||
lfs.render_storage_upload_authorize_response(oid, size)
|
||||
else
|
||||
tmp_file_name = sanitize_tmp_filename(@request.env['HTTP_X_GITLAB_LFS_TMP'])
|
||||
return nil unless tmp_file_name
|
||||
|
||||
lfs.render_storage_upload_store_response(oid, size, tmp_file_name)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,171 +1,27 @@
|
|||
require 'cgi'
|
||||
|
||||
module Rouge
|
||||
module Formatters
|
||||
class HTMLGitlab < Rouge::Formatter
|
||||
class HTMLGitlab < Rouge::Formatters::HTML
|
||||
tag 'html_gitlab'
|
||||
|
||||
# Creates a new <tt>Rouge::Formatter::HTMLGitlab</tt> instance.
|
||||
#
|
||||
# [+nowrap+] If set to True, don't wrap the output at all, not
|
||||
# even inside a <tt><pre></tt> tag (default: false).
|
||||
# [+cssclass+] CSS class for the wrapping <tt><div></tt> tag
|
||||
# (default: 'highlight').
|
||||
# [+linenos+] If set to 'table', output line numbers as a table
|
||||
# with two cells, one containing the line numbers,
|
||||
# the other the whole code. This is copy paste friendly,
|
||||
# but may cause alignment problems with some browsers
|
||||
# or fonts. If set to 'inline', the line numbers will
|
||||
# be integrated in the <tt><pre></tt> tag that contains
|
||||
# the code (default: nil).
|
||||
# [+linenostart+] The line number for the first line (default: 1).
|
||||
# [+lineanchors+] If set to true the formatter will wrap each output
|
||||
# line in an anchor tag with a name of L-linenumber.
|
||||
# This allows easy linking to certain lines
|
||||
# (default: false).
|
||||
# [+lineanchorsid+] If lineanchors is true the name of the anchors can
|
||||
# be changed with lineanchorsid to e.g. foo-linenumber
|
||||
# (default: 'L').
|
||||
# [+anchorlinenos+] If set to true, will wrap line numbers in <tt><a></tt>
|
||||
# tags. Used in combination with linenos and lineanchors
|
||||
# (default: false).
|
||||
# [+inline_theme+] Inline CSS styles for the <pre> tag (default: false).
|
||||
def initialize(
|
||||
nowrap: false,
|
||||
cssclass: 'highlight',
|
||||
linenos: nil,
|
||||
linenostart: 1,
|
||||
lineanchors: false,
|
||||
lineanchorsid: 'L',
|
||||
anchorlinenos: false,
|
||||
inline_theme: nil
|
||||
)
|
||||
@nowrap = nowrap
|
||||
@cssclass = cssclass
|
||||
@linenos = linenos
|
||||
def initialize(linenostart: 1)
|
||||
@linenostart = linenostart
|
||||
@lineanchors = lineanchors
|
||||
@lineanchorsid = lineanchorsid
|
||||
@anchorlinenos = anchorlinenos
|
||||
@inline_theme = Theme.find(inline_theme).new if inline_theme.is_a?(String)
|
||||
@line_number = linenostart
|
||||
end
|
||||
|
||||
def render(tokens)
|
||||
case @linenos
|
||||
when 'table'
|
||||
render_tableized(tokens)
|
||||
when 'inline'
|
||||
render_untableized(tokens)
|
||||
else
|
||||
render_untableized(tokens)
|
||||
end
|
||||
end
|
||||
def stream(tokens, &b)
|
||||
is_first = true
|
||||
token_lines(tokens) do |line|
|
||||
yield "\n" unless is_first
|
||||
is_first = false
|
||||
|
||||
alias_method :format, :render
|
||||
yield %(<span id="LC#{@line_number}" class="line">)
|
||||
line.each { |token, value| yield span(token, value) }
|
||||
yield %(</span>)
|
||||
|
||||
private
|
||||
|
||||
def render_untableized(tokens)
|
||||
data = process_tokens(tokens)
|
||||
|
||||
html = ''
|
||||
html << "<pre class=\"#{@cssclass}\"><code>" unless @nowrap
|
||||
html << wrap_lines(data[:code])
|
||||
html << "</code></pre>\n" unless @nowrap
|
||||
html
|
||||
end
|
||||
|
||||
def render_tableized(tokens)
|
||||
data = process_tokens(tokens)
|
||||
|
||||
html = ''
|
||||
html << "<div class=\"#{@cssclass}\">" unless @nowrap
|
||||
html << '<table><tbody>'
|
||||
html << "<td class=\"linenos\"><pre>"
|
||||
html << wrap_linenos(data[:numbers])
|
||||
html << '</pre></td>'
|
||||
html << "<td class=\"lines\"><pre><code>"
|
||||
html << wrap_lines(data[:code])
|
||||
html << '</code></pre></td>'
|
||||
html << '</tbody></table>'
|
||||
html << '</div>' unless @nowrap
|
||||
html
|
||||
end
|
||||
|
||||
def process_tokens(tokens)
|
||||
rendered = []
|
||||
current_line = ''
|
||||
|
||||
tokens.each do |tok, val|
|
||||
# In the case of multi-line values (e.g. comments), we need to apply
|
||||
# styling to each line since span elements are inline.
|
||||
val.lines.each do |line|
|
||||
stripped = line.chomp
|
||||
current_line << span(tok, stripped)
|
||||
|
||||
if line.end_with?("\n")
|
||||
rendered << current_line
|
||||
current_line = ''
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Add leftover text
|
||||
rendered << current_line if current_line.present?
|
||||
|
||||
num_lines = rendered.size
|
||||
numbers = (@linenostart..num_lines + @linenostart - 1).to_a
|
||||
|
||||
{ numbers: numbers, code: rendered }
|
||||
end
|
||||
|
||||
def wrap_linenos(numbers)
|
||||
if @anchorlinenos
|
||||
numbers.map! do |number|
|
||||
"<a href=\"##{@lineanchorsid}#{number}\">#{number}</a>"
|
||||
end
|
||||
end
|
||||
numbers.join("\n")
|
||||
end
|
||||
|
||||
def wrap_lines(lines)
|
||||
if @lineanchors
|
||||
lines = lines.each_with_index.map do |line, index|
|
||||
number = index + @linenostart
|
||||
|
||||
if @linenos == 'inline'
|
||||
"<a name=\"L#{number}\"></a>" \
|
||||
"<span class=\"linenos\">#{number}</span>" \
|
||||
"<span id=\"#{@lineanchorsid}#{number}\" class=\"line\">#{line}" \
|
||||
'</span>'
|
||||
else
|
||||
"<span id=\"#{@lineanchorsid}#{number}\" class=\"line\">#{line}" \
|
||||
'</span>'
|
||||
end
|
||||
end
|
||||
elsif @linenos == 'inline'
|
||||
lines = lines.each_with_index.map do |line, index|
|
||||
number = index + @linenostart
|
||||
"<span class=\"linenos\">#{number}</span>#{line}"
|
||||
end
|
||||
end
|
||||
|
||||
lines.join("\n")
|
||||
end
|
||||
|
||||
def span(tok, val)
|
||||
# http://stackoverflow.com/a/1600584/2587286
|
||||
val = CGI.escapeHTML(val)
|
||||
|
||||
if tok.shortname.empty?
|
||||
val
|
||||
else
|
||||
if @inline_theme
|
||||
rules = @inline_theme.style_for(tok).rendered_rules
|
||||
"<span style=\"#{rules.to_a.join(';')}\"#{val}</span>"
|
||||
else
|
||||
"<span class=\"#{tok.shortname}\">#{val}</span>"
|
||||
end
|
||||
@line_number += 1
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,14 +1,26 @@
|
|||
require 'spec_helper'
|
||||
|
||||
feature 'Group', feature: true do
|
||||
before do
|
||||
login_as(:admin)
|
||||
end
|
||||
|
||||
describe 'creating a group with space in group path' do
|
||||
it 'renders new group form with validation errors' do
|
||||
visit new_group_path
|
||||
fill_in 'Group path', with: 'space group'
|
||||
|
||||
click_button 'Create group'
|
||||
|
||||
expect(current_path).to eq(groups_path)
|
||||
expect(page).to have_content("Path can contain only letters, digits, '_', '-' and '.'. Cannot start with '-' or end in '.'.")
|
||||
end
|
||||
end
|
||||
|
||||
describe 'description' do
|
||||
let(:group) { create(:group) }
|
||||
let(:path) { group_path(group) }
|
||||
|
||||
before do
|
||||
login_as(:admin)
|
||||
end
|
||||
|
||||
it 'parses Markdown' do
|
||||
group.update_attribute(:description, 'This is **my** group')
|
||||
visit path
|
||||
|
|
|
@ -55,7 +55,7 @@ feature 'issue move to another project' do
|
|||
first('.select2-choice').click
|
||||
end
|
||||
|
||||
fill_in('s2id_autogen1_search', with: new_project_search.name)
|
||||
fill_in('s2id_autogen2_search', with: new_project_search.name)
|
||||
|
||||
page.within '.select2-drop' do
|
||||
expect(page).to have_content(new_project_search.name)
|
||||
|
|
|
@ -50,8 +50,9 @@ describe 'Issues', feature: true do
|
|||
|
||||
expect(page).to have_content "Assignee #{@user.name}"
|
||||
|
||||
first('.js-user-search').click
|
||||
click_link 'Unassigned'
|
||||
first('#s2id_issue_assignee_id').click
|
||||
sleep 2 # wait for ajax stuff to complete
|
||||
first('.user-result').click
|
||||
|
||||
click_button 'Save changes'
|
||||
|
||||
|
@ -120,17 +121,6 @@ describe 'Issues', feature: true do
|
|||
expect(page).to have_content date.to_s(:medium)
|
||||
end
|
||||
end
|
||||
|
||||
it 'warns about version conflict' do
|
||||
issue.update(title: "New title")
|
||||
|
||||
fill_in 'issue_title', with: 'bug 345'
|
||||
fill_in 'issue_description', with: 'bug description'
|
||||
|
||||
click_button 'Save changes'
|
||||
|
||||
expect(page).to have_content 'Someone edited the issue the same time you did'
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -17,16 +17,5 @@ feature 'Edit Merge Request', feature: true do
|
|||
it 'form should have class js-quick-submit' do
|
||||
expect(page).to have_selector('.js-quick-submit')
|
||||
end
|
||||
|
||||
it 'warns about version conflict' do
|
||||
merge_request.update(title: "New title")
|
||||
|
||||
fill_in 'merge_request_title', with: 'bug 345'
|
||||
fill_in 'merge_request_description', with: 'bug description'
|
||||
|
||||
click_button 'Save changes'
|
||||
|
||||
expect(page).to have_content 'Someone edited the merge request the same time you did'
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -426,4 +426,23 @@ describe "Internal Project Access", feature: true do
|
|||
it { is_expected.to be_denied_for :external }
|
||||
it { is_expected.to be_denied_for :visitor }
|
||||
end
|
||||
|
||||
describe "GET /:project_path/container_registry" do
|
||||
before do
|
||||
stub_container_registry_tags('latest')
|
||||
stub_container_registry_config(enabled: true)
|
||||
end
|
||||
|
||||
subject { namespace_project_container_registry_index_path(project.namespace, project) }
|
||||
|
||||
it { is_expected.to be_allowed_for :admin }
|
||||
it { is_expected.to be_allowed_for owner }
|
||||
it { is_expected.to be_allowed_for master }
|
||||
it { is_expected.to be_allowed_for developer }
|
||||
it { is_expected.to be_allowed_for reporter }
|
||||
it { is_expected.to be_allowed_for guest }
|
||||
it { is_expected.to be_allowed_for :user }
|
||||
it { is_expected.to be_denied_for :external }
|
||||
it { is_expected.to be_denied_for :visitor }
|
||||
end
|
||||
end
|
||||
|
|
|
@ -362,4 +362,23 @@ describe "Private Project Access", feature: true do
|
|||
it { is_expected.to be_denied_for :external }
|
||||
it { is_expected.to be_denied_for :visitor }
|
||||
end
|
||||
|
||||
describe "GET /:project_path/container_registry" do
|
||||
before do
|
||||
stub_container_registry_tags('latest')
|
||||
stub_container_registry_config(enabled: true)
|
||||
end
|
||||
|
||||
subject { namespace_project_container_registry_index_path(project.namespace, project) }
|
||||
|
||||
it { is_expected.to be_allowed_for :admin }
|
||||
it { is_expected.to be_allowed_for owner }
|
||||
it { is_expected.to be_allowed_for master }
|
||||
it { is_expected.to be_allowed_for developer }
|
||||
it { is_expected.to be_allowed_for reporter }
|
||||
it { is_expected.to be_denied_for guest }
|
||||
it { is_expected.to be_denied_for :user }
|
||||
it { is_expected.to be_denied_for :external }
|
||||
it { is_expected.to be_denied_for :visitor }
|
||||
end
|
||||
end
|
||||
|
|
|
@ -426,4 +426,23 @@ describe "Public Project Access", feature: true do
|
|||
it { is_expected.to be_denied_for :external }
|
||||
it { is_expected.to be_denied_for :visitor }
|
||||
end
|
||||
|
||||
describe "GET /:project_path/container_registry" do
|
||||
before do
|
||||
stub_container_registry_tags('latest')
|
||||
stub_container_registry_config(enabled: true)
|
||||
end
|
||||
|
||||
subject { namespace_project_container_registry_index_path(project.namespace, project) }
|
||||
|
||||
it { is_expected.to be_allowed_for :admin }
|
||||
it { is_expected.to be_allowed_for owner }
|
||||
it { is_expected.to be_allowed_for master }
|
||||
it { is_expected.to be_allowed_for developer }
|
||||
it { is_expected.to be_allowed_for reporter }
|
||||
it { is_expected.to be_allowed_for guest }
|
||||
it { is_expected.to be_allowed_for :user }
|
||||
it { is_expected.to be_allowed_for :external }
|
||||
it { is_expected.to be_allowed_for :visitor }
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
require 'spec_helper'
|
||||
|
||||
feature 'Using U2F (Universal 2nd Factor) Devices for Authentication', feature: true, js: true do
|
||||
before { allow_any_instance_of(U2fHelper).to receive(:inject_u2f_api?).and_return(true) }
|
||||
|
||||
def register_u2f_device(u2f_device = nil)
|
||||
u2f_device ||= FakeU2fDevice.new(page)
|
||||
u2f_device.respond_to_u2f_registration
|
||||
|
@ -208,21 +210,52 @@ feature 'Using U2F (Universal 2nd Factor) Devices for Authentication', feature:
|
|||
expect(page.body).to match('Authentication via U2F device failed')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "when two-factor authentication is disabled" do
|
||||
let(:user) { create(:user) }
|
||||
describe "when more than one device has been registered by the same user" do
|
||||
it "allows logging in with either device" do
|
||||
# Register first device
|
||||
user = login_as(:user)
|
||||
user.update_attribute(:otp_required_for_login, true)
|
||||
visit profile_two_factor_auth_path
|
||||
expect(page).to have_content("Your U2F device needs to be set up.")
|
||||
first_device = register_u2f_device
|
||||
|
||||
before do
|
||||
login_as(user)
|
||||
user.update_attribute(:otp_required_for_login, true)
|
||||
visit profile_account_path
|
||||
click_on 'Manage Two-Factor Authentication'
|
||||
register_u2f_device
|
||||
# Register second device
|
||||
visit profile_two_factor_auth_path
|
||||
expect(page).to have_content("Your U2F device needs to be set up.")
|
||||
second_device = register_u2f_device
|
||||
logout
|
||||
|
||||
# Authenticate as both devices
|
||||
[first_device, second_device].each do |device|
|
||||
login_as(user)
|
||||
device.respond_to_u2f_authentication
|
||||
click_on "Login Via U2F Device"
|
||||
expect(page.body).to match('We heard back from your U2F device')
|
||||
click_on "Authenticate via U2F Device"
|
||||
|
||||
expect(page.body).to match('Signed in successfully')
|
||||
|
||||
logout
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
it "deletes u2f registrations" do
|
||||
expect { click_on "Disable" }.to change { U2fRegistration.count }.from(1).to(0)
|
||||
describe "when two-factor authentication is disabled" do
|
||||
let(:user) { create(:user) }
|
||||
|
||||
before do
|
||||
user = login_as(:user)
|
||||
user.update_attribute(:otp_required_for_login, true)
|
||||
visit profile_account_path
|
||||
click_on 'Manage Two-Factor Authentication'
|
||||
expect(page).to have_content("Your U2F device needs to be set up.")
|
||||
register_u2f_device
|
||||
end
|
||||
|
||||
it "deletes u2f registrations" do
|
||||
expect { click_on "Disable" }.to change { U2fRegistration.count }.by(-1)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
12
spec/fixtures/parallel_diff_result.yml
vendored
12
spec/fixtures/parallel_diff_result.yml
vendored
|
@ -121,7 +121,7 @@
|
|||
:type: old
|
||||
:number: 9
|
||||
:text: |
|
||||
-<span id="LC9" class="line"> <span class="k">raise</span> <span class="s2">"System commands must be given as an array of strings"</span></span>
|
||||
-<span id="LC9" class="line"> <span class="k">raise</span> <span class="s2">"System commands must be given as an array of strings"</span></span>
|
||||
:line_code: 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_9_9
|
||||
:position: !ruby/object:Gitlab::Diff::Position
|
||||
attributes:
|
||||
|
@ -136,7 +136,7 @@
|
|||
:type: new
|
||||
:number: 9
|
||||
:text: |
|
||||
+<span id="LC9" class="line"> <span class="k">raise</span> <span class="no"><span class='idiff left'>RuntimeError</span></span><span class="p"><span class='idiff'>,</span></span><span class='idiff right'> </span><span class="s2">"System commands must be given as an array of strings"</span></span>
|
||||
+<span id="LC9" class="line"> <span class="k">raise</span> <span class="no"><span class='idiff left'>RuntimeError</span></span><span class="p"><span class='idiff'>,</span></span><span class='idiff right'> </span><span class="s2">"System commands must be given as an array of strings"</span></span>
|
||||
:line_code: 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_10_9
|
||||
:position: !ruby/object:Gitlab::Diff::Position
|
||||
attributes:
|
||||
|
@ -241,7 +241,7 @@
|
|||
:type: old
|
||||
:number: 13
|
||||
:text: |
|
||||
-<span id="LC13" class="line"> <span class="n">vars</span> <span class="o">=</span> <span class="p">{</span> <span class="s2">"PWD"</span> <span class="o">=></span> <span class="n">path</span> <span class="p">}</span></span>
|
||||
-<span id="LC13" class="line"> <span class="n">vars</span> <span class="o">=</span> <span class="p">{</span> <span class="s2">"PWD"</span> <span class="o">=></span> <span class="n">path</span> <span class="p">}</span></span>
|
||||
:line_code: 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_13_13
|
||||
:position: !ruby/object:Gitlab::Diff::Position
|
||||
attributes:
|
||||
|
@ -315,7 +315,7 @@
|
|||
:type: new
|
||||
:number: 15
|
||||
:text: |
|
||||
+<span id="LC15" class="line"> <span class="s2">"PWD"</span> <span class="o">=></span> <span class="n">path</span></span>
|
||||
+<span id="LC15" class="line"> <span class="s2">"PWD"</span> <span class="o">=></span> <span class="n">path</span></span>
|
||||
:line_code: 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_15_15
|
||||
:position: !ruby/object:Gitlab::Diff::Position
|
||||
attributes:
|
||||
|
@ -623,7 +623,7 @@
|
|||
:type:
|
||||
:number: 20
|
||||
:text: |2
|
||||
<span id="LC26" class="line"> <span class="vi">@cmd_output</span> <span class="o">=</span> <span class="s2">""</span></span>
|
||||
<span id="LC26" class="line"> <span class="vi">@cmd_output</span> <span class="o">=</span> <span class="s2">""</span></span>
|
||||
:line_code: 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_20_26
|
||||
:position: !ruby/object:Gitlab::Diff::Position
|
||||
attributes:
|
||||
|
@ -638,7 +638,7 @@
|
|||
:type:
|
||||
:number: 26
|
||||
:text: |2
|
||||
<span id="LC26" class="line"> <span class="vi">@cmd_output</span> <span class="o">=</span> <span class="s2">""</span></span>
|
||||
<span id="LC26" class="line"> <span class="vi">@cmd_output</span> <span class="o">=</span> <span class="s2">""</span></span>
|
||||
:line_code: 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_20_26
|
||||
:position: !ruby/object:Gitlab::Diff::Position
|
||||
attributes:
|
||||
|
|
|
@ -16,19 +16,19 @@ describe BlobHelper do
|
|||
|
||||
describe '#highlight' do
|
||||
it 'should return plaintext for unknown lexer context' do
|
||||
result = helper.highlight(blob_name, no_context_content, nowrap: true)
|
||||
expect(result).to eq('<span id="LC1" class="line">:type "assem"))</span>')
|
||||
result = helper.highlight(blob_name, no_context_content)
|
||||
expect(result).to eq(%[<pre class="code highlight"><code><span id="LC1" class="line">:type "assem"))</span></code></pre>])
|
||||
end
|
||||
|
||||
it 'should highlight single block' do
|
||||
expected = %Q[<span id="LC1" class="line"><span class="p">(</span><span class="nb">make-pathname</span> <span class="ss">:defaults</span> <span class="nv">name</span></span>
|
||||
<span id="LC2" class="line"><span class="ss">:type</span> <span class="s">"assem"</span><span class="p">))</span></span>]
|
||||
expected = %Q[<pre class="code highlight"><code><span id="LC1" class="line"><span class="p">(</span><span class="nb">make-pathname</span> <span class="ss">:defaults</span> <span class="nv">name</span></span>
|
||||
<span id="LC2" class="line"><span class="ss">:type</span> <span class="s">"assem"</span><span class="p">))</span></span></code></pre>]
|
||||
|
||||
expect(helper.highlight(blob_name, blob_content, nowrap: true)).to eq(expected)
|
||||
expect(helper.highlight(blob_name, blob_content)).to eq(expected)
|
||||
end
|
||||
|
||||
it 'should highlight multi-line comments' do
|
||||
result = helper.highlight(blob_name, multiline_content, nowrap: true)
|
||||
result = helper.highlight(blob_name, multiline_content)
|
||||
html = Nokogiri::HTML(result)
|
||||
lines = html.search('.s')
|
||||
expect(lines.count).to eq(3)
|
||||
|
@ -41,33 +41,19 @@ describe BlobHelper do
|
|||
let(:blob_name) { 'test.diff' }
|
||||
let(:blob_content) { "+aaa\n+bbb\n- ccc\n ddd\n"}
|
||||
let(:expected) do
|
||||
%q(<span id="LC1" class="line"><span class="gi">+aaa</span></span>
|
||||
%q(<pre class="code highlight"><code><span id="LC1" class="line"><span class="gi">+aaa</span></span>
|
||||
<span id="LC2" class="line"><span class="gi">+bbb</span></span>
|
||||
<span id="LC3" class="line"><span class="gd">- ccc</span></span>
|
||||
<span id="LC4" class="line"> ddd</span>)
|
||||
<span id="LC4" class="line"> ddd</span></code></pre>)
|
||||
end
|
||||
|
||||
it 'should highlight each line properly' do
|
||||
result = helper.highlight(blob_name, blob_content, nowrap: true)
|
||||
result = helper.highlight(blob_name, blob_content)
|
||||
expect(result).to eq(expected)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "#highlighter" do
|
||||
it 'should highlight continued blocks' do
|
||||
# Both lines have LC1 as ID since formatter doesn't support continue at the moment
|
||||
expected = [
|
||||
'<span id="LC1" class="line"><span class="p">(</span><span class="nb">make-pathname</span> <span class="ss">:defaults</span> <span class="nv">name</span></span>',
|
||||
'<span id="LC1" class="line"><span class="ss">:type</span> <span class="s">"assem"</span><span class="p">))</span></span>'
|
||||
]
|
||||
|
||||
highlighter = helper.highlighter(blob_name, blob_content, nowrap: true)
|
||||
result = split_content.map{ |content| highlighter.highlight(content) }
|
||||
expect(result).to eq(expected)
|
||||
end
|
||||
end
|
||||
|
||||
describe "#sanitize_svg" do
|
||||
let(:input_svg_path) { File.join(Rails.root, 'spec', 'fixtures', 'unsanitized.svg') }
|
||||
let(:data) { open(input_svg_path).read }
|
||||
|
|
|
@ -57,7 +57,7 @@ describe EventsHelper do
|
|||
expected = '<pre class="code highlight js-syntax-highlight ruby">' \
|
||||
"<code><span class=\"k\">def</span> <span class=\"nf\">test</span>\n" \
|
||||
" <span class=\"s1\">\'hello world\'</span>\n" \
|
||||
"<span class=\"k\">end</span>" \
|
||||
"<span class=\"k\">end</span>\n" \
|
||||
'</code></pre>'
|
||||
expect(helper.event_note(input)).to eq(expected)
|
||||
end
|
||||
|
|
|
@ -5,13 +5,12 @@
|
|||
#= require ./mock_u2f_device
|
||||
|
||||
describe 'U2FAuthenticate', ->
|
||||
U2FUtil.enableTestMode()
|
||||
fixture.load('u2f/authenticate')
|
||||
|
||||
beforeEach ->
|
||||
@u2fDevice = new MockU2FDevice
|
||||
@container = $("#js-authenticate-u2f")
|
||||
@component = new U2FAuthenticate(@container, {}, "token")
|
||||
@component = new U2FAuthenticate(@container, {sign_requests: []}, "token")
|
||||
@component.start()
|
||||
|
||||
it 'allows authenticating via a U2F device', ->
|
||||
|
|
|
@ -5,7 +5,6 @@
|
|||
#= require ./mock_u2f_device
|
||||
|
||||
describe 'U2FRegister', ->
|
||||
U2FUtil.enableTestMode()
|
||||
fixture.load('u2f/register')
|
||||
|
||||
beforeEach ->
|
||||
|
|
|
@ -3,15 +3,35 @@ require 'spec_helper'
|
|||
describe Banzai::Filter::SyntaxHighlightFilter, lib: true do
|
||||
include FilterSpecHelper
|
||||
|
||||
it 'highlights valid code blocks' do
|
||||
result = filter('<pre><code>def fun end</code>')
|
||||
expect(result.to_html).to eq("<pre class=\"code highlight js-syntax-highlight plaintext\"><code>def fun end</code></pre>\n")
|
||||
context "when no language is specified" do
|
||||
it "highlights as plaintext" do
|
||||
result = filter('<pre><code>def fun end</code></pre>')
|
||||
expect(result.to_html).to eq('<pre class="code highlight js-syntax-highlight plaintext"><code>def fun end</code></pre>')
|
||||
end
|
||||
end
|
||||
|
||||
it 'passes through invalid code blocks' do
|
||||
allow_any_instance_of(described_class).to receive(:block_code).and_raise(StandardError)
|
||||
context "when a valid language is specified" do
|
||||
it "highlights as that language" do
|
||||
result = filter('<pre><code class="ruby">def fun end</code></pre>')
|
||||
expect(result.to_html).to eq('<pre class="code highlight js-syntax-highlight ruby"><code><span class="k">def</span> <span class="nf">fun</span> <span class="k">end</span></code></pre>')
|
||||
end
|
||||
end
|
||||
|
||||
result = filter('<pre><code>This is a test</code></pre>')
|
||||
expect(result.to_html).to eq('<pre>This is a test</pre>')
|
||||
context "when an invalid language is specified" do
|
||||
it "highlights as plaintext" do
|
||||
result = filter('<pre><code class="gnuplot">This is a test</code></pre>')
|
||||
expect(result.to_html).to eq('<pre class="code highlight js-syntax-highlight plaintext"><code>This is a test</code></pre>')
|
||||
end
|
||||
end
|
||||
|
||||
context "when Rouge formatting fails" do
|
||||
before do
|
||||
allow_any_instance_of(Rouge::Formatter).to receive(:format).and_raise(StandardError)
|
||||
end
|
||||
|
||||
it "highlights as plaintext" do
|
||||
result = filter('<pre><code class="ruby">This is a test</code></pre>')
|
||||
expect(result.to_html).to eq('<pre class="code highlight"><code>This is a test</code></pre>')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -54,12 +54,12 @@ describe Gitlab::BitbucketImport::Client, lib: true do
|
|||
context 'project import' do
|
||||
it 'calls .from_project with no errors' do
|
||||
project = create(:empty_project)
|
||||
project.import_url = "ssh://git@bitbucket.org/test/test.git"
|
||||
project.create_or_update_import_data(credentials:
|
||||
{ user: "git",
|
||||
password: nil,
|
||||
bb_session: { bitbucket_access_token: "test",
|
||||
bitbucket_access_token_secret: "test" } })
|
||||
project.import_url = "ssh://git@bitbucket.org/test/test.git"
|
||||
|
||||
expect { described_class.from_project(project) }.not_to raise_error
|
||||
end
|
||||
|
|
|
@ -13,6 +13,10 @@ describe Gitlab::Database::MigrationHelpers, lib: true do
|
|||
context 'outside a transaction' do
|
||||
before do
|
||||
expect(model).to receive(:transaction_open?).and_return(false)
|
||||
|
||||
unless Gitlab::Database.postgresql?
|
||||
allow_any_instance_of(Gitlab::Database::MigrationHelpers).to receive(:disable_statement_timeout)
|
||||
end
|
||||
end
|
||||
|
||||
context 'using PostgreSQL' do
|
||||
|
|
|
@ -28,13 +28,13 @@ describe Gitlab::Diff::Highlight, lib: true do
|
|||
end
|
||||
|
||||
it 'highlights and marks removed lines' do
|
||||
code = %Q{-<span id="LC9" class="line"> <span class="k">raise</span> <span class="s2">"System commands must be given as an array of strings"</span></span>\n}
|
||||
code = %Q{-<span id="LC9" class="line"> <span class="k">raise</span> <span class="s2">"System commands must be given as an array of strings"</span></span>\n}
|
||||
|
||||
expect(subject[4].text).to eq(code)
|
||||
end
|
||||
|
||||
it 'highlights and marks added lines' do
|
||||
code = %Q{+<span id="LC9" class="line"> <span class="k">raise</span> <span class="no"><span class='idiff left'>RuntimeError</span></span><span class="p"><span class='idiff'>,</span></span><span class='idiff right'> </span><span class="s2">"System commands must be given as an array of strings"</span></span>\n}
|
||||
code = %Q{+<span id="LC9" class="line"> <span class="k">raise</span> <span class="no"><span class='idiff left'>RuntimeError</span></span><span class="p"><span class='idiff'>,</span></span><span class='idiff right'> </span><span class="s2">"System commands must be given as an array of strings"</span></span>\n}
|
||||
|
||||
expect(subject[5].text).to eq(code)
|
||||
end
|
||||
|
|
21
spec/lib/gitlab/import_export/import_export_spec.rb
Normal file
21
spec/lib/gitlab/import_export/import_export_spec.rb
Normal file
|
@ -0,0 +1,21 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe Gitlab::ImportExport, services: true do
|
||||
describe 'export filename' do
|
||||
let(:project) { create(:project, :public, path: 'project-path') }
|
||||
|
||||
it 'contains the project path' do
|
||||
expect(described_class.export_filename(project: project)).to include(project.path)
|
||||
end
|
||||
|
||||
it 'contains the namespace path' do
|
||||
expect(described_class.export_filename(project: project)).to include(project.namespace.path)
|
||||
end
|
||||
|
||||
it 'does not go over a certain length' do
|
||||
project.path = 'a' * 100
|
||||
|
||||
expect(described_class.export_filename(project: project).length).to be < 70
|
||||
end
|
||||
end
|
||||
end
|
|
@ -26,6 +26,7 @@
|
|||
"deleted_at": null,
|
||||
"due_date": null,
|
||||
"moved_to_id": null,
|
||||
"test_ee_field": "test",
|
||||
"notes": [
|
||||
{
|
||||
"id": 351,
|
||||
|
|
|
@ -30,6 +30,14 @@ describe Gitlab::ImportExport::ProjectTreeRestorer, services: true do
|
|||
expect(Event.where.not(data: nil).first.data[:ref]).not_to be_empty
|
||||
end
|
||||
|
||||
it 'preserves updated_at on issues' do
|
||||
restored_project_json
|
||||
|
||||
issue = Issue.where(description: 'Aliquam enim illo et possimus.').first
|
||||
|
||||
expect(issue.reload.updated_at.to_s).to eq('2016-06-14 15:02:47 UTC')
|
||||
end
|
||||
|
||||
context 'event at forth level of the tree' do
|
||||
let(:event) { Event.where(title: 'test levels').first }
|
||||
|
||||
|
|
|
@ -1,730 +0,0 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe Gitlab::Lfs::Router, lib: true do
|
||||
let(:project) { create(:project) }
|
||||
let(:public_project) { create(:project, :public) }
|
||||
let(:forked_project) { fork_project(public_project, user) }
|
||||
|
||||
let(:user) { create(:user) }
|
||||
let(:user_two) { create(:user) }
|
||||
let!(:lfs_object) { create(:lfs_object, :with_file) }
|
||||
|
||||
let(:request) { Rack::Request.new(env) }
|
||||
let(:env) do
|
||||
{
|
||||
'rack.input' => '',
|
||||
'REQUEST_METHOD' => 'GET',
|
||||
}
|
||||
end
|
||||
|
||||
let(:lfs_router_auth) { new_lfs_router(project, user: user) }
|
||||
let(:lfs_router_ci_auth) { new_lfs_router(project, ci: true) }
|
||||
let(:lfs_router_noauth) { new_lfs_router(project) }
|
||||
let(:lfs_router_public_auth) { new_lfs_router(public_project, user: user) }
|
||||
let(:lfs_router_public_ci_auth) { new_lfs_router(public_project, ci: true) }
|
||||
let(:lfs_router_public_noauth) { new_lfs_router(public_project) }
|
||||
let(:lfs_router_forked_noauth) { new_lfs_router(forked_project) }
|
||||
let(:lfs_router_forked_auth) { new_lfs_router(forked_project, user: user_two) }
|
||||
let(:lfs_router_forked_ci_auth) { new_lfs_router(forked_project, ci: true) }
|
||||
|
||||
let(:sample_oid) { "b68143e6463773b1b6c6fd009a76c32aeec041faff32ba2ed42fd7f708a17f80" }
|
||||
let(:sample_size) { 499013 }
|
||||
let(:respond_with_deprecated) {[ 501, { "Content-Type" => "application/json; charset=utf-8" }, ["{\"message\":\"Server supports batch API only, please update your Git LFS client to version 1.0.1 and up.\",\"documentation_url\":\"#{Gitlab.config.gitlab.url}/help\"}"]]}
|
||||
let(:respond_with_disabled) {[ 501, { "Content-Type" => "application/json; charset=utf-8" }, ["{\"message\":\"Git LFS is not enabled on this GitLab server, contact your admin.\",\"documentation_url\":\"#{Gitlab.config.gitlab.url}/help\"}"]]}
|
||||
|
||||
describe 'when lfs is disabled' do
|
||||
before do
|
||||
allow(Gitlab.config.lfs).to receive(:enabled).and_return(false)
|
||||
env['REQUEST_METHOD'] = 'POST'
|
||||
body = {
|
||||
'objects' => [
|
||||
{ 'oid' => '91eff75a492a3ed0dfcb544d7f31326bc4014c8551849c192fd1e48d4dd2c897',
|
||||
'size' => 1575078
|
||||
},
|
||||
{ 'oid' => sample_oid,
|
||||
'size' => sample_size
|
||||
}
|
||||
],
|
||||
'operation' => 'upload'
|
||||
}.to_json
|
||||
env['rack.input'] = StringIO.new(body)
|
||||
env["PATH_INFO"] = "#{project.repository.path_with_namespace}.git/info/lfs/objects/batch"
|
||||
end
|
||||
|
||||
it 'responds with 501' do
|
||||
expect(lfs_router_auth.try_call).to match_array(respond_with_disabled)
|
||||
end
|
||||
end
|
||||
|
||||
describe 'when fetching lfs object using deprecated API' do
|
||||
before do
|
||||
enable_lfs
|
||||
env["PATH_INFO"] = "#{project.repository.path_with_namespace}.git/info/lfs/objects/#{sample_oid}"
|
||||
end
|
||||
|
||||
it 'responds with 501' do
|
||||
expect(lfs_router_auth.try_call).to match_array(respond_with_deprecated)
|
||||
end
|
||||
end
|
||||
|
||||
describe 'when fetching lfs object' do
|
||||
before do
|
||||
enable_lfs
|
||||
env['HTTP_ACCEPT'] = "application/vnd.git-lfs+json; charset=utf-8"
|
||||
env["PATH_INFO"] = "#{project.repository.path_with_namespace}.git/gitlab-lfs/objects/#{sample_oid}"
|
||||
end
|
||||
|
||||
describe 'and request comes from gitlab-workhorse' do
|
||||
context 'without user being authorized' do
|
||||
it "responds with status 401" do
|
||||
expect(lfs_router_noauth.try_call.first).to eq(401)
|
||||
end
|
||||
end
|
||||
|
||||
context 'with required headers' do
|
||||
before do
|
||||
project.lfs_objects << lfs_object
|
||||
env['HTTP_X_SENDFILE_TYPE'] = "X-Sendfile"
|
||||
end
|
||||
|
||||
context 'when user does not have project access' do
|
||||
it "responds with status 403" do
|
||||
expect(lfs_router_auth.try_call.first).to eq(403)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when user has project access' do
|
||||
before do
|
||||
project.team << [user, :master]
|
||||
end
|
||||
|
||||
it "responds with status 200" do
|
||||
expect(lfs_router_auth.try_call.first).to eq(200)
|
||||
end
|
||||
|
||||
it "responds with the file location" do
|
||||
expect(lfs_router_auth.try_call[1]['Content-Type']).to eq("application/octet-stream")
|
||||
expect(lfs_router_auth.try_call[1]['X-Sendfile']).to eq(lfs_object.file.path)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when CI is authorized' do
|
||||
it "responds with status 200" do
|
||||
expect(lfs_router_ci_auth.try_call.first).to eq(200)
|
||||
end
|
||||
|
||||
it "responds with the file location" do
|
||||
expect(lfs_router_ci_auth.try_call[1]['Content-Type']).to eq("application/octet-stream")
|
||||
expect(lfs_router_ci_auth.try_call[1]['X-Sendfile']).to eq(lfs_object.file.path)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'without required headers' do
|
||||
it "responds with status 403" do
|
||||
expect(lfs_router_auth.try_call.first).to eq(403)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'when handling lfs request using deprecated API' do
|
||||
before do
|
||||
enable_lfs
|
||||
env['REQUEST_METHOD'] = 'POST'
|
||||
env["PATH_INFO"] = "#{project.repository.path_with_namespace}.git/info/lfs/objects"
|
||||
end
|
||||
|
||||
it 'responds with 501' do
|
||||
expect(lfs_router_auth.try_call).to match_array(respond_with_deprecated)
|
||||
end
|
||||
end
|
||||
|
||||
describe 'when handling lfs batch request' do
|
||||
before do
|
||||
enable_lfs
|
||||
env['REQUEST_METHOD'] = 'POST'
|
||||
env['PATH_INFO'] = "#{project.repository.path_with_namespace}.git/info/lfs/objects/batch"
|
||||
end
|
||||
|
||||
describe 'download' do
|
||||
before do
|
||||
body = { 'operation' => 'download',
|
||||
'objects' => [
|
||||
{ 'oid' => sample_oid,
|
||||
'size' => sample_size
|
||||
}]
|
||||
}.to_json
|
||||
env['rack.input'] = StringIO.new(body)
|
||||
end
|
||||
|
||||
shared_examples 'an authorized requests' do
|
||||
context 'when downloading an lfs object that is assigned to our project' do
|
||||
before do
|
||||
project.lfs_objects << lfs_object
|
||||
end
|
||||
|
||||
it 'responds with status 200 and href to download' do
|
||||
response = router.try_call
|
||||
expect(response.first).to eq(200)
|
||||
response_body = ActiveSupport::JSON.decode(response.last.first)
|
||||
|
||||
expect(response_body).to eq('objects' => [
|
||||
{ 'oid' => sample_oid,
|
||||
'size' => sample_size,
|
||||
'actions' => {
|
||||
'download' => {
|
||||
'href' => "#{project.http_url_to_repo}/gitlab-lfs/objects/#{sample_oid}",
|
||||
'header' => { 'Authorization' => auth }
|
||||
}
|
||||
}
|
||||
}])
|
||||
end
|
||||
end
|
||||
|
||||
context 'when downloading an lfs object that is assigned to other project' do
|
||||
before do
|
||||
public_project.lfs_objects << lfs_object
|
||||
end
|
||||
|
||||
it 'responds with status 200 and error message' do
|
||||
response = router.try_call
|
||||
expect(response.first).to eq(200)
|
||||
response_body = ActiveSupport::JSON.decode(response.last.first)
|
||||
|
||||
expect(response_body).to eq('objects' => [
|
||||
{ 'oid' => sample_oid,
|
||||
'size' => sample_size,
|
||||
'error' => {
|
||||
'code' => 404,
|
||||
'message' => "Object does not exist on the server or you don't have permissions to access it",
|
||||
}
|
||||
}])
|
||||
end
|
||||
end
|
||||
|
||||
context 'when downloading a lfs object that does not exist' do
|
||||
before do
|
||||
body = { 'operation' => 'download',
|
||||
'objects' => [
|
||||
{ 'oid' => '91eff75a492a3ed0dfcb544d7f31326bc4014c8551849c192fd1e48d4dd2c897',
|
||||
'size' => 1575078
|
||||
}]
|
||||
}.to_json
|
||||
env['rack.input'] = StringIO.new(body)
|
||||
end
|
||||
|
||||
it "responds with status 200 and error message" do
|
||||
response = router.try_call
|
||||
expect(response.first).to eq(200)
|
||||
response_body = ActiveSupport::JSON.decode(response.last.first)
|
||||
|
||||
expect(response_body).to eq('objects' => [
|
||||
{ 'oid' => '91eff75a492a3ed0dfcb544d7f31326bc4014c8551849c192fd1e48d4dd2c897',
|
||||
'size' => 1575078,
|
||||
'error' => {
|
||||
'code' => 404,
|
||||
'message' => "Object does not exist on the server or you don't have permissions to access it",
|
||||
}
|
||||
}])
|
||||
end
|
||||
end
|
||||
|
||||
context 'when downloading one new and one existing lfs object' do
|
||||
before do
|
||||
body = { 'operation' => 'download',
|
||||
'objects' => [
|
||||
{ 'oid' => '91eff75a492a3ed0dfcb544d7f31326bc4014c8551849c192fd1e48d4dd2c897',
|
||||
'size' => 1575078
|
||||
},
|
||||
{ 'oid' => sample_oid,
|
||||
'size' => sample_size
|
||||
}
|
||||
]
|
||||
}.to_json
|
||||
env['rack.input'] = StringIO.new(body)
|
||||
project.lfs_objects << lfs_object
|
||||
end
|
||||
|
||||
it "responds with status 200 with upload hypermedia link for the new object" do
|
||||
response = router.try_call
|
||||
expect(response.first).to eq(200)
|
||||
response_body = ActiveSupport::JSON.decode(response.last.first)
|
||||
|
||||
expect(response_body).to eq('objects' => [
|
||||
{ 'oid' => '91eff75a492a3ed0dfcb544d7f31326bc4014c8551849c192fd1e48d4dd2c897',
|
||||
'size' => 1575078,
|
||||
'error' => {
|
||||
'code' => 404,
|
||||
'message' => "Object does not exist on the server or you don't have permissions to access it",
|
||||
}
|
||||
},
|
||||
{ 'oid' => sample_oid,
|
||||
'size' => sample_size,
|
||||
'actions' => {
|
||||
'download' => {
|
||||
'href' => "#{project.http_url_to_repo}/gitlab-lfs/objects/#{sample_oid}",
|
||||
'header' => { 'Authorization' => auth }
|
||||
}
|
||||
}
|
||||
}])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when user is authenticated' do
|
||||
let(:auth) { authorize(user) }
|
||||
|
||||
before do
|
||||
env["HTTP_AUTHORIZATION"] = auth
|
||||
project.team << [user, role]
|
||||
end
|
||||
|
||||
it_behaves_like 'an authorized requests' do
|
||||
let(:role) { :reporter }
|
||||
let(:router) { lfs_router_auth }
|
||||
end
|
||||
|
||||
context 'when user does is not member of the project' do
|
||||
let(:role) { :guest }
|
||||
|
||||
it 'responds with 403' do
|
||||
expect(lfs_router_auth.try_call.first).to eq(403)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when user does not have download access' do
|
||||
let(:role) { :guest }
|
||||
|
||||
it 'responds with 403' do
|
||||
expect(lfs_router_auth.try_call.first).to eq(403)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when CI is authorized' do
|
||||
let(:auth) { 'gitlab-ci-token:password' }
|
||||
|
||||
before do
|
||||
env["HTTP_AUTHORIZATION"] = auth
|
||||
end
|
||||
|
||||
it_behaves_like 'an authorized requests' do
|
||||
let(:router) { lfs_router_ci_auth }
|
||||
end
|
||||
end
|
||||
|
||||
context 'when user is not authenticated' do
|
||||
describe 'is accessing public project' do
|
||||
before do
|
||||
public_project.lfs_objects << lfs_object
|
||||
end
|
||||
|
||||
it 'responds with status 200 and href to download' do
|
||||
response = lfs_router_public_noauth.try_call
|
||||
expect(response.first).to eq(200)
|
||||
response_body = ActiveSupport::JSON.decode(response.last.first)
|
||||
|
||||
expect(response_body).to eq('objects' => [
|
||||
{ 'oid' => sample_oid,
|
||||
'size' => sample_size,
|
||||
'actions' => {
|
||||
'download' => {
|
||||
'href' => "#{public_project.http_url_to_repo}/gitlab-lfs/objects/#{sample_oid}",
|
||||
'header' => {}
|
||||
}
|
||||
}
|
||||
}])
|
||||
end
|
||||
end
|
||||
|
||||
describe 'is accessing non-public project' do
|
||||
before do
|
||||
project.lfs_objects << lfs_object
|
||||
end
|
||||
|
||||
it 'responds with authorization required' do
|
||||
expect(lfs_router_noauth.try_call.first).to eq(401)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'upload' do
|
||||
before do
|
||||
body = { 'operation' => 'upload',
|
||||
'objects' => [
|
||||
{ 'oid' => sample_oid,
|
||||
'size' => sample_size
|
||||
}]
|
||||
}.to_json
|
||||
env['rack.input'] = StringIO.new(body)
|
||||
end
|
||||
|
||||
describe 'when request is authenticated' do
|
||||
describe 'when user has project push access' do
|
||||
before do
|
||||
@auth = authorize(user)
|
||||
env["HTTP_AUTHORIZATION"] = @auth
|
||||
project.team << [user, :developer]
|
||||
end
|
||||
|
||||
context 'when pushing an lfs object that already exists' do
|
||||
before do
|
||||
public_project.lfs_objects << lfs_object
|
||||
end
|
||||
|
||||
it "responds with status 200 and links the object to the project" do
|
||||
response_body = lfs_router_auth.try_call.last
|
||||
response = ActiveSupport::JSON.decode(response_body.first)
|
||||
|
||||
expect(response['objects']).to be_kind_of(Array)
|
||||
expect(response['objects'].first['oid']).to eq(sample_oid)
|
||||
expect(response['objects'].first['size']).to eq(sample_size)
|
||||
expect(lfs_object.projects.pluck(:id)).not_to include(project.id)
|
||||
expect(lfs_object.projects.pluck(:id)).to include(public_project.id)
|
||||
expect(response['objects'].first['actions']['upload']['href']).to eq("#{Gitlab.config.gitlab.url}/#{project.path_with_namespace}.git/gitlab-lfs/objects/#{sample_oid}/#{sample_size}")
|
||||
expect(response['objects'].first['actions']['upload']['header']).to eq('Authorization' => @auth)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when pushing a lfs object that does not exist' do
|
||||
before do
|
||||
body = { 'operation' => 'upload',
|
||||
'objects' => [
|
||||
{ 'oid' => '91eff75a492a3ed0dfcb544d7f31326bc4014c8551849c192fd1e48d4dd2c897',
|
||||
'size' => 1575078
|
||||
}]
|
||||
}.to_json
|
||||
env['rack.input'] = StringIO.new(body)
|
||||
end
|
||||
|
||||
it "responds with status 200 and upload hypermedia link" do
|
||||
response = lfs_router_auth.try_call
|
||||
expect(response.first).to eq(200)
|
||||
|
||||
response_body = ActiveSupport::JSON.decode(response.last.first)
|
||||
expect(response_body['objects']).to be_kind_of(Array)
|
||||
expect(response_body['objects'].first['oid']).to eq("91eff75a492a3ed0dfcb544d7f31326bc4014c8551849c192fd1e48d4dd2c897")
|
||||
expect(response_body['objects'].first['size']).to eq(1575078)
|
||||
expect(lfs_object.projects.pluck(:id)).not_to include(project.id)
|
||||
expect(response_body['objects'].first['actions']['upload']['href']).to eq("#{Gitlab.config.gitlab.url}/#{project.path_with_namespace}.git/gitlab-lfs/objects/91eff75a492a3ed0dfcb544d7f31326bc4014c8551849c192fd1e48d4dd2c897/1575078")
|
||||
expect(response_body['objects'].first['actions']['upload']['header']).to eq('Authorization' => @auth)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when pushing one new and one existing lfs object' do
|
||||
before do
|
||||
body = { 'operation' => 'upload',
|
||||
'objects' => [
|
||||
{ 'oid' => '91eff75a492a3ed0dfcb544d7f31326bc4014c8551849c192fd1e48d4dd2c897',
|
||||
'size' => 1575078
|
||||
},
|
||||
{ 'oid' => sample_oid,
|
||||
'size' => sample_size
|
||||
}
|
||||
]
|
||||
}.to_json
|
||||
env['rack.input'] = StringIO.new(body)
|
||||
project.lfs_objects << lfs_object
|
||||
end
|
||||
|
||||
it "responds with status 200 with upload hypermedia link for the new object" do
|
||||
response = lfs_router_auth.try_call
|
||||
expect(response.first).to eq(200)
|
||||
|
||||
response_body = ActiveSupport::JSON.decode(response.last.first)
|
||||
expect(response_body['objects']).to be_kind_of(Array)
|
||||
|
||||
expect(response_body['objects'].first['oid']).to eq("91eff75a492a3ed0dfcb544d7f31326bc4014c8551849c192fd1e48d4dd2c897")
|
||||
expect(response_body['objects'].first['size']).to eq(1575078)
|
||||
expect(response_body['objects'].first['actions']['upload']['href']).to eq("#{Gitlab.config.gitlab.url}/#{project.path_with_namespace}.git/gitlab-lfs/objects/91eff75a492a3ed0dfcb544d7f31326bc4014c8551849c192fd1e48d4dd2c897/1575078")
|
||||
expect(response_body['objects'].first['actions']['upload']['header']).to eq("Authorization" => @auth)
|
||||
|
||||
expect(response_body['objects'].last['oid']).to eq(sample_oid)
|
||||
expect(response_body['objects'].last['size']).to eq(sample_size)
|
||||
expect(response_body['objects'].last).not_to have_key('actions')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when user does not have push access' do
|
||||
it 'responds with 403' do
|
||||
expect(lfs_router_auth.try_call.first).to eq(403)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when CI is authorized' do
|
||||
it 'responds with 401' do
|
||||
expect(lfs_router_ci_auth.try_call.first).to eq(401)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when user is not authenticated' do
|
||||
context 'when user has push access' do
|
||||
before do
|
||||
project.team << [user, :master]
|
||||
end
|
||||
|
||||
it "responds with status 401" do
|
||||
expect(lfs_router_public_noauth.try_call.first).to eq(401)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when user does not have push access' do
|
||||
it "responds with status 401" do
|
||||
expect(lfs_router_public_noauth.try_call.first).to eq(401)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when CI is authorized' do
|
||||
let(:auth) { 'gitlab-ci-token:password' }
|
||||
|
||||
before do
|
||||
env["HTTP_AUTHORIZATION"] = auth
|
||||
end
|
||||
|
||||
it "responds with status 403" do
|
||||
expect(lfs_router_public_ci_auth.try_call.first).to eq(401)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'unsupported' do
|
||||
before do
|
||||
body = { 'operation' => 'other',
|
||||
'objects' => [
|
||||
{ 'oid' => sample_oid,
|
||||
'size' => sample_size
|
||||
}]
|
||||
}.to_json
|
||||
env['rack.input'] = StringIO.new(body)
|
||||
end
|
||||
|
||||
it 'responds with status 404' do
|
||||
expect(lfs_router_public_noauth.try_call.first).to eq(404)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'when pushing a lfs object' do
|
||||
before do
|
||||
enable_lfs
|
||||
env['REQUEST_METHOD'] = 'PUT'
|
||||
end
|
||||
|
||||
shared_examples 'unauthorized' do
|
||||
context 'and request is sent by gitlab-workhorse to authorize the request' do
|
||||
before do
|
||||
header_for_upload_authorize(router.project)
|
||||
end
|
||||
|
||||
it 'responds with status 401' do
|
||||
expect(router.try_call.first).to eq(401)
|
||||
end
|
||||
end
|
||||
|
||||
context 'and request is sent by gitlab-workhorse to finalize the upload' do
|
||||
before do
|
||||
headers_for_upload_finalize(router.project)
|
||||
end
|
||||
|
||||
it 'responds with status 401' do
|
||||
expect(router.try_call.first).to eq(401)
|
||||
end
|
||||
end
|
||||
|
||||
context 'and request is sent with a malformed headers' do
|
||||
before do
|
||||
env["PATH_INFO"] = "#{router.project.repository.path_with_namespace}.git/gitlab-lfs/objects/#{sample_oid}/#{sample_size}"
|
||||
env["HTTP_X_GITLAB_LFS_TMP"] = "cat /etc/passwd"
|
||||
end
|
||||
|
||||
it 'does not recognize it as a valid lfs command' do
|
||||
expect(router.try_call).to eq(nil)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
shared_examples 'forbidden' do
|
||||
context 'and request is sent by gitlab-workhorse to authorize the request' do
|
||||
before do
|
||||
header_for_upload_authorize(router.project)
|
||||
end
|
||||
|
||||
it 'responds with 403' do
|
||||
expect(router.try_call.first).to eq(403)
|
||||
end
|
||||
end
|
||||
|
||||
context 'and request is sent by gitlab-workhorse to finalize the upload' do
|
||||
before do
|
||||
headers_for_upload_finalize(router.project)
|
||||
end
|
||||
|
||||
it 'responds with 403' do
|
||||
expect(router.try_call.first).to eq(403)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'to one project' do
|
||||
describe 'when user is authenticated' do
|
||||
describe 'when user has push access to the project' do
|
||||
before do
|
||||
project.team << [user, :developer]
|
||||
end
|
||||
|
||||
context 'and request is sent by gitlab-workhorse to authorize the request' do
|
||||
before do
|
||||
header_for_upload_authorize(project)
|
||||
end
|
||||
|
||||
it 'responds with status 200, location of lfs store and object details' do
|
||||
json_response = ActiveSupport::JSON.decode(lfs_router_auth.try_call.last.first)
|
||||
|
||||
expect(lfs_router_auth.try_call.first).to eq(200)
|
||||
expect(json_response['StoreLFSPath']).to eq("#{Gitlab.config.shared.path}/lfs-objects/tmp/upload")
|
||||
expect(json_response['LfsOid']).to eq(sample_oid)
|
||||
expect(json_response['LfsSize']).to eq(sample_size)
|
||||
end
|
||||
end
|
||||
|
||||
context 'and request is sent by gitlab-workhorse to finalize the upload' do
|
||||
before do
|
||||
headers_for_upload_finalize(project)
|
||||
end
|
||||
|
||||
it 'responds with status 200 and lfs object is linked to the project' do
|
||||
expect(lfs_router_auth.try_call.first).to eq(200)
|
||||
expect(lfs_object.projects.pluck(:id)).to include(project.id)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'and user does not have push access' do
|
||||
let(:router) { lfs_router_auth }
|
||||
|
||||
it_behaves_like 'forbidden'
|
||||
end
|
||||
end
|
||||
|
||||
context 'when CI is authenticated' do
|
||||
let(:router) { lfs_router_ci_auth }
|
||||
|
||||
it_behaves_like 'unauthorized'
|
||||
end
|
||||
|
||||
context 'for unauthenticated' do
|
||||
let(:router) { new_lfs_router(project) }
|
||||
|
||||
it_behaves_like 'unauthorized'
|
||||
end
|
||||
end
|
||||
|
||||
describe 'to a forked project' do
|
||||
let(:forked_project) { fork_project(public_project, user) }
|
||||
|
||||
describe 'when user is authenticated' do
|
||||
describe 'when user has push access to the project' do
|
||||
before do
|
||||
forked_project.team << [user_two, :developer]
|
||||
end
|
||||
|
||||
context 'and request is sent by gitlab-workhorse to authorize the request' do
|
||||
before do
|
||||
header_for_upload_authorize(forked_project)
|
||||
end
|
||||
|
||||
it 'responds with status 200, location of lfs store and object details' do
|
||||
json_response = ActiveSupport::JSON.decode(lfs_router_forked_auth.try_call.last.first)
|
||||
|
||||
expect(lfs_router_forked_auth.try_call.first).to eq(200)
|
||||
expect(json_response['StoreLFSPath']).to eq("#{Gitlab.config.shared.path}/lfs-objects/tmp/upload")
|
||||
expect(json_response['LfsOid']).to eq(sample_oid)
|
||||
expect(json_response['LfsSize']).to eq(sample_size)
|
||||
end
|
||||
end
|
||||
|
||||
context 'and request is sent by gitlab-workhorse to finalize the upload' do
|
||||
before do
|
||||
headers_for_upload_finalize(forked_project)
|
||||
end
|
||||
|
||||
it 'responds with status 200 and lfs object is linked to the source project' do
|
||||
expect(lfs_router_forked_auth.try_call.first).to eq(200)
|
||||
expect(lfs_object.projects.pluck(:id)).to include(public_project.id)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'and user does not have push access' do
|
||||
let(:router) { lfs_router_forked_auth }
|
||||
|
||||
it_behaves_like 'forbidden'
|
||||
end
|
||||
end
|
||||
|
||||
context 'when CI is authenticated' do
|
||||
let(:router) { lfs_router_forked_ci_auth }
|
||||
|
||||
it_behaves_like 'unauthorized'
|
||||
end
|
||||
|
||||
context 'for unauthenticated' do
|
||||
let(:router) { lfs_router_forked_noauth }
|
||||
|
||||
it_behaves_like 'unauthorized'
|
||||
end
|
||||
|
||||
describe 'and second project not related to fork or a source project' do
|
||||
let(:second_project) { create(:project) }
|
||||
let(:lfs_router_second_project) { new_lfs_router(second_project, user: user) }
|
||||
|
||||
before do
|
||||
public_project.lfs_objects << lfs_object
|
||||
headers_for_upload_finalize(second_project)
|
||||
end
|
||||
|
||||
context 'when pushing the same lfs object to the second project' do
|
||||
before do
|
||||
second_project.team << [user, :master]
|
||||
end
|
||||
|
||||
it 'responds with 200 and links the lfs object to the project' do
|
||||
expect(lfs_router_second_project.try_call.first).to eq(200)
|
||||
expect(lfs_object.projects.pluck(:id)).to include(second_project.id, public_project.id)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def enable_lfs
|
||||
allow(Gitlab.config.lfs).to receive(:enabled).and_return(true)
|
||||
end
|
||||
|
||||
def authorize(user)
|
||||
ActionController::HttpAuthentication::Basic.encode_credentials(user.username, user.password)
|
||||
end
|
||||
|
||||
def new_lfs_router(project, user: nil, ci: false)
|
||||
Gitlab::Lfs::Router.new(project, user, ci, request)
|
||||
end
|
||||
|
||||
def header_for_upload_authorize(project)
|
||||
env["PATH_INFO"] = "#{project.repository.path_with_namespace}.git/gitlab-lfs/objects/#{sample_oid}/#{sample_size}/authorize"
|
||||
end
|
||||
|
||||
def headers_for_upload_finalize(project)
|
||||
env["PATH_INFO"] = "#{project.repository.path_with_namespace}.git/gitlab-lfs/objects/#{sample_oid}/#{sample_size}"
|
||||
env["HTTP_X_GITLAB_LFS_TMP"] = "#{sample_oid}6e561c9d4"
|
||||
end
|
||||
|
||||
def fork_project(project, user, object = nil)
|
||||
allow(RepositoryForkWorker).to receive(:perform_async).and_return(true)
|
||||
Projects::ForkService.new(project, user, {}).execute
|
||||
end
|
||||
end
|
|
@ -5,9 +5,12 @@ describe Ci::Pipeline, models: true do
|
|||
let(:pipeline) { FactoryGirl.create :ci_pipeline, project: project }
|
||||
|
||||
it { is_expected.to belong_to(:project) }
|
||||
it { is_expected.to belong_to(:user) }
|
||||
|
||||
it { is_expected.to have_many(:statuses) }
|
||||
it { is_expected.to have_many(:trigger_requests) }
|
||||
it { is_expected.to have_many(:builds) }
|
||||
|
||||
it { is_expected.to validate_presence_of :sha }
|
||||
it { is_expected.to validate_presence_of :status }
|
||||
|
||||
|
|
|
@ -177,10 +177,10 @@ describe CommitStatus, models: true do
|
|||
|
||||
describe '#stages' do
|
||||
before do
|
||||
FactoryGirl.create :commit_status, pipeline: pipeline, stage: 'build', stage_idx: 0, status: 'success'
|
||||
FactoryGirl.create :commit_status, pipeline: pipeline, stage: 'build', stage_idx: 0, status: 'failed'
|
||||
FactoryGirl.create :commit_status, pipeline: pipeline, stage: 'deploy', stage_idx: 2, status: 'running'
|
||||
FactoryGirl.create :commit_status, pipeline: pipeline, stage: 'test', stage_idx: 1, status: 'success'
|
||||
create :commit_status, pipeline: pipeline, stage: 'build', name: 'linux', stage_idx: 0, status: 'success'
|
||||
create :commit_status, pipeline: pipeline, stage: 'build', name: 'mac', stage_idx: 0, status: 'failed'
|
||||
create :commit_status, pipeline: pipeline, stage: 'deploy', name: 'staging', stage_idx: 2, status: 'running'
|
||||
create :commit_status, pipeline: pipeline, stage: 'test', name: 'rspec', stage_idx: 1, status: 'success'
|
||||
end
|
||||
|
||||
context 'stages list' do
|
||||
|
@ -192,7 +192,7 @@ describe CommitStatus, models: true do
|
|||
end
|
||||
|
||||
context 'stages with statuses' do
|
||||
subject { CommitStatus.where(pipeline: pipeline).stages_status }
|
||||
subject { CommitStatus.where(pipeline: pipeline).latest.stages_status }
|
||||
|
||||
it 'return list of stages with statuses' do
|
||||
is_expected.to eq({
|
||||
|
@ -201,6 +201,20 @@ describe CommitStatus, models: true do
|
|||
'deploy' => 'running'
|
||||
})
|
||||
end
|
||||
|
||||
context 'when build is retried' do
|
||||
before do
|
||||
create :commit_status, pipeline: pipeline, stage: 'build', name: 'mac', stage_idx: 0, status: 'success'
|
||||
end
|
||||
|
||||
it 'ignores a previous state' do
|
||||
is_expected.to eq({
|
||||
'build' => 'success',
|
||||
'test' => 'success',
|
||||
'deploy' => 'running'
|
||||
})
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue