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:
Kamil Trzcinski 2016-07-18 10:40:22 +02:00
commit ffea9c4600
111 changed files with 1980 additions and 1674 deletions

View file

@ -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
View 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

View file

@ -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

View file

@ -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

View file

@ -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)

View file

@ -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()

View file

@ -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()

View file

@ -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'

View file

@ -62,7 +62,7 @@ class @MilestoneSelect
title: 'Upcoming'
)
if extraOptions.length > 0
if extraOptions.length > 2
extraOptions.push 'divider'
callback(extraOptions.concat(data))

View file

@ -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);

View file

@ -0,0 +1,3 @@
class @U2FUtil
@isU2FSupported: ->
window.u2f

View file

@ -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 %>

View file

@ -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

View file

@ -56,7 +56,7 @@
position: absolute;
top: 50%;
right: 6px;
margin-top: -6px;
margin-top: -4px;
color: $dropdown-toggle-icon-color;
font-size: 10px;
}

View file

@ -324,10 +324,6 @@
.issuable-form-select-holder {
display: inline-block;
width: 250px;
.dropdown-menu-toggle {
width: 100%;
}
}
.table-holder {

View file

@ -129,6 +129,8 @@
}
.cancel-retry-btns {
vertical-align: middle;
.btn:not(:first-child) {
margin-left: 8px;
}

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -0,0 +1,5 @@
module U2fHelper
def inject_u2f_api?
browser.chrome? && browser.version.to_i >= 41 && !browser.device.mobile?
end
end

View file

@ -204,7 +204,8 @@ class Ability
:download_code,
:fork_project,
:read_commit_status,
:read_pipeline
:read_pipeline,
:read_container_image
]
end

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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')

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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)}"] = {

View file

@ -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

View file

@ -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

View file

@ -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")

View file

@ -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'

View file

@ -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

View file

@ -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 }

View file

@ -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

View file

@ -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)

View file

@ -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'

View file

@ -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

View file

@ -0,0 +1,7 @@
class AddUserIdToPipeline < ActiveRecord::Migration
include Gitlab::Database::MigrationHelpers
def change
add_column :ci_commits, :user_id, :integer
end
end

View file

@ -0,0 +1,7 @@
class AddIndexForPipelineUserId < ActiveRecord::Migration
include Gitlab::Database::MigrationHelpers
def change
add_concurrent_index :ci_commits, :user_id
end
end

View file

@ -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

View file

@ -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
```

View file

@ -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

View file

@ -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"

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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}")

View file

@ -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])

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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'

View file

@ -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)

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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)

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -121,7 +121,7 @@
:type: old
:number: 9
:text: |
-<span id="LC9" class="line"> <span class="k">raise</span> <span class="s2">&quot;System commands must be given as an array of strings&quot;</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">&quot;System commands must be given as an array of strings&quot;</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">&quot;PWD&quot;</span> <span class="o">=&gt;</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">=&gt;</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">&quot;PWD&quot;</span> <span class="o">=&gt;</span> <span class="n">path</span></span>
+<span id="LC15" class="line"> <span class="s2">"PWD"</span> <span class="o">=&gt;</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">&quot;&quot;</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">&quot;&quot;</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:

View file

@ -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 &quot;assem&quot;))</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">&quot;assem&quot;</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">&quot;assem&quot;</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 }

View file

@ -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

View file

@ -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', ->

View file

@ -5,7 +5,6 @@
#= require ./mock_u2f_device
describe 'U2FRegister', ->
U2FUtil.enableTestMode()
fixture.load('u2f/register')
beforeEach ->

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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">&quot;System commands must be given as an array of strings&quot;</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">&quot;System commands must be given as an array of strings&quot;</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

View 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

View file

@ -26,6 +26,7 @@
"deleted_at": null,
"due_date": null,
"moved_to_id": null,
"test_ee_field": "test",
"notes": [
{
"id": 351,

View file

@ -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 }

View file

@ -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

View file

@ -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 }

View file

@ -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