Merge branch 'master' into 'docs-specific-review-examples'

# Conflicts:
#   doc/development/code_review.md
This commit is contained in:
Clement Ho 2017-08-01 18:23:36 +00:00
commit 9ba8685ea7
281 changed files with 3383 additions and 1627 deletions

View File

@ -96,6 +96,7 @@ stages:
- export KNAPSACK_GENERATE_REPORT=true
- export CACHE_CLASSES=true
- cp ${KNAPSACK_RSPEC_SUITE_REPORT_PATH} ${KNAPSACK_REPORT_PATH}
- scripts/gitaly-test-spawn
- knapsack rspec "--color --format documentation"
artifacts:
expire_in: 31d
@ -221,6 +222,7 @@ setup-test-env:
- bundle exec rake gettext:po_to_json
- bundle exec rake gitlab:assets:compile
- bundle exec ruby -Ispec -e 'require "spec_helper" ; TestEnv.init'
- scripts/gitaly-test-build # Do not use 'bundle exec' here
artifacts:
expire_in: 7d
paths:
@ -486,6 +488,7 @@ karma:
BABEL_ENV: "coverage"
CHROME_LOG_FILE: "chrome_debug.log"
script:
- scripts/gitaly-test-spawn
- bundle exec rake gettext:po_to_json
- bundle exec rake karma
coverage: '/^Statements *: (\d+\.\d+%)/'

View File

@ -6,6 +6,7 @@ inherit_from: .rubocop_todo.yml
AllCops:
TargetRubyVersion: 2.3
TargetRailsVersion: 4.2
# Cop names are not d§splayed in offense messages by default. Change behavior
# by overriding DisplayCopNames, or by giving the -D/--display-cop-names
# option.
@ -29,12 +30,221 @@ AllCops:
Bundler/OrderedGems:
Enabled: false
# Style #######################################################################
# Layout ######################################################################
# Check indentation of private/protected visibility modifiers.
Style/AccessModifierIndentation:
Layout/AccessModifierIndentation:
Enabled: true
# Align the elements of an array literal if they span more than one line.
Layout/AlignArray:
Enabled: true
# Align the elements of a hash literal if they span more than one line.
Layout/AlignHash:
Enabled: true
# Here we check if the parameters on a multi-line method call or
# definition are aligned.
Layout/AlignParameters:
Enabled: false
# Put end statement of multiline block on its own line.
Layout/BlockEndNewline:
Enabled: true
# Indentation of when in a case/when/[else/]end.
Layout/CaseIndentation:
Enabled: true
# Indentation of comments.
Layout/CommentIndentation:
Enabled: true
# Multi-line method chaining should be done with leading dots.
Layout/DotPosition:
Enabled: true
EnforcedStyle: leading
# Align elses and elsifs correctly.
Layout/ElseAlignment:
Enabled: true
# Add an empty line after magic comments to separate them from code.
Layout/EmptyLineAfterMagicComment:
Enabled: false
# Use empty lines between defs.
Layout/EmptyLineBetweenDefs:
Enabled: true
# Don't use several empty lines in a row.
Layout/EmptyLines:
Enabled: true
# Keep blank lines around access modifiers.
Layout/EmptyLinesAroundAccessModifier:
Enabled: true
# Keeps track of empty lines around block bodies.
Layout/EmptyLinesAroundBlockBody:
Enabled: true
# Keeps track of empty lines around class bodies.
Layout/EmptyLinesAroundClassBody:
Enabled: true
# Keeps track of empty lines around exception handling keywords.
Layout/EmptyLinesAroundExceptionHandlingKeywords:
Enabled: false
# Keeps track of empty lines around method bodies.
Layout/EmptyLinesAroundMethodBody:
Enabled: true
# Keeps track of empty lines around module bodies.
Layout/EmptyLinesAroundModuleBody:
Enabled: true
# Use Unix-style line endings.
Layout/EndOfLine:
Enabled: true
# Checks for a line break before the first parameter in a multi-line method
# parameter definition.
Layout/FirstMethodParameterLineBreak:
Enabled: true
# Keep indentation straight.
Layout/IndentationConsistency:
Enabled: true
# Use 2 spaces for indentation.
Layout/IndentationWidth:
Enabled: true
# Checks the indentation of the first line of the right-hand-side of a
# multi-line assignment.
Layout/IndentAssignment:
Enabled: true
# This cops checks the indentation of the here document bodies.
Layout/IndentHeredoc:
Enabled: false
# Comments should start with a space.
Layout/LeadingCommentSpace:
Enabled: true
# Checks that the closing brace in an array literal is either on the same line
# as the last array element, or a new line.
Layout/MultilineArrayBraceLayout:
Enabled: true
EnforcedStyle: symmetrical
# Ensures newlines after multiline block do statements.
Layout/MultilineBlockLayout:
Enabled: true
# Checks that the closing brace in a hash literal is either on the same line as
# the last hash element, or a new line.
Layout/MultilineHashBraceLayout:
Enabled: true
EnforcedStyle: symmetrical
# Checks that the closing brace in a method call is either on the same line as
# the last method argument, or a new line.
Layout/MultilineMethodCallBraceLayout:
Enabled: false
EnforcedStyle: symmetrical
# Checks indentation of method calls with the dot operator that span more than
# one line.
Layout/MultilineMethodCallIndentation:
Enabled: false
# Checks that the closing brace in a method definition is symmetrical with
# respect to the opening brace and the method parameters.
Layout/MultilineMethodDefinitionBraceLayout:
Enabled: false
# Checks indentation of binary operations that span more than one line.
Layout/MultilineOperationIndentation:
Enabled: true
EnforcedStyle: indented
# Use spaces after colons.
Layout/SpaceAfterColon:
Enabled: true
# Use spaces after commas.
Layout/SpaceAfterComma:
Enabled: true
# Do not put a space between a method name and the opening parenthesis in a
# method definition.
Layout/SpaceAfterMethodName:
Enabled: true
# Tracks redundant space after the ! operator.
Layout/SpaceAfterNot:
Enabled: true
# Use spaces after semicolons.
Layout/SpaceAfterSemicolon:
Enabled: true
# Use space around equals in parameter default
Layout/SpaceAroundEqualsInParameterDefault:
Enabled: true
# Use a space around keywords if appropriate.
Layout/SpaceAroundKeyword:
Enabled: true
# Use a single space around operators.
Layout/SpaceAroundOperators:
Enabled: true
# No spaces before commas.
Layout/SpaceBeforeComma:
Enabled: true
# Checks for missing space between code and a comment on the same line.
Layout/SpaceBeforeComment:
Enabled: true
# No spaces before semicolons.
Layout/SpaceBeforeSemicolon:
Enabled: true
# Checks for spaces inside square brackets.
Layout/SpaceInsideBrackets:
Enabled: true
# Use spaces inside hash literal braces - or don't.
Layout/SpaceInsideHashLiteralBraces:
Enabled: true
# No spaces inside range literals.
Layout/SpaceInsideRangeLiteral:
Enabled: true
# Checks for padding/surrounding spaces inside string interpolation.
Layout/SpaceInsideStringInterpolation:
EnforcedStyle: no_space
Enabled: true
# No hard tabs.
Layout/Tab:
Enabled: true
# Checks trailing blank lines and final newline.
Layout/TrailingBlankLines:
Enabled: true
# Style #######################################################################
# Check the naming of accessor methods for get_/set_.
Style/AccessorMethodName:
Enabled: false
@ -44,19 +254,6 @@ Style/Alias:
EnforcedStyle: prefer_alias_method
Enabled: true
# Align the elements of an array literal if they span more than one line.
Style/AlignArray:
Enabled: true
# Align the elements of a hash literal if they span more than one line.
Style/AlignHash:
Enabled: true
# Here we check if the parameters on a multi-line method call or
# definition are aligned.
Style/AlignParameters:
Enabled: false
# Whether `and` and `or` are banned only in conditionals (conditionals)
# or completely (always).
Style/AndOr:
@ -91,10 +288,6 @@ Style/BlockComments:
Style/BlockDelimiters:
Enabled: true
# Put end statement of multiline block on its own line.
Style/BlockEndNewline:
Enabled: true
# This cop checks for braces around the last parameter in a method call
# if the last parameter is a hash.
Style/BracesAroundHashParameters:
@ -104,10 +297,6 @@ Style/BracesAroundHashParameters:
Style/CaseEquality:
Enabled: false
# Indentation of when in a case/when/[else/]end.
Style/CaseIndentation:
Enabled: true
# Checks for uses of character literals.
Style/CharacterLiteral:
Enabled: true
@ -142,10 +331,6 @@ Style/ColonMethodCall:
Style/CommentAnnotation:
Enabled: false
# Indentation of comments.
Style/CommentIndentation:
Enabled: true
# Check for `if` and `case` statements where each branch is used for
# assignment to the same variable when using the return of the
# condition can be used instead.
@ -164,57 +349,16 @@ Style/DefWithParentheses:
Style/Documentation:
Enabled: false
# Multi-line method chaining should be done with leading dots.
Style/DotPosition:
Enabled: true
EnforcedStyle: leading
# This cop checks for uses of double negation (!!) to convert something
# to a boolean value. As this is both cryptic and usually redundant, it
# should be avoided.
Style/DoubleNegation:
Enabled: false
# Align elses and elsifs correctly.
Style/ElseAlignment:
Enabled: true
# Use empty lines between defs.
Style/EmptyLineBetweenDefs:
Enabled: true
# Don't use several empty lines in a row.
Style/EmptyLines:
Enabled: true
# Keep blank lines around access modifiers.
Style/EmptyLinesAroundAccessModifier:
Enabled: true
# Keeps track of empty lines around block bodies.
Style/EmptyLinesAroundBlockBody:
Enabled: true
# Keeps track of empty lines around class bodies.
Style/EmptyLinesAroundClassBody:
Enabled: true
# Keeps track of empty lines around method bodies.
Style/EmptyLinesAroundMethodBody:
Enabled: true
# Keeps track of empty lines around module bodies.
Style/EmptyLinesAroundModuleBody:
Enabled: true
# Avoid the use of END blocks.
Style/EndBlock:
Enabled: true
# Use Unix-style line endings.
Style/EndOfLine:
Enabled: true
# Favor the use of Fixnum#even? && Fixnum#odd?
Style/EvenOdd:
Enabled: true
@ -223,11 +367,6 @@ Style/EvenOdd:
Style/FileName:
Enabled: true
# Checks for a line break before the first parameter in a multi-line method
# parameter definition.
Style/FirstMethodParameterLineBreak:
Enabled: true
# Checks for flip flops.
Style/FlipFlop:
Enabled: true
@ -236,6 +375,10 @@ Style/FlipFlop:
Style/For:
Enabled: true
# Use a consistent style for format string tokens.
Style/FormatStringToken:
Enabled: false
# Checks if there is a magic comment to enforce string literals
Style/FrozenStringLiteralComment:
Enabled: false
@ -261,31 +404,19 @@ Style/IdenticalConditionalBranches:
Style/IfWithSemicolon:
Enabled: true
# Checks the indentation of the first line of the right-hand-side of a
# multi-line assignment.
Style/IndentAssignment:
Enabled: true
# Keep indentation straight.
Style/IndentationConsistency:
Enabled: true
# Use 2 spaces for indentation.
Style/IndentationWidth:
Enabled: true
# Use Kernel#loop for infinite loops.
Style/InfiniteLoop:
Enabled: true
# Use the inverse method instead of `!.method`
# if an inverse method is defined.
Style/InverseMethods:
Enabled: false
# Use lambda.call(...) instead of lambda.(...).
Style/LambdaCall:
Enabled: true
# Comments should start with a space.
Style/LeadingCommentSpace:
Enabled: true
# Checks if the method definitions have or don't have parentheses.
Style/MethodDefParentheses:
Enabled: true
@ -298,55 +429,23 @@ Style/MethodName:
Style/ModuleFunction:
Enabled: false
# Checks that the closing brace in an array literal is either on the same line
# as the last array element, or a new line.
Style/MultilineArrayBraceLayout:
Enabled: true
EnforcedStyle: symmetrical
# Avoid multi-line chains of blocks.
Style/MultilineBlockChain:
Enabled: true
# Ensures newlines after multiline block do statements.
Style/MultilineBlockLayout:
Enabled: true
# Checks that the closing brace in a hash literal is either on the same line as
# the last hash element, or a new line.
Style/MultilineHashBraceLayout:
Enabled: true
EnforcedStyle: symmetrical
# Do not use then for multi-line if/unless.
Style/MultilineIfThen:
Enabled: true
# Checks that the closing brace in a method call is either on the same line as
# the last method argument, or a new line.
Style/MultilineMethodCallBraceLayout:
Enabled: false
EnforcedStyle: symmetrical
# Checks indentation of method calls with the dot operator that span more than
# one line.
Style/MultilineMethodCallIndentation:
Enabled: false
# Checks that the closing brace in a method definition is symmetrical with
# respect to the opening brace and the method parameters.
Style/MultilineMethodDefinitionBraceLayout:
Enabled: false
# Checks indentation of binary operations that span more than one line.
Style/MultilineOperationIndentation:
Enabled: true
EnforcedStyle: indented
# Avoid multi-line `? :` (the ternary operator), use if/unless instead.
Style/MultilineTernaryOperator:
Enabled: true
# Avoid comparing a variable with multiple items in a conditional,
# use Array#include? instead.
Style/MultipleComparison:
Enabled: false
# This cop checks whether some constant value isn't a
# mutable literal (e.g. array or hash).
Style/MutableConstant:
@ -421,68 +520,6 @@ Style/SignalException:
EnforcedStyle: only_raise
Enabled: true
# Use spaces after colons.
Style/SpaceAfterColon:
Enabled: true
# Use spaces after commas.
Style/SpaceAfterComma:
Enabled: true
# Do not put a space between a method name and the opening parenthesis in a
# method definition.
Style/SpaceAfterMethodName:
Enabled: true
# Tracks redundant space after the ! operator.
Style/SpaceAfterNot:
Enabled: true
# Use spaces after semicolons.
Style/SpaceAfterSemicolon:
Enabled: true
# Use space around equals in parameter default
Style/SpaceAroundEqualsInParameterDefault:
Enabled: true
# Use a space around keywords if appropriate.
Style/SpaceAroundKeyword:
Enabled: true
# Use a single space around operators.
Style/SpaceAroundOperators:
Enabled: true
# No spaces before commas.
Style/SpaceBeforeComma:
Enabled: true
# Checks for missing space between code and a comment on the same line.
Style/SpaceBeforeComment:
Enabled: true
# No spaces before semicolons.
Style/SpaceBeforeSemicolon:
Enabled: true
# Checks for spaces inside square brackets.
Style/SpaceInsideBrackets:
Enabled: true
# Use spaces inside hash literal braces - or don't.
Style/SpaceInsideHashLiteralBraces:
Enabled: true
# No spaces inside range literals.
Style/SpaceInsideRangeLiteral:
Enabled: true
# Checks for padding/surrounding spaces inside string interpolation.
Style/SpaceInsideStringInterpolation:
EnforcedStyle: no_space
Enabled: true
# Check for the usage of parentheses around stabby lambda arguments.
Style/StabbyLambdaParentheses:
EnforcedStyle: require_parentheses
@ -498,13 +535,9 @@ Style/StringMethods:
intern: to_sym
Enabled: true
# No hard tabs.
Style/Tab:
Enabled: true
# Checks trailing blank lines and final newline.
Style/TrailingBlankLines:
Enabled: true
# Use %i or %I for arrays of symbols.
Style/SymbolArray:
Enabled: false
# This cop checks for trailing comma in array and hash literals.
Style/TrailingCommaInLiteral:
@ -553,6 +586,10 @@ Style/WhileUntilModifier:
Style/WordArray:
Enabled: true
# Do not use literals as the first operand of a comparison.
Style/YodaCondition:
Enabled: false
# Use `proc` instead of `Proc.new`.
Style/Proc:
Enabled: true
@ -608,6 +645,11 @@ Metrics/PerceivedComplexity:
# Lint ########################################################################
# Checks for ambiguous block association with method when param passed without
# parentheses.
Lint/AmbiguousBlockAssociation:
Enabled: false
# Checks for ambiguous operators in the first argument of a method invocation
# without parentheses.
Lint/AmbiguousOperator:
@ -809,6 +851,10 @@ Lint/Void:
# Performance #################################################################
# Use `caller(n..n)` instead of `caller`.
Performance/Caller:
Enabled: false
# Use `casecmp` rather than `downcase ==`.
Performance/Casecmp:
Enabled: true
@ -883,6 +929,14 @@ Rails/ActionFilter:
Enabled: true
EnforcedStyle: action
# Check that models subclass ApplicationRecord.
Rails/ApplicationRecord:
Enabled: false
# Enforce using `blank?` and `present?`.
Rails/Blank:
Enabled: false
# Checks the correct usage of date aware methods, such as `Date.today`,
# `Date.current`, etc.
Rails/Date:
@ -939,10 +993,18 @@ Rails/OutputSafety:
Rails/PluralizationGrammar:
Enabled: true
# Enforce using `blank?` and `present?`.
Rails/Present:
Enabled: false
# Checks for `read_attribute(:attr)` and `write_attribute(:attr, val)`.
Rails/ReadWriteAttribute:
Enabled: false
# Do not assign relative date to constants.
Rails/RelativeDateConstant:
Enabled: false
# Checks the arguments of ActiveRecord scopes.
Rails/ScopeArgs:
Enabled: true

View File

@ -1,26 +1,89 @@
# This configuration was generated by
# `rubocop --auto-gen-config --exclude-limit 0`
# on 2017-04-07 20:17:35 -0400 using RuboCop version 0.47.1.
# on 2017-07-10 01:48:30 +0900 using RuboCop version 0.49.1.
# 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: 233
# Offense count: 181
# Cop supports --auto-correct.
# Configuration parameters: AllowForAlignment, ForceEqualSignAlignment.
Layout/ExtraSpacing:
Enabled: false
# Offense count: 119
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle, SupportedStyles, IndentationWidth.
# SupportedStyles: special_inside_parentheses, consistent, align_brackets
Layout/IndentArray:
Enabled: false
# Offense count: 208
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle, SupportedStyles, IndentationWidth.
# SupportedStyles: special_inside_parentheses, consistent, align_braces
Layout/IndentHash:
Enabled: false
# Offense count: 174
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle, SupportedStyles.
# SupportedStyles: space, no_space
Layout/SpaceBeforeBlockBraces:
Enabled: false
# Offense count: 8
# Cop supports --auto-correct.
# Configuration parameters: AllowForAlignment.
Layout/SpaceBeforeFirstArg:
Enabled: false
# Offense count: 64
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle, SupportedStyles.
# SupportedStyles: require_no_space, require_space
Layout/SpaceInLambdaLiteral:
Enabled: false
# Offense count: 256
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle, SupportedStyles, EnforcedStyleForEmptyBraces, SupportedStylesForEmptyBraces, SpaceBeforeBlockParameters.
# SupportedStyles: space, no_space
# SupportedStylesForEmptyBraces: space, no_space
Layout/SpaceInsideBlockBraces:
Enabled: false
# Offense count: 135
# Cop supports --auto-correct.
Layout/SpaceInsideParens:
Enabled: false
# Offense count: 14
# Cop supports --auto-correct.
Layout/SpaceInsidePercentLiteralDelimiters:
Enabled: false
# Offense count: 89
# Cop supports --auto-correct.
Layout/TrailingWhitespace:
Enabled: false
# Offense count: 272
RSpec/EmptyLineAfterFinalLet:
Enabled: false
# Offense count: 167
# Offense count: 181
RSpec/EmptyLineAfterSubject:
Enabled: false
# Offense count: 72
# Offense count: 78
# Configuration parameters: EnforcedStyle, SupportedStyles.
# SupportedStyles: implicit, each, example
RSpec/HookArgument:
Enabled: false
# Offense count: 11
# Offense count: 9
# Configuration parameters: EnforcedStyle, SupportedStyles.
# SupportedStyles: it_behaves_like, it_should_behave_like
RSpec/ItBehavesLike:
@ -30,19 +93,19 @@ RSpec/ItBehavesLike:
RSpec/IteratedExpectation:
Enabled: false
# Offense count: 3
# Offense count: 2
RSpec/OverwritingSetup:
Enabled: false
# Offense count: 34
# Offense count: 36
RSpec/RepeatedExample:
Enabled: false
# Offense count: 43
# Offense count: 86
RSpec/ScatteredLet:
Enabled: false
# Offense count: 32
# Offense count: 20
RSpec/ScatteredSetup:
Enabled: false
@ -50,7 +113,7 @@ RSpec/ScatteredSetup:
RSpec/SharedContext:
Enabled: false
# Offense count: 150
# Offense count: 115
Rails/FilePath:
Enabled: false
@ -60,90 +123,71 @@ Rails/FilePath:
Rails/ReversibleMigration:
Enabled: false
# Offense count: 302
# Offense count: 336
# Configuration parameters: Blacklist.
# Blacklist: decrement!, decrement_counter, increment!, increment_counter, toggle!, touch, update_all, update_attribute, update_column, update_columns, update_counters
Rails/SkipsModelValidations:
Enabled: false
# Offense count: 7
# Offense count: 11
# Cop supports --auto-correct.
Security/YAMLLoad:
Enabled: false
# Offense count: 59
# Offense count: 58
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle, SupportedStyles.
# SupportedStyles: percent_q, bare_percent
Style/BarePercentLiterals:
Enabled: false
# Offense count: 5
# Offense count: 6
# Cop supports --auto-correct.
Style/EachWithObject:
Enabled: false
# Offense count: 28
# Offense count: 31
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle, SupportedStyles.
# SupportedStyles: empty, nil, both
Style/EmptyElse:
Enabled: false
# Offense count: 4
# Offense count: 9
# Cop supports --auto-correct.
Style/EmptyLiteral:
Enabled: false
# Offense count: 59
# Offense count: 78
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle, SupportedStyles.
# SupportedStyles: compact, expanded
Style/EmptyMethod:
Enabled: false
# Offense count: 214
# Offense count: 23
# Cop supports --auto-correct.
# Configuration parameters: AllowForAlignment, ForceEqualSignAlignment.
Style/ExtraSpacing:
Enabled: false
# Offense count: 9
# Configuration parameters: EnforcedStyle, SupportedStyles.
# SupportedStyles: format, sprintf, percent
Style/FormatString:
Enabled: false
# Offense count: 285
# Offense count: 301
# Configuration parameters: MinBodyLength.
Style/GuardClause:
Enabled: false
# Offense count: 16
# Offense count: 18
Style/IfInsideElse:
Enabled: false
# Offense count: 186
# Offense count: 182
# Cop supports --auto-correct.
# Configuration parameters: MaxLineLength.
Style/IfUnlessModifier:
Enabled: false
# Offense count: 99
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle, SupportedStyles, IndentationWidth.
# SupportedStyles: special_inside_parentheses, consistent, align_brackets
Style/IndentArray:
Enabled: false
# Offense count: 160
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle, SupportedStyles, IndentationWidth.
# SupportedStyles: special_inside_parentheses, consistent, align_braces
Style/IndentHash:
Enabled: false
# Offense count: 50
# Offense count: 52
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle, SupportedStyles.
# SupportedStyles: line_count_dependent, lambda, literal
@ -155,63 +199,63 @@ Style/Lambda:
Style/LineEndConcatenation:
Enabled: false
# Offense count: 34
# Offense count: 40
# Cop supports --auto-correct.
Style/MethodCallWithoutArgsParentheses:
Enabled: false
# Offense count: 10
# Offense count: 13
Style/MethodMissing:
Enabled: false
# Offense count: 3
# Offense count: 6
# Cop supports --auto-correct.
Style/MultilineIfModifier:
Enabled: false
# Offense count: 24
# Offense count: 26
# Cop supports --auto-correct.
Style/NestedParenthesizedCalls:
Enabled: false
# Offense count: 18
# Offense count: 20
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle, MinBodyLength, SupportedStyles.
# SupportedStyles: skip_modifier_ifs, always
Style/Next:
Enabled: false
# Offense count: 37
# Offense count: 45
# Cop supports --auto-correct.
# Configuration parameters: EnforcedOctalStyle, SupportedOctalStyles.
# SupportedOctalStyles: zero_with_o, zero_only
Style/NumericLiteralPrefix:
Enabled: false
# Offense count: 88
# Offense count: 98
# Cop supports --auto-correct.
# Configuration parameters: AutoCorrect, EnforcedStyle, SupportedStyles.
# SupportedStyles: predicate, comparison
Style/NumericPredicate:
Enabled: false
# Offense count: 36
# Offense count: 42
# Cop supports --auto-correct.
Style/ParallelAssignment:
Enabled: false
# Offense count: 570
# Offense count: 800
# Cop supports --auto-correct.
# Configuration parameters: PreferredDelimiters.
Style/PercentLiteralDelimiters:
Enabled: false
# Offense count: 14
# Offense count: 15
# Cop supports --auto-correct.
Style/PerlBackrefs:
Enabled: false
# Offense count: 83
# Offense count: 105
# Configuration parameters: NamePrefix, NamePrefixBlacklist, NameWhitelist.
# NamePrefix: is_, has_, have_
# NamePrefixBlacklist: is_, has_, have_
@ -219,47 +263,47 @@ Style/PerlBackrefs:
Style/PredicateName:
Enabled: false
# Offense count: 65
# Offense count: 58
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle, SupportedStyles.
# SupportedStyles: compact, exploded
Style/RaiseArgs:
Enabled: false
# Offense count: 5
# Offense count: 6
# Cop supports --auto-correct.
Style/RedundantBegin:
Enabled: false
# Offense count: 32
# Offense count: 37
# Cop supports --auto-correct.
Style/RedundantFreeze:
Enabled: false
# Offense count: 15
# Offense count: 14
# Cop supports --auto-correct.
# Configuration parameters: AllowMultipleReturnValues.
Style/RedundantReturn:
Enabled: false
# Offense count: 382
# Offense count: 406
# Cop supports --auto-correct.
Style/RedundantSelf:
Enabled: false
# Offense count: 111
# Offense count: 115
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle, SupportedStyles, AllowInnerSlashes.
# SupportedStyles: slashes, percent_r, mixed
Style/RegexpLiteral:
Enabled: false
# Offense count: 24
# Offense count: 29
# Cop supports --auto-correct.
Style/RescueModifier:
Enabled: false
# Offense count: 7
# Offense count: 8
# Cop supports --auto-correct.
Style/SelfAssignment:
Enabled: false
@ -270,101 +314,58 @@ Style/SelfAssignment:
Style/SingleLineMethods:
Enabled: false
# Offense count: 168
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle, SupportedStyles.
# SupportedStyles: space, no_space
Style/SpaceBeforeBlockBraces:
Enabled: false
# Offense count: 8
# Cop supports --auto-correct.
# Configuration parameters: AllowForAlignment.
Style/SpaceBeforeFirstArg:
Enabled: false
# Offense count: 46
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle, SupportedStyles.
# SupportedStyles: require_no_space, require_space
Style/SpaceInLambdaLiteral:
Enabled: false
# Offense count: 229
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle, SupportedStyles, EnforcedStyleForEmptyBraces, SupportedStylesForEmptyBraces, SpaceBeforeBlockParameters.
# SupportedStyles: space, no_space
# SupportedStylesForEmptyBraces: space, no_space
Style/SpaceInsideBlockBraces:
Enabled: false
# Offense count: 116
# Cop supports --auto-correct.
Style/SpaceInsideParens:
Enabled: false
# Offense count: 12
# Cop supports --auto-correct.
Style/SpaceInsidePercentLiteralDelimiters:
Enabled: false
# Offense count: 57
# Offense count: 64
# Cop supports --auto-correct.
# Configuration parameters: SupportedStyles.
# SupportedStyles: use_perl_names, use_english_names
Style/SpecialGlobalVars:
EnforcedStyle: use_perl_names
# Offense count: 42
# Offense count: 44
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle, SupportedStyles.
# SupportedStyles: single_quotes, double_quotes
Style/StringLiteralsInInterpolation:
Enabled: false
# Offense count: 64
# Offense count: 84
# Cop supports --auto-correct.
# Configuration parameters: IgnoredMethods.
# IgnoredMethods: respond_to, define_method
Style/SymbolProc:
Enabled: false
# Offense count: 6
# Offense count: 8
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle, SupportedStyles, AllowSafeAssignment.
# SupportedStyles: require_parentheses, require_no_parentheses, require_parentheses_when_complex
Style/TernaryParentheses:
Enabled: false
# Offense count: 18
# Offense count: 17
# Cop supports --auto-correct.
# Configuration parameters: AllowNamedUnderscoreVariables.
Style/TrailingUnderscoreVariable:
Enabled: false
# Offense count: 78
# Cop supports --auto-correct.
Style/TrailingWhitespace:
Enabled: false
# Offense count: 3
# Offense count: 4
# 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: 6
# Offense count: 5
# Cop supports --auto-correct.
Style/UnlessElse:
Enabled: false
# Offense count: 24
# Offense count: 28
# Cop supports --auto-correct.
Style/UnneededInterpolation:
Enabled: false
# Offense count: 8
# Offense count: 11
# Cop supports --auto-correct.
Style/ZeroLengthPredicate:
Enabled: false

View File

@ -2,6 +2,16 @@
documentation](doc/development/changelog.md) for instructions on adding your own
entry.
## 9.4.3 (2017-07-31)
- Fix Prometheus client PID reuse bug. !13130
- Improve deploy environment chatops slash command. !13150
- Fix asynchronous javascript paths when GitLab is installed under a relative URL. !13165
- Fix LDAP authentication to Git repository or container registry.
- Fixed new navigation breadcrumb title on help pages.
- Ensure filesystem metrics test files are deleted.
- Properly affixes nav bar in job view in microsoft edge.
## 9.4.2 (2017-07-28)
- Fix job merge request link to a forked source project. !12965

View File

@ -1 +1 @@
0.25.0
0.26.0

View File

@ -339,8 +339,8 @@ group :development, :test do
gem 'spring-commands-rspec', '~> 1.0.4'
gem 'spring-commands-spinach', '~> 1.1.0'
gem 'rubocop', '~> 0.47.1', require: false
gem 'rubocop-rspec', '~> 1.15.0', require: false
gem 'rubocop', '~> 0.49.1', require: false
gem 'rubocop-rspec', '~> 1.15.1', require: false
gem 'scss_lint', '~> 0.54.0', require: false
gem 'haml_lint', '~> 0.21.0', require: false
gem 'simplecov', '~> 0.14.0', require: false

View File

@ -323,7 +323,7 @@ GEM
multi_json (~> 1.10)
retriable (~> 1.4)
signet (~> 0.6)
google-protobuf (3.2.0.2)
google-protobuf (3.3.0)
googleauth (0.5.1)
faraday (~> 0.9)
jwt (~> 1.4)
@ -545,6 +545,7 @@ GEM
rubypants (~> 0.2)
orm_adapter (0.5.0)
os (0.9.6)
parallel (1.11.2)
paranoia (2.3.1)
activerecord (>= 4.0, < 5.2)
parser (2.4.0.0)
@ -730,13 +731,14 @@ GEM
pg
rails
sqlite3
rubocop (0.47.1)
rubocop (0.49.1)
parallel (~> 1.10)
parser (>= 2.3.3.1, < 3.0)
powerpack (~> 0.1)
rainbow (>= 1.99.1, < 3.0)
ruby-progressbar (~> 1.7)
unicode-display_width (~> 1.0, >= 1.0.1)
rubocop-rspec (1.15.0)
rubocop-rspec (1.15.1)
rubocop (>= 0.42.0)
ruby-fogbugz (0.2.1)
crack (~> 0.4)
@ -868,7 +870,7 @@ GEM
unf (0.1.4)
unf_ext
unf_ext (0.0.7.2)
unicode-display_width (1.1.3)
unicode-display_width (1.3.0)
unicorn (5.1.0)
kgio (~> 2.6)
raindrops (~> 0.7)
@ -1078,8 +1080,8 @@ DEPENDENCIES
rspec-retry (~> 0.4.5)
rspec-set (~> 0.1.3)
rspec_profiling (~> 0.0.5)
rubocop (~> 0.47.1)
rubocop-rspec (~> 1.15.0)
rubocop (~> 0.49.1)
rubocop-rspec (~> 1.15.1)
ruby-fogbugz (~> 0.2.1)
ruby-prof (~> 0.16.2)
ruby_parser (~> 3.8)

View File

@ -128,7 +128,7 @@ information, see
### After the 7th
Once the stable branch is frozen, only fixes for regressions (bugs introduced in that same release)
Once the stable branch is frozen, only fixes for [regressions](#regressions)
and security issues will be cherry-picked into the stable branch.
Any merge requests cherry-picked into the stable branch for a previous release will also be picked into the latest stable branch.
These fixes will be shipped in the next RC for that release if it is before the 22nd.
@ -158,6 +158,24 @@ release should have the correct milestone assigned _and_ have the label
Merge requests without a milestone and this label will
not be merged into any stable branches.
### Regressions
A regression for a particular monthly release is a bug that exists in that
release, but wasn't present in the release before. This includes bugs in
features that were only added in that monthly release. Every regression **must**
have the milestone of the release it was introduced in - if a regression doesn't
have a milestone, it might be 'just' a bug!
For instance, if 10.5.0 adds a feature, and that feature doesn't work correctly,
then this is a regression in 10.5. If 10.5.1 then fixes that, but 10.5.3 somehow
reintroduces the bug, then this bug is still a regression in 10.5.
Because GitLab.com runs release candidates of new releases, a regression can be
reported in a release before its 'official' release date on the 22nd of the
month. When we say 'the most recent monthly release', this can refer to either
the version currently running on GitLab.com, or the most recent version
available in the package repositories.
## Release retrospective and kickoff
### Retrospective

View File

@ -8,6 +8,7 @@ import BlobFileDropzone from '../blob/blob_file_dropzone';
$(() => {
const editBlobForm = $('.js-edit-blob-form');
const uploadBlobForm = $('.js-upload-blob-form');
const deleteBlobForm = $('.js-delete-blob-form');
if (editBlobForm.length) {
const urlRoot = editBlobForm.data('relative-url-root');
@ -30,4 +31,8 @@ $(() => {
'.btn-upload-file',
);
}
if (deleteBlobForm.length) {
new NewCommitForm(deleteBlobForm);
}
});

View File

@ -64,7 +64,7 @@ window.Build = (function () {
$(window)
.off('scroll')
.on('scroll', () => {
const contentHeight = this.$buildTraceOutput.prop('scrollHeight');
const contentHeight = this.$buildTraceOutput.height();
if (contentHeight > this.windowSize) {
// means the user did not scroll, the content was updated.
this.windowSize = contentHeight;
@ -105,16 +105,17 @@ window.Build = (function () {
};
Build.prototype.canScroll = function () {
return document.body.scrollHeight > window.innerHeight;
return $(document).height() > $(window).height();
};
Build.prototype.toggleScroll = function () {
const currentPosition = document.body.scrollTop;
const windowHeight = window.innerHeight;
const currentPosition = $(document).scrollTop();
const scrollHeight = $(document).height();
const windowHeight = $(window).height();
if (this.canScroll()) {
if (currentPosition > 0 &&
(document.body.scrollHeight - currentPosition !== windowHeight)) {
(scrollHeight - currentPosition !== windowHeight)) {
// User is in the middle of the log
this.toggleDisableButton(this.$scrollTopBtn, false);
@ -124,7 +125,7 @@ window.Build = (function () {
this.toggleDisableButton(this.$scrollTopBtn, true);
this.toggleDisableButton(this.$scrollBottomBtn, false);
} else if (document.body.scrollHeight - currentPosition === windowHeight) {
} else if (scrollHeight - currentPosition === windowHeight) {
// User is at the bottom of the build log.
this.toggleDisableButton(this.$scrollTopBtn, false);
@ -137,7 +138,7 @@ window.Build = (function () {
};
Build.prototype.scrollDown = function () {
document.body.scrollTop = document.body.scrollHeight;
$(document).scrollTop($(document).height());
};
Build.prototype.scrollToBottom = function () {
@ -147,7 +148,7 @@ window.Build = (function () {
};
Build.prototype.scrollToTop = function () {
document.body.scrollTop = 0;
$(document).scrollTop(0);
this.hasBeenScrolled = true;
this.toggleScroll();
};
@ -178,7 +179,7 @@ window.Build = (function () {
this.state = log.state;
}
this.windowSize = this.$buildTraceOutput.prop('scrollHeight');
this.windowSize = this.$buildTraceOutput.height();
if (log.append) {
this.$buildTraceOutput.append(log.html);

View File

@ -8,6 +8,8 @@
/* global LabelsSelect */
/* global MilestoneSelect */
/* global Commit */
/* global CommitsList */
/* global NewBranchForm */
/* global NotificationsForm */
/* global NotificationsDropdown */
/* global GroupAvatar */
@ -18,15 +20,20 @@
/* global Search */
/* global Admin */
/* global NamespaceSelects */
/* global NewCommitForm */
/* global NewBranchForm */
/* global Project */
/* global ProjectAvatar */
/* global MergeRequest */
/* global Compare */
/* global CompareAutocomplete */
/* global ProjectFindFile */
/* global ProjectNew */
/* global ProjectShow */
/* global ProjectImport */
/* global Labels */
/* global Shortcuts */
/* global ShortcutsFindFile */
/* global Sidebar */
/* global ShortcutsWiki */
@ -194,7 +201,6 @@ import GpgBadges from './gpg_badges';
break;
case 'explore:groups:index':
new GroupsList();
const landingElement = document.querySelector('.js-explore-groups-landing');
if (!landingElement) break;
const exploreGroupsLanding = new Landing(
@ -217,6 +223,10 @@ import GpgBadges from './gpg_badges';
case 'projects:compare:show':
new gl.Diff();
break;
case 'projects:branches:new':
case 'projects:branches:create':
new NewBranchForm($('.js-create-branch-form'), JSON.parse(document.getElementById('availableRefs').innerHTML));
break;
case 'projects:branches:index':
gl.AjaxLoadingSpinner.init();
new DeleteModal();
@ -258,7 +268,7 @@ import GpgBadges from './gpg_badges';
case 'projects:tags:new':
new ZenMode();
new gl.GLForm($('.tag-form'), true);
new RefSelectDropdown($('.js-branch-select'), window.gl.availableRefs);
new RefSelectDropdown($('.js-branch-select'));
break;
case 'projects:snippets:show':
initNotes();
@ -304,19 +314,24 @@ import GpgBadges from './gpg_badges';
container: '.js-commit-pipeline-graph',
}).bindEvents();
initNotes();
$('.commit-info.branches').load(document.querySelector('.js-commit-box').dataset.commitPath);
break;
case 'projects:commit:pipelines':
new MiniPipelineGraph({
container: '.js-commit-pipeline-graph',
}).bindEvents();
break;
case 'projects:commits:show':
shortcut_handler = new ShortcutsNavigation();
GpgBadges.fetch();
$('.commit-info.branches').load(document.querySelector('.js-commit-box').dataset.commitPath);
break;
case 'projects:activity':
new gl.Activities();
shortcut_handler = new ShortcutsNavigation();
break;
case 'projects:commits:show':
CommitsList.init(document.querySelector('.js-project-commits-show').dataset.commitsLimit);
new gl.Activities();
shortcut_handler = new ShortcutsNavigation();
GpgBadges.fetch();
break;
case 'projects:show':
shortcut_handler = new ShortcutsNavigation();
new NotificationsForm();
@ -330,6 +345,12 @@ import GpgBadges from './gpg_badges';
case 'projects:edit':
setupProjectEdit();
break;
case 'projects:imports:show':
new ProjectImport();
break;
case 'projects:pipelines:new':
new NewBranchForm($('.js-new-pipeline-form'));
break;
case 'projects:pipelines:builds':
case 'projects:pipelines:failures':
case 'projects:pipelines:show':
@ -383,8 +404,19 @@ import GpgBadges from './gpg_badges';
shortcut_handler = new ShortcutsNavigation();
new TreeView();
new BlobViewer();
new NewCommitForm($('.js-create-dir-form'));
$('#tree-slider').waitForImages(function() {
gl.utils.ajaxGet(document.querySelector('.js-tree-content').dataset.logsPath);
});
break;
case 'projects:find_file:show':
const findElement = document.querySelector('.js-file-finder');
const projectFindFile = new ProjectFindFile($(".file-finder-holder"), {
url: findElement.dataset.fileFindUrl,
treeUrl: findElement.dataset.findTreeUrl,
blobUrlTemplate: findElement.dataset.blobUrlTemplate,
});
new ShortcutsFindFile(projectFindFile);
shortcut_handler = true;
break;
case 'projects:blob:show':
@ -540,6 +572,7 @@ import GpgBadges from './gpg_badges';
shortcut_handler = new ShortcutsWiki();
new ZenMode();
new gl.GLForm($('.wiki-form'), true);
new Sidebar();
break;
case 'snippets':
shortcut_handler = new ShortcutsNavigation();

View File

@ -730,10 +730,10 @@ GitLabDropdown = (function() {
GitLabDropdown.prototype.focusTextInput = function(triggerFocus = false) {
if (this.options.filterable) {
$(':focus').blur();
this.dropdown.one('transitionend', () => {
this.filterInput.focus();
if (this.dropdown.is('.open')) {
this.filterInput.focus();
}
});
if (triggerFocus) {

View File

@ -1,6 +1,4 @@
import Chart from 'vendor/Chart';
import ContributorsStatGraph from './stat_graph_contributors';
// export to global scope
window.Chart = Chart;
window.ContributorsStatGraph = ContributorsStatGraph;

View File

@ -0,0 +1,63 @@
import Chart from 'vendor/Chart';
document.addEventListener('DOMContentLoaded', () => {
const projectChartData = JSON.parse(document.getElementById('projectChartData').innerHTML);
const responsiveChart = (selector, data) => {
const options = {
scaleOverlay: true,
responsive: true,
pointHitDetectionRadius: 2,
maintainAspectRatio: false,
};
// get selector by context
const ctx = selector.get(0).getContext('2d');
// pointing parent container to make chart.js inherit its width
const container = $(selector).parent();
const generateChart = () => {
selector.attr('width', $(container).width());
if (window.innerWidth < 768) {
// Scale fonts if window width lower than 768px (iPad portrait)
options.scaleFontSize = 8;
}
return new Chart(ctx).Bar(data, options);
};
// enabling auto-resizing
$(window).resize(generateChart);
return generateChart();
};
const chartData = (keys, values) => {
const data = {
labels: keys,
datasets: [{
fillColor: 'rgba(220,220,220,0.5)',
strokeColor: 'rgba(220,220,220,1)',
barStrokeWidth: 1,
barValueSpacing: 1,
barDatasetSpacing: 1,
data: values,
}],
};
return data;
};
const hourData = chartData(projectChartData.hour.keys, projectChartData.hour.values);
responsiveChart($('#hour-chart'), hourData);
const dayData = chartData(projectChartData.weekDays.keys, projectChartData.weekDays.values);
responsiveChart($('#weekday-chart'), dayData);
const monthData = chartData(projectChartData.month.keys, projectChartData.month.values);
responsiveChart($('#month-chart'), monthData);
const data = projectChartData.languages;
const ctx = $('#languages-chart').get(0).getContext('2d');
const options = {
scaleOverlay: true,
responsive: true,
maintainAspectRatio: false,
};
new Chart(ctx).Pie(data, options);
});

View File

@ -0,0 +1,21 @@
import ContributorsStatGraph from './stat_graph_contributors';
document.addEventListener('DOMContentLoaded', () => {
$.ajax({
type: 'GET',
url: document.querySelector('.js-graphs-show').dataset.projectGraphPath,
dataType: 'json',
success(data) {
const graph = new ContributorsStatGraph();
graph.init(data);
$('#brush_change').change(() => {
graph.change_date_header();
graph.redraw_authors();
});
$('.stat-graph').fadeIn();
$('.loading-graph').hide();
},
});
});

View File

@ -0,0 +1,38 @@
import Chart from 'vendor/Chart';
document.addEventListener('DOMContentLoaded', () => {
const chartData = JSON.parse(document.getElementById('pipelinesChartsData').innerHTML);
const buildChart = (chartScope) => {
const data = {
labels: chartScope.labels,
datasets: [{
fillColor: '#7f8fa4',
strokeColor: '#7f8fa4',
pointColor: '#7f8fa4',
pointStrokeColor: '#EEE',
data: chartScope.totalValues,
},
{
fillColor: '#44aa22',
strokeColor: '#44aa22',
pointColor: '#44aa22',
pointStrokeColor: '#fff',
data: chartScope.successValues,
},
],
};
const ctx = $(`#${chartScope.scope}Chart`).get(0).getContext('2d');
const options = {
scaleOverlay: true,
responsive: true,
maintainAspectRatio: false,
};
if (window.innerWidth < 768) {
// Scale fonts if window width lower than 768px (iPad portrait)
options.scaleFontSize = 8;
}
new Chart(ctx).Line(data, options);
};
chartData.forEach(scope => buildChart(scope));
});

View File

@ -0,0 +1,27 @@
import Chart from 'vendor/Chart';
document.addEventListener('DOMContentLoaded', () => {
const chartData = JSON.parse(document.getElementById('pipelinesTimesChartsData').innerHTML);
const data = {
labels: chartData.labels,
datasets: [{
fillColor: 'rgba(220,220,220,0.5)',
strokeColor: 'rgba(220,220,220,1)',
barStrokeWidth: 1,
barValueSpacing: 1,
barDatasetSpacing: 1,
data: chartData.values,
}],
};
const ctx = $('#build_timesChart').get(0).getContext('2d');
const options = {
scaleOverlay: true,
responsive: true,
maintainAspectRatio: false,
};
if (window.innerWidth < 768) {
// Scale fonts if window width lower than 768px (iPad portrait)
options.scaleFontSize = 8;
}
new Chart(ctx).Bar(data, options);
});

View File

@ -0,0 +1,85 @@
let hasUserDefinedProjectPath = false;
const deriveProjectPathFromUrl = ($projectImportUrl, $projectPath) => {
if ($projectImportUrl.attr('disabled') || hasUserDefinedProjectPath) {
return;
}
let importUrl = $projectImportUrl.val().trim();
if (importUrl.length === 0) {
return;
}
/*
\/?: remove trailing slash
(\.git\/?)?: remove trailing .git (with optional trailing slash)
(\?.*)?: remove query string
(#.*)?: remove fragment identifier
*/
importUrl = importUrl.replace(/\/?(\.git\/?)?(\?.*)?(#.*)?$/, '');
// extract everything after the last slash
const pathMatch = /\/([^/]+)$/.exec(importUrl);
if (pathMatch) {
$projectPath.val(pathMatch[1]);
}
};
const bindEvents = () => {
const $newProjectForm = $('#new_project');
const importBtnTooltip = 'Please enter a valid project name.';
const $importBtnWrapper = $('.import_gitlab_project');
const $projectImportUrl = $('#project_import_url');
const $projectPath = $('#project_path');
if ($newProjectForm.length !== 1) {
return;
}
$('.how_to_import_link').on('click', (e) => {
e.preventDefault();
$('.how_to_import_link').next('.modal').show();
});
$('.modal-header .close').on('click', () => {
$('.modal').hide();
});
$('.btn_import_gitlab_project').on('click', () => {
const importHref = $('a.btn_import_gitlab_project').attr('href');
$('.btn_import_gitlab_project').attr('href', `${importHref}?namespace_id=${$('#project_namespace_id').val()}&path=${$projectPath.val()}`);
});
$('.btn_import_gitlab_project').attr('disabled', !$projectPath.val().trim().length);
$importBtnWrapper.attr('title', importBtnTooltip);
$newProjectForm.on('submit', () => {
$projectPath.val($projectPath.val().trim());
});
$projectPath.on('keyup', () => {
hasUserDefinedProjectPath = $projectPath.val().trim().length > 0;
if (hasUserDefinedProjectPath) {
$('.btn_import_gitlab_project').attr('disabled', false);
$importBtnWrapper.attr('title', '');
$importBtnWrapper.removeClass('has-tooltip');
} else {
$('.btn_import_gitlab_project').attr('disabled', true);
$importBtnWrapper.addClass('has-tooltip');
}
});
$projectImportUrl.disable();
$projectImportUrl.keyup(() => deriveProjectPathFromUrl($projectImportUrl, $projectPath));
$('.import_git').on('click', () => {
$projectImportUrl.attr('disabled', !$projectImportUrl.attr('disabled'));
});
};
document.addEventListener('DOMContentLoaded', bindEvents);
export default {
bindEvents,
deriveProjectPathFromUrl,
};

View File

@ -1,7 +1,8 @@
class RefSelectDropdown {
constructor($dropdownButton, availableRefs) {
const availableRefsValue = availableRefs || JSON.parse(document.getElementById('availableRefs').innerHTML);
$dropdownButton.glDropdown({
data: availableRefs,
data: availableRefsValue,
filterable: true,
filterByText: true,
remote: false,

View File

@ -0,0 +1,13 @@
/* global U2FRegister */
document.addEventListener('DOMContentLoaded', () => {
const twoFactorNode = document.querySelector('.js-two-factor-auth');
const skippable = twoFactorNode.dataset.twoFactorSkippable === 'true';
if (skippable) {
const button = `<a class="btn btn-xs btn-warning pull-right" data-method="patch" href="${twoFactorNode.dataset.two_factor_skip_url}">Configure it later</a>`;
const flashAlert = document.querySelector('.flash-alert .container-fluid');
if (flashAlert) flashAlert.insertAdjacentHTML('beforeend', button);
}
const u2fRegister = new U2FRegister($('#js-register-u2f'), gon.u2f);
u2fRegister.start();
});

View File

@ -0,0 +1,22 @@
import Api from './api';
document.addEventListener('DOMContentLoaded', () => {
$('#js-project-dropdown').glDropdown({
data: (term, callback) => {
Api.projects(term, {
order_by: 'last_activity_at',
}, (data) => {
callback(data);
});
},
text: project => (project.name_with_namespace || project.name),
selectable: true,
fieldName: 'author_id',
filterable: true,
search: {
fields: ['name_with_namespace'],
},
id: data => data.id,
isSelected: data => (data.id === 2),
});
});

View File

@ -88,6 +88,10 @@
overflow: hidden;
display: flex;
a {
display: flex;
}
.avatar {
border-radius: 0;
border: none;

View File

@ -414,13 +414,16 @@
background-color: $dropdown-hover-color;
color: $white-light;
text-decoration: none;
outline: 0;
.avatar {
border-color: $white-light;
}
}
.filter-dropdown-item {
.droplab-dropdown .dropdown-menu .filter-dropdown-item {
padding: 0;
.btn {
border: none;
width: 100%;
@ -455,14 +458,11 @@
}
.dropdown-user {
display: -webkit-flex;
display: flex;
}
.dropdown-user-details {
display: -webkit-flex;
display: flex;
-webkit-flex-direction: column;
flex-direction: column;
> span {

View File

@ -313,6 +313,29 @@ header {
.impersonation i {
color: $red-500;
}
// TODO: fallback to global style
.dropdown-menu,
.dropdown-menu-nav {
li {
padding: 0 1px;
a {
border-radius: 0;
padding: 8px 16px;
&:hover,
&:active,
&:focus {
background-color: $gray-darker;
}
}
}
}
}
.with-performance-bar header.navbar-gitlab {
top: $performance-bar-height;
}
.navbar-nav {

View File

@ -120,3 +120,7 @@ of the body element here, we negate cascading side effects but allow momentum sc
.page-with-sidebar {
-webkit-overflow-scrolling: auto;
}
.with-performance-bar .page-with-sidebar {
margin-top: $header-height + $performance-bar-height;
}

View File

@ -347,6 +347,10 @@
}
}
.with-performance-bar .layout-nav {
margin-top: $header-height + $performance-bar-height;
}
.scrolling-tabs-container {
position: relative;
@ -441,6 +445,22 @@
}
}
.with-performance-bar .page-with-layout-nav {
.right-sidebar {
top: ($header-height + 1) * 2 + $performance-bar-height;
}
&.page-with-sub-nav {
.right-sidebar {
top: ($header-height + 1) * 3 + $performance-bar-height;
&.affix {
top: $header-height + $performance-bar-height;
}
}
}
}
.nav-block {
&.activities {
border-bottom: 1px solid $border-color;

View File

@ -89,6 +89,10 @@
}
}
.with-performance-bar .right-sidebar.affix {
top: $header-height + $performance-bar-height;
}
@mixin maintain-sidebar-dimensions {
display: block;
width: $gutter-width;

View File

@ -204,6 +204,7 @@ $divergence-graph-separator-bg: #ccc;
$general-hover-transition-duration: 100ms;
$general-hover-transition-curve: linear;
$highlight-changes-color: rgb(235, 255, 232);
$performance-bar-height: 35px;
/*

View File

@ -309,6 +309,25 @@ header.navbar-gitlab-new {
outline: 0;
}
}
// TODO: fallback to global style
.dropdown-menu {
li {
padding: 0 1px;
a {
border-radius: 0;
padding: 8px 16px;
&.is-focused,
&:hover,
&:active,
&:focus {
background-color: $gray-darker;
}
}
}
}
}
.breadcrumbs-container {
@ -325,6 +344,7 @@ header.navbar-gitlab-new {
.breadcrumbs-links {
flex: 1;
min-width: 0;
align-self: center;
color: $gl-text-color-quaternary;
@ -343,7 +363,7 @@ header.navbar-gitlab-new {
}
.title {
white-space: nowrap;
display: inline-block;
> a {
&:last-of-type:not(:first-child) {

View File

@ -118,7 +118,7 @@ $new-sidebar-width: 220px;
z-index: 400;
width: $new-sidebar-width;
transition: left $sidebar-transition-duration;
top: 50px;
top: $header-height;
bottom: 0;
left: 0;
overflow: auto;
@ -163,6 +163,10 @@ $new-sidebar-width: 220px;
}
}
.with-performance-bar .nav-sidebar {
top: $header-height + $performance-bar-height;
}
.sidebar-sub-level-items {
display: none;
padding-bottom: 8px;
@ -260,7 +264,7 @@ $new-sidebar-width: 220px;
// Make issue boards full-height now that sub-nav is gone
.boards-list {
height: calc(100vh - 50px);
height: calc(100vh - #{$header-height});
@media (min-width: $screen-sm-min) {
height: 475px; // Needed for PhantomJS
@ -270,6 +274,10 @@ $new-sidebar-width: 220px;
}
}
.with-performance-bar .boards-list {
height: calc(100vh - #{$header-height} - #{$performance-bar-height});
}
// Change color of all horizontal tabs to match the new indigo color
.nav-links li.active a {

View File

@ -64,10 +64,10 @@
color: $gl-text-color;
position: sticky;
position: -webkit-sticky;
top: 50px;
top: $header-height;
&.affix {
top: 50px;
top: $header-height;
}
// with sidebar
@ -86,6 +86,7 @@
position: absolute;
right: 0;
left: 0;
top: 0;
}
.truncated-info {
@ -171,6 +172,16 @@
}
}
.with-performance-bar .build-page {
.top-bar {
top: $header-height + $performance-bar-height;
&.affix {
top: $header-height + $performance-bar-height;
}
}
}
.build-header {
.ci-header-container,
.header-action-buttons {
@ -300,9 +311,7 @@
}
.dropdown-menu {
right: $gl-padding;
left: $gl-padding;
width: auto;
margin-top: -$gl-padding;
}
svg {

View File

@ -110,6 +110,10 @@
.js-ca-dropdown {
top: $gl-padding-top;
.dropdown-menu-align-right {
margin-top: 2px;
}
}
.content-list {
@ -442,6 +446,24 @@
margin-bottom: 20px;
}
}
// TODO: fallback to global style
.dropdown-menu {
li {
padding: 0 1px;
a {
border-radius: 0;
padding: 8px 16px;
&:hover,
&:active,
&:focus {
background-color: $gray-darker;
}
}
}
}
}
.cycle-analytics-overview {

View File

@ -445,6 +445,14 @@
}
}
.with-performance-bar .right-sidebar {
top: $header-height + $performance-bar-height;
.issuable-sidebar {
height: calc(100% - #{$header-height} - #{$performance-bar-height});
}
}
.detail-page-description {
padding: 16px 0;

View File

@ -759,6 +759,10 @@
}
}
.with-performance-bar .merge-request-tabs-holder {
top: $header-height + $performance-bar-height;
}
.merge-request-tabs {
display: flex;
margin-bottom: 0;

View File

@ -202,6 +202,28 @@
}
}
}
// TODO: fallback to global style
.dropdown-menu:not(.dropdown-menu-selectable) {
li {
padding: 0 1px;
&.dropdown-header {
padding: 8px 16px;
}
a {
border-radius: 0;
padding: 8px 16px;
&:hover,
&:active,
&:focus {
background-color: $gray-darker;
}
}
}
}
}
.blob-commit-info {

View File

@ -3,9 +3,16 @@
@import "peek/views/rblineprof";
#peek {
height: 35px;
position: fixed;
left: 0;
top: 0;
width: 100%;
z-index: 2000;
overflow-x: hidden;
height: $performance-bar-height;
background: $black;
line-height: 35px;
line-height: $performance-bar-height;
color: $perf-bar-text;
&.disabled {
@ -25,7 +32,8 @@
}
.wrapper {
width: 1000px;
width: 80%;
height: $performance-bar-height;
margin: 0 auto;
}

View File

@ -43,23 +43,7 @@ class Projects::GraphsController < Projects::ApplicationController
end
def get_languages
@languages = Linguist::Repository.new(@repository.rugged, @repository.rugged.head.target_id).languages
total = @languages.map(&:last).sum
@languages = @languages.map do |language|
name, share = language
color = Linguist::Language[name].color || "##{Digest::SHA256.hexdigest(name)[0...6]}"
{
value: (share.to_f * 100 / total).round(2),
label: name,
color: color,
highlight: color
}
end
@languages.sort! do |x, y|
y[:value] <=> x[:value]
end
@languages = @project.repository.languages
end
def fetch_graph

View File

@ -264,7 +264,11 @@ module ApplicationHelper
end
def page_class
"issue-boards-page" if current_controller?(:boards)
class_names = []
class_names << 'issue-boards-page' if current_controller?(:boards)
class_names << 'with-performance-bar' if performance_bar_enabled?
class_names
end
# Returns active css class when condition returns true

View File

@ -48,7 +48,11 @@ module GitlabRoutingHelper
end
def milestone_path(entity, *args)
project_milestone_path(entity.project, entity, *args)
if entity.is_group_milestone?
group_milestone_path(entity.group, entity, *args)
elsif entity.is_project_milestone?
project_milestone_path(entity.project, entity, *args)
end
end
def issue_url(entity, *args)
@ -63,6 +67,14 @@ module GitlabRoutingHelper
project_pipeline_url(pipeline.project, pipeline.id, *args)
end
def milestone_url(entity, *args)
if entity.is_group_milestone?
group_milestone_url(entity.group, entity, *args)
elsif entity.is_project_milestone?
project_milestone_url(entity.project, entity, *args)
end
end
def pipeline_job_url(pipeline, build, *args)
project_job_url(pipeline.project, build.id, *args)
end

View File

@ -40,7 +40,7 @@ module MergeRequestsHelper
def merge_path_description(merge_request, separator)
if merge_request.for_fork?
"Project:Branches: #{@merge_request.source_project_path}:#{@merge_request.source_branch} #{separator} #{@merge_request.target_project.path_with_namespace}:#{@merge_request.target_branch}"
"Project:Branches: #{@merge_request.source_project_path}:#{@merge_request.source_branch} #{separator} #{@merge_request.target_project.full_path}:#{@merge_request.target_branch}"
else
"Branches: #{@merge_request.source_branch} #{separator} #{@merge_request.target_branch}"
end

View File

@ -1,38 +1,49 @@
module NavHelper
def page_with_sidebar_class
class_name = page_gutter_class
class_name << 'page-with-new-sidebar' if defined?(@new_sidebar) && @new_sidebar
class_name
end
def page_gutter_class
if current_path?('merge_requests#show') ||
current_path?('projects/merge_requests/conflicts#show') ||
current_path?('issues#show') ||
current_path?('milestones#show')
if cookies[:collapsed_gutter] == 'true'
"page-gutter right-sidebar-collapsed"
%w[page-gutter right-sidebar-collapsed]
else
"page-gutter right-sidebar-expanded"
%w[page-gutter right-sidebar-expanded]
end
elsif current_path?('jobs#show')
"page-gutter build-sidebar right-sidebar-expanded"
%w[page-gutter build-sidebar right-sidebar-expanded]
elsif current_path?('wikis#show') ||
current_path?('wikis#edit') ||
current_path?('wikis#update') ||
current_path?('wikis#history') ||
current_path?('wikis#git_access')
"page-gutter wiki-sidebar right-sidebar-expanded"
%w[page-gutter wiki-sidebar right-sidebar-expanded]
else
[]
end
end
def nav_header_class
class_name = ''
class_name << " with-horizontal-nav" if defined?(nav) && nav
class_names = []
class_names << 'with-horizontal-nav' if defined?(nav) && nav
class_name
class_names
end
def layout_nav_class
class_name = ''
class_name << " page-with-layout-nav" if defined?(nav) && nav
class_name << " page-with-sub-nav" if content_for?(:sub_nav)
return [] if show_new_nav?
class_name
class_names = []
class_names << 'page-with-layout-nav' if defined?(nav) && nav
class_names << 'page-with-sub-nav' if content_for?(:sub_nav)
class_names
end
def nav_control_class

View File

@ -398,7 +398,7 @@ module ProjectsHelper
if project
import_path = "/Home/Stacks/import"
repo = project.path_with_namespace
repo = project.full_path
branch ||= project.default_branch
sha ||= project.commit.short_id
@ -458,7 +458,7 @@ module ProjectsHelper
def readme_cache_key
sha = @project.commit.try(:sha) || 'nil'
[@project.path_with_namespace, sha, "readme"].join('-')
[@project.full_path, sha, "readme"].join('-')
end
def current_ref

View File

@ -34,6 +34,8 @@ module WebpackHelper
end
def webpack_public_path
"#{webpack_public_host}/#{Rails.application.config.webpack.public_path}/"
relative_path = Rails.application.config.relative_url_root
webpack_path = Rails.application.config.webpack.public_path
File.join(webpack_public_host.to_s, relative_path.to_s, webpack_path.to_s, '')
end
end

View File

@ -165,7 +165,7 @@ class Notify < BaseMailer
headers['X-GitLab-Project'] = @project.name
headers['X-GitLab-Project-Id'] = @project.id
headers['X-GitLab-Project-Path'] = @project.path_with_namespace
headers['X-GitLab-Project-Path'] = @project.full_path
end
def add_unsubscription_headers_and_links

View File

@ -317,7 +317,7 @@ module Ci
return @config_processor if defined?(@config_processor)
@config_processor ||= begin
Ci::GitlabCiYamlProcessor.new(ci_yaml_file, project.path_with_namespace)
Ci::GitlabCiYamlProcessor.new(ci_yaml_file, project.full_path)
rescue Ci::GitlabCiYamlProcessor::ValidationError, Psych::SyntaxError => e
self.yaml_errors = e.message
nil

View File

@ -0,0 +1,102 @@
module Storage
module LegacyNamespace
extend ActiveSupport::Concern
def move_dir
if any_project_has_container_registry_tags?
raise Gitlab::UpdatePathError.new('Namespace cannot be moved, because at least one project has tags in container registry')
end
# Move the namespace directory in all storage paths used by member projects
repository_storage_paths.each do |repository_storage_path|
# Ensure old directory exists before moving it
gitlab_shell.add_namespace(repository_storage_path, full_path_was)
unless gitlab_shell.mv_namespace(repository_storage_path, full_path_was, full_path)
Rails.logger.error "Exception moving path #{repository_storage_path} from #{full_path_was} to #{full_path}"
# if we cannot move namespace directory we should rollback
# db changes in order to prevent out of sync between db and fs
raise Gitlab::UpdatePathError.new('namespace directory cannot be moved')
end
end
Gitlab::UploadsTransfer.new.rename_namespace(full_path_was, full_path)
Gitlab::PagesTransfer.new.rename_namespace(full_path_was, full_path)
remove_exports!
# If repositories moved successfully we need to
# send update instructions to users.
# However we cannot allow rollback since we moved namespace dir
# So we basically we mute exceptions in next actions
begin
send_update_instructions
true
rescue
# Returning false does not rollback after_* transaction but gives
# us information about failing some of tasks
false
end
end
# Hooks
# Save the storage paths before the projects are destroyed to use them on after destroy
def prepare_for_destroy
old_repository_storage_paths
end
private
def old_repository_storage_paths
@old_repository_storage_paths ||= repository_storage_paths
end
def repository_storage_paths
# We need to get the storage paths for all the projects, even the ones that are
# pending delete. Unscoping also get rids of the default order, which causes
# problems with SELECT DISTINCT.
Project.unscoped do
all_projects.select('distinct(repository_storage)').to_a.map(&:repository_storage_path)
end
end
def rm_dir
# Remove the namespace directory in all storages paths used by member projects
old_repository_storage_paths.each do |repository_storage_path|
# Move namespace directory into trash.
# We will remove it later async
new_path = "#{full_path}+#{id}+deleted"
if gitlab_shell.mv_namespace(repository_storage_path, full_path, new_path)
Gitlab::AppLogger.info %Q(Namespace directory "#{full_path}" moved to "#{new_path}")
# Remove namespace directroy async with delay so
# GitLab has time to remove all projects first
run_after_commit do
GitlabShellWorker.perform_in(5.minutes, :rm_namespace, repository_storage_path, new_path)
end
end
end
remove_exports!
end
def remove_exports!
Gitlab::Popen.popen(%W(find #{export_path} -not -path #{export_path} -delete))
end
def export_path
File.join(Gitlab::ImportExport.storage_path, full_path_was)
end
def full_path_was
if parent
parent.full_path + '/' + path_was
else
path_was
end
end
end
end

View File

@ -0,0 +1,76 @@
module Storage
module LegacyProject
extend ActiveSupport::Concern
def disk_path
full_path
end
def ensure_storage_path_exist
gitlab_shell.add_namespace(repository_storage_path, namespace.full_path)
end
def rename_repo
path_was = previous_changes['path'].first
old_path_with_namespace = File.join(namespace.full_path, path_was)
new_path_with_namespace = File.join(namespace.full_path, path)
Rails.logger.error "Attempting to rename #{old_path_with_namespace} -> #{new_path_with_namespace}"
if has_container_registry_tags?
Rails.logger.error "Project #{old_path_with_namespace} cannot be renamed because container registry tags are present!"
# we currently doesn't support renaming repository if it contains images in container registry
raise StandardError.new('Project cannot be renamed, because images are present in its container registry')
end
expire_caches_before_rename(old_path_with_namespace)
if gitlab_shell.mv_repository(repository_storage_path, old_path_with_namespace, new_path_with_namespace)
# If repository moved successfully we need to send update instructions to users.
# However we cannot allow rollback since we moved repository
# So we basically we mute exceptions in next actions
begin
gitlab_shell.mv_repository(repository_storage_path, "#{old_path_with_namespace}.wiki", "#{new_path_with_namespace}.wiki")
send_move_instructions(old_path_with_namespace)
expires_full_path_cache
@old_path_with_namespace = old_path_with_namespace
SystemHooksService.new.execute_hooks_for(self, :rename)
@repository = nil
rescue => e
Rails.logger.error "Exception renaming #{old_path_with_namespace} -> #{new_path_with_namespace}: #{e}"
# Returning false does not rollback after_* transaction but gives
# us information about failing some of tasks
false
end
else
Rails.logger.error "Repository could not be renamed: #{old_path_with_namespace} -> #{new_path_with_namespace}"
# if we cannot move namespace directory we should rollback
# db changes in order to prevent out of sync between db and fs
raise StandardError.new('repository cannot be renamed')
end
Gitlab::AppLogger.info "Project was renamed: #{old_path_with_namespace} -> #{new_path_with_namespace}"
Gitlab::UploadsTransfer.new.rename_project(path_was, path, namespace.full_path)
Gitlab::PagesTransfer.new.rename_project(path_was, path, namespace.full_path)
end
def create_repository(force: false)
# Forked import is handled asynchronously
return if forked? && !force
if gitlab_shell.add_repository(repository_storage_path, path_with_namespace)
repository.after_create
true
else
errors.add(:base, 'Failed to create repository via gitlab-shell')
false
end
end
end
end

View File

@ -0,0 +1,9 @@
module Storage
module LegacyProjectWiki
extend ActiveSupport::Concern
def disk_path
project.disk_path + '.wiki'
end
end
end

View File

@ -0,0 +1,7 @@
module Storage
module LegacyRepository
extend ActiveSupport::Concern
delegate :disk_path, to: :project
end
end

View File

@ -630,7 +630,7 @@ class MergeRequest < ActiveRecord::Base
def target_project_path
if target_project
target_project.path_with_namespace
target_project.full_path
else
"(removed)"
end
@ -638,7 +638,7 @@ class MergeRequest < ActiveRecord::Base
def source_project_path
if source_project
source_project.path_with_namespace
source_project.full_path
else
"(removed)"
end

View File

@ -8,6 +8,7 @@ class Namespace < ActiveRecord::Base
include Gitlab::VisibilityLevel
include Routable
include AfterCommitQueue
include Storage::LegacyNamespace
# Prevent users from creating unreasonably deep level of nesting.
# The number 20 was taken based on maximum nesting level of
@ -41,10 +42,11 @@ class Namespace < ActiveRecord::Base
delegate :name, to: :owner, allow_nil: true, prefix: true
after_update :move_dir, if: :path_changed?
after_commit :refresh_access_of_projects_invited_groups, on: :update, if: -> { previous_changes.key?('share_with_group_lock') }
# Save the storage paths before the projects are destroyed to use them on after destroy
# Legacy Storage specific hooks
after_update :move_dir, if: :path_changed?
before_destroy(prepend: true) { prepare_for_destroy }
after_destroy :rm_dir
@ -118,43 +120,6 @@ class Namespace < ActiveRecord::Base
owner_name
end
def move_dir
if any_project_has_container_registry_tags?
raise Gitlab::UpdatePathError.new('Namespace cannot be moved, because at least one project has tags in container registry')
end
# Move the namespace directory in all storages paths used by member projects
repository_storage_paths.each do |repository_storage_path|
# Ensure old directory exists before moving it
gitlab_shell.add_namespace(repository_storage_path, full_path_was)
unless gitlab_shell.mv_namespace(repository_storage_path, full_path_was, full_path)
Rails.logger.error "Exception moving path #{repository_storage_path} from #{full_path_was} to #{full_path}"
# if we cannot move namespace directory we should rollback
# db changes in order to prevent out of sync between db and fs
raise Gitlab::UpdatePathError.new('namespace directory cannot be moved')
end
end
Gitlab::UploadsTransfer.new.rename_namespace(full_path_was, full_path)
Gitlab::PagesTransfer.new.rename_namespace(full_path_was, full_path)
remove_exports!
# If repositories moved successfully we need to
# send update instructions to users.
# However we cannot allow rollback since we moved namespace dir
# So we basically we mute exceptions in next actions
begin
send_update_instructions
rescue
# Returning false does not rollback after_* transaction but gives
# us information about failing some of tasks
false
end
end
def any_project_has_container_registry_tags?
all_projects.any?(&:has_container_registry_tags?)
end
@ -206,14 +171,6 @@ class Namespace < ActiveRecord::Base
parent_id_changed?
end
def prepare_for_destroy
old_repository_storage_paths
end
def old_repository_storage_paths
@old_repository_storage_paths ||= repository_storage_paths
end
# Includes projects from this namespace and projects from all subgroups
# that belongs to this namespace
def all_projects
@ -232,37 +189,6 @@ class Namespace < ActiveRecord::Base
private
def repository_storage_paths
# We need to get the storage paths for all the projects, even the ones that are
# pending delete. Unscoping also get rids of the default order, which causes
# problems with SELECT DISTINCT.
Project.unscoped do
all_projects.select('distinct(repository_storage)').to_a.map(&:repository_storage_path)
end
end
def rm_dir
# Remove the namespace directory in all storages paths used by member projects
old_repository_storage_paths.each do |repository_storage_path|
# Move namespace directory into trash.
# We will remove it later async
new_path = "#{full_path}+#{id}+deleted"
if gitlab_shell.mv_namespace(repository_storage_path, full_path, new_path)
message = "Namespace directory \"#{full_path}\" moved to \"#{new_path}\""
Gitlab::AppLogger.info message
# Remove namespace directroy async with delay so
# GitLab has time to remove all projects first
run_after_commit do
GitlabShellWorker.perform_in(5.minutes, :rm_namespace, repository_storage_path, new_path)
end
end
end
remove_exports!
end
def refresh_access_of_projects_invited_groups
Group
.joins(project_group_links: :project)
@ -270,22 +196,6 @@ class Namespace < ActiveRecord::Base
.find_each(&:refresh_members_authorized_projects)
end
def remove_exports!
Gitlab::Popen.popen(%W(find #{export_path} -not -path #{export_path} -delete))
end
def export_path
File.join(Gitlab::ImportExport.storage_path, full_path_was)
end
def full_path_was
if parent
parent.full_path + '/' + path_was
else
path_was
end
end
def nesting_level_allowed
if ancestors.count > Group::NUMBER_OF_ANCESTORS_ALLOWED
errors.add(:parent_id, "has too deep level of nesting")

View File

@ -1,4 +1,8 @@
class NotificationSetting < ActiveRecord::Base
include IgnorableColumn
ignore_column :events
enum level: { global: 3, watch: 2, mention: 4, participating: 1, disabled: 0, custom: 5 }
default_value_for :level, NotificationSetting.levels[:global]
@ -41,9 +45,6 @@ class NotificationSetting < ActiveRecord::Base
:success_pipeline
].freeze
store :events, coder: JSON
before_save :convert_events
def self.find_or_create_for(source)
setting = find_or_initialize_by(source: source)
@ -54,42 +55,17 @@ class NotificationSetting < ActiveRecord::Base
setting
end
# 1. Check if this event has a value stored in its database column.
# 2. If it does, return that value.
# 3. If it doesn't (the value is nil), return the value from the serialized
# JSON hash in `events`.
(EMAIL_EVENTS - [:failed_pipeline]).each do |event|
define_method(event) do
bool = super()
bool.nil? ? !!events[event] : bool
end
alias_method :"#{event}?", event
end
# Allow people to receive failed pipeline notifications if they already have
# custom notifications enabled, as these are more like mentions than the other
# custom settings.
def failed_pipeline
bool = super
bool = events[:failed_pipeline] if bool.nil?
bool.nil? || bool
end
alias_method :failed_pipeline?, :failed_pipeline
def event_enabled?(event)
respond_to?(event) && public_send(event)
end
def convert_events
return if events_before_type_cast.nil?
EMAIL_EVENTS.each do |event|
write_attribute(event, public_send(event))
end
write_attribute(:events, nil)
respond_to?(event) && !!public_send(event)
end
end

View File

@ -17,6 +17,7 @@ class Project < ActiveRecord::Base
include ProjectFeaturesCompatibility
include SelectForProjectAuthorization
include Routable
include Storage::LegacyProject
extend Gitlab::ConfigHelper
@ -43,9 +44,8 @@ class Project < ActiveRecord::Base
default_value_for :snippets_enabled, gitlab_config_features.snippets
default_value_for :only_allow_merge_if_all_discussions_are_resolved, false
after_create :ensure_dir_exist
after_create :ensure_storage_path_exist
after_create :create_project_feature, unless: :project_feature
after_save :ensure_dir_exist, if: :namespace_id_changed?
after_save :update_project_statistics, if: :namespace_id_changed?
# set last_activity_at to the same as created_at
@ -67,6 +67,10 @@ class Project < ActiveRecord::Base
after_validation :check_pending_delete
# Legacy Storage specific hooks
after_save :ensure_storage_path_exist, if: :namespace_id_changed?
acts_as_taggable
attr_accessor :new_default_branch
@ -375,7 +379,7 @@ class Project < ActiveRecord::Base
begin
Projects::HousekeepingService.new(project).execute
rescue Projects::HousekeepingService::LeaseTaken => e
Rails.logger.info("Could not perform housekeeping for project #{project.path_with_namespace} (#{project.id}): #{e}")
Rails.logger.info("Could not perform housekeeping for project #{project.full_path} (#{project.id}): #{e}")
end
end
end
@ -476,12 +480,12 @@ class Project < ActiveRecord::Base
end
def repository
@repository ||= Repository.new(path_with_namespace, self)
@repository ||= Repository.new(full_path, self, disk_path: disk_path)
end
def container_registry_url
if Gitlab.config.registry.enabled
"#{Gitlab.config.registry.host_port}/#{path_with_namespace.downcase}"
"#{Gitlab.config.registry.host_port}/#{full_path.downcase}"
end
end
@ -520,16 +524,16 @@ class Project < ActiveRecord::Base
job_id =
if forked?
RepositoryForkWorker.perform_async(id, forked_from_project.repository_storage_path,
forked_from_project.path_with_namespace,
forked_from_project.full_path,
self.namespace.full_path)
else
RepositoryImportWorker.perform_async(self.id)
end
if job_id
Rails.logger.info "Import job started for #{path_with_namespace} with job ID #{job_id}"
Rails.logger.info "Import job started for #{full_path} with job ID #{job_id}"
else
Rails.logger.error "Import job failed to start for #{path_with_namespace}"
Rails.logger.error "Import job failed to start for #{full_path}"
end
end
@ -690,7 +694,7 @@ class Project < ActiveRecord::Base
# `from` argument can be a Namespace or Project.
def to_reference(from = nil, full: false)
if full || cross_namespace_reference?(from)
path_with_namespace
full_path
elsif cross_project_reference?(from)
path
end
@ -714,7 +718,7 @@ class Project < ActiveRecord::Base
author.ensure_incoming_email_token!
Gitlab::IncomingEmail.reply_address(
"#{path_with_namespace}+#{author.incoming_email_token}")
"#{full_path}+#{author.incoming_email_token}")
end
def build_commit_note(commit)
@ -941,7 +945,7 @@ class Project < ActiveRecord::Base
end
def url_to_repo
gitlab_shell.url_to_repo(path_with_namespace)
gitlab_shell.url_to_repo(full_path)
end
def repo_exists?
@ -974,56 +978,6 @@ class Project < ActiveRecord::Base
!group
end
def rename_repo
path_was = previous_changes['path'].first
old_path_with_namespace = File.join(namespace.full_path, path_was)
new_path_with_namespace = File.join(namespace.full_path, path)
Rails.logger.error "Attempting to rename #{old_path_with_namespace} -> #{new_path_with_namespace}"
if has_container_registry_tags?
Rails.logger.error "Project #{old_path_with_namespace} cannot be renamed because container registry tags are present!"
# we currently doesn't support renaming repository if it contains images in container registry
raise StandardError.new('Project cannot be renamed, because images are present in its container registry')
end
expire_caches_before_rename(old_path_with_namespace)
if gitlab_shell.mv_repository(repository_storage_path, old_path_with_namespace, new_path_with_namespace)
# If repository moved successfully we need to send update instructions to users.
# However we cannot allow rollback since we moved repository
# So we basically we mute exceptions in next actions
begin
gitlab_shell.mv_repository(repository_storage_path, "#{old_path_with_namespace}.wiki", "#{new_path_with_namespace}.wiki")
send_move_instructions(old_path_with_namespace)
expires_full_path_cache
@old_path_with_namespace = old_path_with_namespace
SystemHooksService.new.execute_hooks_for(self, :rename)
@repository = nil
rescue => e
Rails.logger.error "Exception renaming #{old_path_with_namespace} -> #{new_path_with_namespace}: #{e}"
# Returning false does not rollback after_* transaction but gives
# us information about failing some of tasks
false
end
else
Rails.logger.error "Repository could not be renamed: #{old_path_with_namespace} -> #{new_path_with_namespace}"
# if we cannot move namespace directory we should rollback
# db changes in order to prevent out of sync between db and fs
raise StandardError.new('repository cannot be renamed')
end
Gitlab::AppLogger.info "Project was renamed: #{old_path_with_namespace} -> #{new_path_with_namespace}"
Gitlab::UploadsTransfer.new.rename_project(path_was, path, namespace.full_path)
Gitlab::PagesTransfer.new.rename_project(path_was, path, namespace.full_path)
end
# Expires various caches before a project is renamed.
def expire_caches_before_rename(old_path)
repo = Repository.new(old_path, self)
@ -1048,7 +1002,7 @@ class Project < ActiveRecord::Base
git_http_url: http_url_to_repo,
namespace: namespace.name,
visibility_level: visibility_level,
path_with_namespace: path_with_namespace,
path_with_namespace: full_path,
default_branch: default_branch,
ci_config_path: ci_config_path
}
@ -1109,19 +1063,6 @@ class Project < ActiveRecord::Base
merge_requests.where(source_project_id: self.id)
end
def create_repository(force: false)
# Forked import is handled asynchronously
return if forked? && !force
if gitlab_shell.add_repository(repository_storage_path, path_with_namespace)
repository.after_create
true
else
errors.add(:base, 'Failed to create repository via gitlab-shell')
false
end
end
def ensure_repository
create_repository(force: true) unless repository_exists?
end
@ -1257,7 +1198,7 @@ class Project < ActiveRecord::Base
end
def pages_path
File.join(Settings.pages.path, path_with_namespace)
File.join(Settings.pages.path, disk_path)
end
def public_pages_path
@ -1265,9 +1206,21 @@ class Project < ActiveRecord::Base
end
def remove_private_deploy_keys
deploy_keys.where(public: false).delete_all
exclude_keys_linked_to_other_projects = <<-SQL
NOT EXISTS (
SELECT 1
FROM deploy_keys_projects dkp2
WHERE dkp2.deploy_key_id = deploy_keys_projects.deploy_key_id
AND dkp2.project_id != deploy_keys_projects.project_id
)
SQL
deploy_keys.where(public: false)
.where(exclude_keys_linked_to_other_projects)
.delete_all
end
# TODO: what to do here when not using Legacy Storage? Do we still need to rename and delay removal?
def remove_pages
::Projects::UpdatePagesConfigurationService.new(self).execute
@ -1315,7 +1268,7 @@ class Project < ActiveRecord::Base
end
def export_path
File.join(Gitlab::ImportExport.storage_path, path_with_namespace)
File.join(Gitlab::ImportExport.storage_path, disk_path)
end
def export_project_path
@ -1327,16 +1280,12 @@ class Project < ActiveRecord::Base
status.zero?
end
def ensure_dir_exist
gitlab_shell.add_namespace(repository_storage_path, namespace.full_path)
end
def predefined_variables
[
{ key: 'CI_PROJECT_ID', value: id.to_s, public: true },
{ key: 'CI_PROJECT_NAME', value: path, public: true },
{ key: 'CI_PROJECT_PATH', value: path_with_namespace, public: true },
{ key: 'CI_PROJECT_PATH_SLUG', value: path_with_namespace.parameterize, public: true },
{ key: 'CI_PROJECT_PATH', value: full_path, public: true },
{ key: 'CI_PROJECT_PATH_SLUG', value: full_path.parameterize, public: true },
{ key: 'CI_PROJECT_NAMESPACE', value: namespace.full_path, public: true },
{ key: 'CI_PROJECT_URL', value: web_url, public: true }
]
@ -1441,6 +1390,7 @@ class Project < ActiveRecord::Base
alias_method :name_with_namespace, :full_name
alias_method :human_name, :full_name
# @deprecated cannot remove yet because it has an index with its name in elasticsearch
alias_method :path_with_namespace, :full_path
private
@ -1495,7 +1445,7 @@ class Project < ActiveRecord::Base
def pending_delete_twin
return false unless path
Project.pending_delete.find_by_full_path(path_with_namespace)
Project.pending_delete.find_by_full_path(full_path)
end
##

View File

@ -35,9 +35,9 @@ class FlowdockService < Service
data[:after],
token: token,
repo: project.repository.path_to_repo,
repo_url: "#{Gitlab.config.gitlab.url}/#{project.path_with_namespace}",
commit_url: "#{Gitlab.config.gitlab.url}/#{project.path_with_namespace}/commit/%s",
diff_url: "#{Gitlab.config.gitlab.url}/#{project.path_with_namespace}/compare/%s...%s"
repo_url: "#{Gitlab.config.gitlab.url}/#{project.full_path}",
commit_url: "#{Gitlab.config.gitlab.url}/#{project.full_path}/commit/%s",
diff_url: "#{Gitlab.config.gitlab.url}/#{project.full_path}/compare/%s...%s"
)
end
end

View File

@ -140,7 +140,7 @@ class JiraService < IssueTrackerService
url: resource_url(user_path(author))
},
project: {
name: project.path_with_namespace,
name: project.full_path,
url: resource_url(namespace_project_path(project.namespace, project)) # rubocop:disable Cop/ProjectPathHelper
},
entity: {

View File

@ -1,5 +1,6 @@
class ProjectWiki
include Gitlab::ShellAdapter
include Storage::LegacyProjectWiki
MARKUPS = {
'Markdown' => :markdown,
@ -26,16 +27,19 @@ class ProjectWiki
@project.path + '.wiki'
end
def path_with_namespace
@project.path_with_namespace + ".wiki"
def full_path
@project.full_path + '.wiki'
end
# @deprecated use full_path when you need it for an URL route or disk_path when you want to point to the filesystem
alias_method :path_with_namespace, :full_path
def web_url
Gitlab::Routing.url_helpers.project_wiki_url(@project, :home)
end
def url_to_repo
gitlab_shell.url_to_repo(path_with_namespace)
gitlab_shell.url_to_repo(full_path)
end
def ssh_url_to_repo
@ -43,11 +47,11 @@ class ProjectWiki
end
def http_url_to_repo
"#{Gitlab.config.gitlab.url}/#{path_with_namespace}.git"
"#{Gitlab.config.gitlab.url}/#{full_path}.git"
end
def wiki_base_path
[Gitlab.config.gitlab.relative_url_root, "/", @project.path_with_namespace, "/wikis"].join('')
[Gitlab.config.gitlab.relative_url_root, '/', @project.full_path, '/wikis'].join('')
end
# Returns the Gollum::Wiki object.
@ -134,7 +138,7 @@ class ProjectWiki
end
def repository
@repository ||= Repository.new(path_with_namespace, @project)
@repository ||= Repository.new(full_path, @project, disk_path: disk_path)
end
def default_branch
@ -142,7 +146,7 @@ class ProjectWiki
end
def create_repo!
if init_repo(path_with_namespace)
if init_repo(disk_path)
wiki = Gollum::Wiki.new(path_to_repo)
else
raise CouldNotCreateWikiError
@ -162,15 +166,15 @@ class ProjectWiki
web_url: web_url,
git_ssh_url: ssh_url_to_repo,
git_http_url: http_url_to_repo,
path_with_namespace: path_with_namespace,
path_with_namespace: full_path,
default_branch: default_branch
}
end
private
def init_repo(path_with_namespace)
gitlab_shell.add_repository(project.repository_storage_path, path_with_namespace)
def init_repo(disk_path)
gitlab_shell.add_repository(project.repository_storage_path, disk_path)
end
def commit_details(action, message = nil, title = nil)
@ -184,7 +188,7 @@ class ProjectWiki
end
def path_to_repo
@path_to_repo ||= File.join(project.repository_storage_path, "#{path_with_namespace}.git")
@path_to_repo ||= File.join(project.repository_storage_path, "#{disk_path}.git")
end
def update_project_activity

View File

@ -4,7 +4,7 @@ class Repository
include Gitlab::ShellAdapter
include RepositoryMirroring
attr_accessor :path_with_namespace, :project
attr_accessor :full_path, :disk_path, :project
delegate :ref_name_for_sha, to: :raw_repository
@ -52,13 +52,14 @@ class Repository
end
end
def initialize(path_with_namespace, project)
@path_with_namespace = path_with_namespace
def initialize(full_path, project, disk_path: nil)
@full_path = full_path
@disk_path = disk_path || full_path
@project = project
end
def raw_repository
return nil unless path_with_namespace
return nil unless full_path
@raw_repository ||= initialize_raw_repository
end
@ -66,7 +67,7 @@ class Repository
# Return absolute path to repository
def path_to_repo
@path_to_repo ||= File.expand_path(
File.join(repository_storage_path, path_with_namespace + ".git")
File.join(repository_storage_path, disk_path + '.git')
)
end
@ -469,7 +470,7 @@ class Repository
# Gitaly migration: https://gitlab.com/gitlab-org/gitaly/issues/314
def exists?
return false unless path_with_namespace
return false unless full_path
Gitlab::GitalyClient.migrate(:repository_exists) do |enabled|
if enabled
@ -1005,7 +1006,7 @@ class Repository
end
def fetch_remote(remote, forced: false, no_tags: false)
gitlab_shell.fetch_remote(repository_storage_path, path_with_namespace, remote, forced: forced, no_tags: no_tags)
gitlab_shell.fetch_remote(repository_storage_path, disk_path, remote, forced: forced, no_tags: no_tags)
end
def fetch_ref(source_path, source_ref, target_ref)
@ -1104,7 +1105,8 @@ class Repository
end
def cache
@cache ||= RepositoryCache.new(path_with_namespace, @project.id)
# TODO: should we use UUIDs here? We could move repositories without clearing this cache
@cache ||= RepositoryCache.new(full_path, @project.id)
end
def tags_sorted_by_committed_date
@ -1127,7 +1129,7 @@ class Repository
end
def repository_event(event, tags = {})
Gitlab::Metrics.add_event(event, { path: path_with_namespace }.merge(tags))
Gitlab::Metrics.add_event(event, { path: full_path }.merge(tags))
end
def create_commit(params = {})
@ -1141,6 +1143,6 @@ class Repository
end
def initialize_raw_repository
Gitlab::Git::Repository.new(project.repository_storage, path_with_namespace + '.git')
Gitlab::Git::Repository.new(project.repository_storage, disk_path + '.git')
end
end

View File

@ -44,7 +44,7 @@ class GlobalPolicy < BasePolicy
prevent :log_in
end
rule { admin | ~restricted_public_level }.policy do
rule { ~(anonymous & restricted_public_level) }.policy do
enable :read_users_list
end
end

View File

@ -60,7 +60,7 @@ class GitOperationService
start_branch_name = nil if start_repository.empty_repo?
if start_branch_name && !start_repository.branch_exists?(start_branch_name)
raise ArgumentError, "Cannot find branch #{start_branch_name} in #{start_repository.path_with_namespace}"
raise ArgumentError, "Cannot find branch #{start_branch_name} in #{start_repository.full_path}"
end
update_branch_with_hooks(branch_name) do

View File

@ -9,7 +9,7 @@ module Projects
def async_execute
project.update_attribute(:pending_delete, true)
job_id = ProjectDestroyWorker.perform_async(project.id, current_user.id, params)
Rails.logger.info("User #{current_user.id} scheduled destruction of project #{project.path_with_namespace} with job ID #{job_id}")
Rails.logger.info("User #{current_user.id} scheduled destruction of project #{project.full_path} with job ID #{job_id}")
end
def execute
@ -40,7 +40,7 @@ module Projects
private
def repo_path
project.path_with_namespace
project.disk_path
end
def wiki_path
@ -127,7 +127,7 @@ module Projects
def flush_caches(project)
project.repository.before_delete
Repository.new(wiki_path, project).before_delete
Repository.new(wiki_path, project, disk_path: repo_path).before_delete
end
end
end

View File

@ -2,7 +2,7 @@ module Projects
module ImportExport
class ExportService < BaseService
def execute(_options = {})
@shared = Gitlab::ImportExport::Shared.new(relative_path: File.join(project.path_with_namespace, 'work'))
@shared = Gitlab::ImportExport::Shared.new(relative_path: File.join(project.disk_path, 'work'))
save_all
end

View File

@ -11,7 +11,7 @@ module Projects
success
rescue => e
error("Error importing repository #{project.import_url} into #{project.path_with_namespace} - #{e.message}")
error("Error importing repository #{project.import_url} into #{project.full_path} - #{e.message}")
end
private
@ -51,7 +51,7 @@ module Projects
end
def clone_repository
gitlab_shell.import_repository(project.repository_storage_path, project.path_with_namespace, project.import_url)
gitlab_shell.import_repository(project.repository_storage_path, project.disk_path, project.import_url)
end
def fetch_repository

View File

@ -34,7 +34,7 @@ module Projects
private
def transfer(project)
@old_path = project.path_with_namespace
@old_path = project.full_path
@old_group = project.group
@new_path = File.join(@new_namespace.try(:full_path) || '', project.path)
@old_namespace = project.namespace
@ -61,11 +61,13 @@ module Projects
project.send_move_instructions(@old_path)
# Move main repository
# TODO: check storage type and NOOP when not using Legacy
unless move_repo_folder(@old_path, @new_path)
raise TransferError.new('Cannot move project')
end
# Move wiki repo also if present
# TODO: check storage type and NOOP when not using Legacy
move_repo_folder("#{@old_path}.wiki", "#{@new_path}.wiki")
# Move missing group labels to project

View File

@ -4,6 +4,9 @@ module QuickActions
attr_reader :issuable
SHRUG = '¯\\_(ツ)_/¯'.freeze
TABLEFLIP = '(╯°□°)╯︵ ┻━┻'.freeze
# Takes a text and interprets the commands that are extracted from it.
# Returns the content without commands, and hash of changes to be applied to a record.
def execute(content, issuable)
@ -14,6 +17,7 @@ module QuickActions
content, commands = extractor.extract_commands(content, context)
extract_updates(commands, context)
[content, @updates]
end
@ -423,6 +427,18 @@ module QuickActions
@updates[:spend_time] = { duration: :reset, user: current_user }
end
desc "Append the comment with #{SHRUG}"
params '<Comment>'
substitution :shrug do |comment|
"#{comment} #{SHRUG}"
end
desc "Append the comment with #{TABLEFLIP}"
params '<Comment>'
substitution :tableflip do |comment|
"#{comment} #{TABLEFLIP}"
end
# This is a dummy command, so that it appears in the autocomplete commands
desc 'CC'
params '@user'

View File

@ -24,7 +24,7 @@ class SystemHooksService
key: model.key,
id: model.id
)
if model.user
data[:username] = model.user.username
end
@ -56,7 +56,7 @@ class SystemHooksService
when GroupMember
data.merge!(group_member_data(model))
end
data
end
@ -79,7 +79,7 @@ class SystemHooksService
{
name: model.name,
path: model.path,
path_with_namespace: model.path_with_namespace,
path_with_namespace: model.full_path,
project_id: model.id,
owner_name: owner.name,
owner_email: owner.respond_to?(:email) ? owner.email : "",
@ -93,7 +93,7 @@ class SystemHooksService
{
project_name: project.name,
project_path: project.path,
project_path_with_namespace: project.path_with_namespace,
project_path_with_namespace: project.full_path,
project_id: project.id,
user_username: model.user.username,
user_name: model.user.name,

View File

@ -30,7 +30,7 @@ class FileUploader < GitlabUploader
#
# Returns a String without a trailing slash
def self.dynamic_path_segment(model)
File.join(CarrierWave.root, base_dir, model.path_with_namespace)
File.join(CarrierWave.root, base_dir, model.full_path)
end
attr_accessor :model

View File

@ -70,7 +70,7 @@
%span.badge
= storage_counter(project.statistics.storage_size)
%span.pull-right.light
%span.monospace= project.path_with_namespace + ".git"
%span.monospace= project.full_path + '.git'
.panel-footer
= paginate @projects, param_name: 'projects_page', theme: 'gitlab'
@ -88,7 +88,7 @@
%span.badge
= storage_counter(project.statistics.storage_size)
%span.pull-right.light
%span.monospace= project.path_with_namespace + ".git"
%span.monospace= project.full_path + '.git'
.col-md-6
- if can?(current_user, :admin_group_member, @group)

View File

@ -1,5 +1,7 @@
- page_title "UI Development Kit", "Help"
- lorem = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed fermentum nisi sapien, non consequat lectus aliquam ultrices. Suspendisse sodales est euismod nunc condimentum, a consectetur diam ornare."
- content_for :page_specific_javascripts do
= webpack_bundle_tag('ui_development_kit')
.gitlab-ui-dev-kit
%h1 GitLab UI development kit
@ -407,29 +409,6 @@
.dropdown-content
.dropdown-loading
= icon('spinner spin')
:javascript
$('#js-project-dropdown').glDropdown({
data: function (term, callback) {
Api.projects(term, { order_by: 'last_activity_at' }, function (data) {
callback(data);
});
},
text: function (project) {
return project.name_with_namespace || project.name;
},
selectable: true,
fieldName: "author_id",
filterable: true,
search: {
fields: ['name_with_namespace']
},
id: function (data) {
return data.id;
},
isSelected: function (data) {
return data.id === 2;
}
})
.example
%div

View File

@ -25,7 +25,7 @@
%td
= provider_project_link(provider, project.import_source)
%td
= link_to project.path_with_namespace, [project.namespace.becomes(Namespace), project]
= link_to project.full_path, [project.namespace.becomes(Namespace), project]
%td.job-status
- if project.import_status == 'finished'
%span

View File

@ -4,7 +4,7 @@
job.attr("id", "project_#{@project.id}")
target_field = job.find(".import-target")
target_field.empty()
target_field.append('#{link_to @project.path_with_namespace, project_path(@project)}')
target_field.append('#{link_to @project.full_path, project_path(@project)}')
$("table.import-jobs tbody").prepend(job)
job.addClass("active").find(".import-actions").html("<i class='fa fa-spinner fa-spin'></i> started")
- else

View File

@ -35,7 +35,7 @@
%td
= link_to project.import_source, "https://bitbucket.org/#{project.import_source}", target: '_blank', rel: 'noopener noreferrer'
%td
= link_to project.path_with_namespace, [project.namespace.becomes(Namespace), project]
= link_to project.full_path, [project.namespace.becomes(Namespace), project]
%td.job-status
- if project.import_status == 'finished'
%span

View File

@ -33,7 +33,7 @@
%td
= project.import_source
%td
= link_to project.path_with_namespace, [project.namespace.becomes(Namespace), project]
= link_to project.full_path, [project.namespace.becomes(Namespace), project]
%td.job-status
- if project.import_status == 'finished'
%span

View File

@ -28,7 +28,7 @@
%td
= link_to project.import_source, "https://gitlab.com/#{project.import_source}", target: "_blank"
%td
= link_to project.path_with_namespace, [project.namespace.becomes(Namespace), project]
= link_to project.full_path, [project.namespace.becomes(Namespace), project]
%td.job-status
- if project.import_status == 'finished'
%span

View File

@ -38,7 +38,7 @@
%td
= link_to project.import_source, "https://code.google.com/p/#{project.import_source}", target: "_blank", rel: 'noopener noreferrer'
%td
= link_to project.path_with_namespace, [project.namespace.becomes(Namespace), project]
= link_to project.full_path, [project.namespace.becomes(Namespace), project]
%td.job-status
- if project.import_status == 'finished'
%span

View File

@ -1,3 +1,4 @@
-# haml-lint:disable InlineJavaScript
:javascript
var _gaq = _gaq || [];
_gaq.push(['_setAccount', '#{extra_config.google_analytics_id}']);

View File

@ -2,6 +2,7 @@
- noteable_type = @noteable.class if @noteable.present?
- if project
-# haml-lint:disable InlineJavaScript
:javascript
gl.GfmAutoComplete = gl.GfmAutoComplete || {};
gl.GfmAutoComplete.dataSources = {

View File

@ -1,4 +1,4 @@
.page-with-sidebar{ class: "#{('page-with-new-sidebar' if defined?(@new_sidebar) && @new_sidebar)} #{page_gutter_class}" }
.page-with-sidebar{ class: page_with_sidebar_class }
- if show_new_nav?
- if defined?(nav) && nav
= render "layouts/nav/#{nav}"
@ -9,7 +9,7 @@
= render "layouts/nav/#{nav}"
- if content_for?(:sub_nav)
= yield :sub_nav
.content-wrapper{ class: "#{(layout_nav_class unless show_new_nav?)}" }
.content-wrapper{ class: layout_nav_class }
- if show_new_nav?
.mobile-overlay
.alert-wrapper

View File

@ -1,4 +1,5 @@
<!-- Piwik -->
-# haml-lint:disable InlineJavaScript
:javascript
var _paq = _paq || [];
_paq.push(['trackPageView']);

View File

@ -1,8 +1,9 @@
!!! 5
%html{ lang: I18n.locale, class: "#{page_class}" }
%html{ lang: I18n.locale, class: page_class }
= render "layouts/head"
%body{ class: @body_class, data: { page: body_data_page, project: "#{@project.path if @project}", group: "#{@group.path if @group}", find_file: find_file_path } }
= render "layouts/init_auto_complete" if @gfm_form
= render 'peek/bar'
- if show_new_nav?
= render "layouts/header/new"
- else
@ -10,5 +11,3 @@
= render 'layouts/page', sidebar: sidebar, nav: nav
= yield :scripts_body
= render 'peek/bar'

View File

@ -91,8 +91,8 @@
= nav_link(controller: :abuse_reports) do
= link_to admin_abuse_reports_path, title: "Abuse Reports" do
%span
Abuse Reports
%span.badge.count= number_with_delimiter(AbuseReport.count(:all))
Abuse Reports
- if akismet_enabled?
= nav_link(controller: :spam_logs) do

View File

@ -28,9 +28,9 @@
= nav_link(path: ['groups#issues', 'labels#index', 'milestones#index']) do
= link_to issues_group_path(@group), title: 'Issues' do
%span
Issues
- issues = IssuesFinder.new(current_user, group_id: @group.id, state: 'opened').execute
%span.badge.count= number_with_delimiter(issues.count)
Issues
%ul.sidebar-sub-level-items
= nav_link(path: 'groups#issues', html_options: { class: 'home' }) do
@ -51,9 +51,9 @@
= nav_link(path: 'groups#merge_requests') do
= link_to merge_requests_group_path(@group), title: 'Merge Requests' do
%span
Merge Requests
- merge_requests = MergeRequestsFinder.new(current_user, group_id: @group.id, state: 'opened', non_archived: true).execute
%span.badge.count= number_with_delimiter(merge_requests.count)
Merge Requests
= nav_link(path: 'group_members#index') do
= link_to group_group_members_path(@group), title: 'Members' do
%span

View File

@ -10,6 +10,7 @@
- content_for :project_javascripts do
- project = @target_project || @project
- if current_user
-# haml-lint:disable InlineJavaScript
:javascript
window.uploads_path = "#{project_uploads_path(project)}";

View File

@ -2,6 +2,7 @@
- content_for :page_specific_javascripts do
- if @snippet && current_user
-# haml-lint:disable InlineJavaScript
:javascript
window.uploads_path = "#{upload_path('personal_snippet', id: @snippet.id)}";

View File

@ -0,0 +1,2 @@
%span.current-host
= truncate(view.hostname)

View File

@ -1,5 +1,6 @@
- page_title "Personal Access Tokens"
- @content_class = "limit-container-width" unless fluid_layout
= render 'profiles/head'
.row.prepend-top-default
@ -19,7 +20,7 @@
%h5.prepend-top-0
Your New Personal Access Token
.form-group
= text_field_tag 'created-personal-access-token', flash[:personal_access_token], readonly: true, class: "form-control", 'aria-describedby' => "created-personal-access-token-help-block"
= text_field_tag 'created-personal-access-token', flash[:personal_access_token], readonly: true, class: "form-control js-select-on-focus", 'aria-describedby' => "created-personal-access-token-help-block"
= clipboard_button(text: flash[:personal_access_token], title: "Copy personal access token to clipboard", placement: "left")
%span#created-personal-access-token-help-block.help-block.text-danger Make sure you save it - you won't be able to access it again.
@ -28,8 +29,3 @@
= render "shared/personal_access_tokens_form", path: profile_personal_access_tokens_path, impersonation: false, token: @personal_access_token, scopes: @scopes
= render "shared/personal_access_tokens_table", impersonation: false, active_tokens: @active_personal_access_tokens, inactive_tokens: @inactive_personal_access_tokens
:javascript
$("#created-personal-access-token").click(function() {
this.select();
});

View File

@ -7,97 +7,92 @@
= render 'profiles/head'
- if inject_u2f_api?
- content_for :page_specific_javascripts do
- content_for :page_specific_javascripts do
- if inject_u2f_api?
= page_specific_javascript_bundle_tag('u2f')
= page_specific_javascript_bundle_tag('two_factor_auth')
.row.prepend-top-default
.col-lg-4
%h4.prepend-top-0
Register Two-Factor Authentication App
%p
Use an app on your mobile device to enable two-factor authentication (2FA).
.col-lg-8
- if current_user.two_factor_otp_enabled?
= icon "check inverse", base: "circle", class: "text-success", text: "You've already enabled two-factor authentication using mobile authenticator applications. You can disable it from your account settings page."
- else
.js-two-factor-auth{ 'data-two-factor-skippable' => "#{two_factor_skippable?}", 'data-two_factor_skip_url' => skip_profile_two_factor_auth_path }
.row.prepend-top-default
.col-lg-4
%h4.prepend-top-0
Register Two-Factor Authentication App
%p
Download the Google Authenticator application from App Store or Google Play Store and scan this code.
More information is available in the #{link_to('documentation', help_page_path('profile/two_factor_authentication'))}.
.row.append-bottom-10
.col-md-4
= raw @qr_code
.col-md-8
.account-well
%p.prepend-top-0.append-bottom-0
Can't scan the code?
%p.prepend-top-0.append-bottom-0
To add the entry manually, provide the following details to the application on your phone.
%p.prepend-top-0.append-bottom-0
Account:
= @account_string
%p.prepend-top-0.append-bottom-0
Key:
= current_user.otp_secret.scan(/.{4}/).join(' ')
%p.two-factor-new-manual-content
Time based: Yes
= form_tag profile_two_factor_auth_path, method: :post do |f|
- if @error
.alert.alert-danger
= @error
.form-group
= label_tag :pin_code, nil, class: "label-light"
= text_field_tag :pin_code, nil, class: "form-control", required: true
.prepend-top-default
= submit_tag 'Register with two-factor app', class: 'btn btn-success'
Use an app on your mobile device to enable two-factor authentication (2FA).
.col-lg-8
- if current_user.two_factor_otp_enabled?
= icon "check inverse", base: "circle", class: "text-success", text: "You've already enabled two-factor authentication using mobile authenticator applications. You can disable it from your account settings page."
- else
%p
Download the Google Authenticator application from App Store or Google Play Store and scan this code.
More information is available in the #{link_to('documentation', help_page_path('profile/two_factor_authentication'))}.
.row.append-bottom-10
.col-md-4
= raw @qr_code
.col-md-8
.account-well
%p.prepend-top-0.append-bottom-0
Can't scan the code?
%p.prepend-top-0.append-bottom-0
To add the entry manually, provide the following details to the application on your phone.
%p.prepend-top-0.append-bottom-0
Account:
= @account_string
%p.prepend-top-0.append-bottom-0
Key:
= current_user.otp_secret.scan(/.{4}/).join(' ')
%p.two-factor-new-manual-content
Time based: Yes
= form_tag profile_two_factor_auth_path, method: :post do |f|
- if @error
.alert.alert-danger
= @error
.form-group
= label_tag :pin_code, nil, class: "label-light"
= text_field_tag :pin_code, nil, class: "form-control", required: true
.prepend-top-default
= submit_tag 'Register with two-factor app', class: 'btn btn-success'
%hr
%hr
.row.prepend-top-default
.row.prepend-top-default
.col-lg-4
%h4.prepend-top-0
Register Universal Two-Factor (U2F) Device
%p
Use a hardware device to add the second factor of authentication.
%p
As U2F devices are only supported by a few browsers, we require that you set up a
two-factor authentication app before a U2F device. That way you'll always be able to
log in - even when you're using an unsupported browser.
.col-lg-8
- if @u2f_registration.errors.present?
= form_errors(@u2f_registration)
= render "u2f/register"
.col-lg-4
%h4.prepend-top-0
Register Universal Two-Factor (U2F) Device
%p
Use a hardware device to add the second factor of authentication.
%p
As U2F devices are only supported by a few browsers, we require that you set up a
two-factor authentication app before a U2F device. That way you'll always be able to
log in - even when you're using an unsupported browser.
.col-lg-8
- if @u2f_registration.errors.present?
= form_errors(@u2f_registration)
= render "u2f/register"
%hr
%hr
%h5 U2F Devices (#{@u2f_registrations.length})
%h5 U2F Devices (#{@u2f_registrations.length})
- if @u2f_registrations.present?
.table-responsive
%table.table.table-bordered.u2f-registrations
%colgroup
%col{ width: "50%" }
%col{ width: "30%" }
%col{ width: "20%" }
%thead
%tr
%th Name
%th Registered On
%th
%tbody
- @u2f_registrations.each do |registration|
- if @u2f_registrations.present?
.table-responsive
%table.table.table-bordered.u2f-registrations
%colgroup
%col{ width: "50%" }
%col{ width: "30%" }
%col{ width: "20%" }
%thead
%tr
%td= registration.name.presence || "<no name set>"
%td= registration.created_at.to_date.to_s(:medium)
%td= link_to "Delete", profile_u2f_registration_path(registration), method: :delete, class: "btn btn-danger pull-right", data: { confirm: "Are you sure you want to delete this device? This action cannot be undone." }
%th Name
%th Registered On
%th
%tbody
- @u2f_registrations.each do |registration|
%tr
%td= registration.name.presence || "<no name set>"
%td= registration.created_at.to_date.to_s(:medium)
%td= link_to "Delete", profile_u2f_registration_path(registration), method: :delete, class: "btn btn-danger pull-right", data: { confirm: "Are you sure you want to delete this device? This action cannot be undone." }
- else
.settings-message.text-center
You don't have any U2F devices registered yet.
- if two_factor_skippable?
:javascript
var button = "<a class='btn btn-xs btn-warning pull-right' data-method='patch' href='#{skip_profile_two_factor_auth_path}'>Configure it later</a>";
$(".flash-alert").append(button);
- else
.settings-message.text-center
You don't have any U2F devices registered yet.

View File

@ -8,9 +8,3 @@
.content_list.project-activity{ :"data-href" => activity_project_path(@project) }
= spinner
:javascript
var activity = new gl.Activities();
$(document).on('page:restore', function (event) {
activity.reloadActivities()
})

View File

@ -20,6 +20,3 @@
- unless can?(current_user, :push_code, @project)
.inline.prepend-left-10
= commit_in_fork_help
:javascript
new NewCommitForm($('.js-create-dir-form'))

View File

@ -13,6 +13,3 @@
.col-sm-offset-2.col-sm-10
= button_tag 'Delete file', class: 'btn btn-remove btn-remove-file'
= link_to "Cancel", '#', class: "btn btn-cancel", "data-dismiss" => "modal"
:javascript
new NewCommitForm($('.js-delete-blob-form'))

View File

@ -28,8 +28,4 @@
.form-actions
= button_tag 'Create branch', class: 'btn btn-create', tabindex: 3
= link_to 'Cancel', project_branches_path(@project), class: 'btn btn-cancel'
:javascript
var availableRefs = #{@project.repository.ref_names.to_json};
new NewBranchForm($('.js-create-branch-form'), availableRefs)
%script#availableRefs{ type: "application/json" }= @project.repository.ref_names.to_json.html_safe

View File

@ -1,4 +1,4 @@
.page-content-header
.page-content-header.js-commit-box{ 'data-commit-path' => branches_project_commit_path(@project, @commit.id) }
.header-main-content
= render partial: 'signature', object: @commit.signature
%strong
@ -79,6 +79,3 @@
= render 'shared/mini_pipeline_graph', pipeline: last_pipeline, klass: 'js-commit-pipeline-graph'
in
= time_interval_in_words last_pipeline.duration
:javascript
$(".commit-info.branches").load("#{branches_project_commit_path(@project, @commit.id)}");

View File

@ -5,7 +5,7 @@
- notes = commit.notes
- note_count = notes.user.count
- cache_key = [project.path_with_namespace, commit.id, current_application_settings, note_count, @path.presence, current_controller?(:commits)]
- cache_key = [project.full_path, commit.id, current_application_settings, note_count, @path.presence, current_controller?(:commits)]
- cache_key.push(commit.status(ref)) if commit.status(ref)
= cache(cache_key, expires_in: 1.day) do

View File

@ -11,34 +11,32 @@
= content_for :sub_nav do
= render "head"
%div{ class: container_class }
.tree-holder
.nav-block
.tree-ref-container
.tree-ref-holder
= render 'shared/ref_switcher', destination: 'commits'
.js-project-commits-show{ 'data-commits-limit' => @limit }
%div{ class: container_class }
.tree-holder
.nav-block
.tree-ref-container
.tree-ref-holder
= render 'shared/ref_switcher', destination: 'commits'
%ul.breadcrumb.repo-breadcrumb
= commits_breadcrumbs
.tree-controls.hidden-xs.hidden-sm
- if @merge_request.present?
.control
= link_to _("View open merge request"), project_merge_request_path(@project, @merge_request), class: 'btn'
- elsif create_mr_button?(@repository.root_ref, @ref)
.control
= link_to _("Create merge request"), create_mr_path(@repository.root_ref, @ref), class: 'btn btn-success'
%ul.breadcrumb.repo-breadcrumb
= commits_breadcrumbs
.tree-controls.hidden-xs.hidden-sm
- if @merge_request.present?
.control
= link_to _("View open merge request"), project_merge_request_path(@project, @merge_request), class: 'btn'
- elsif create_mr_button?(@repository.root_ref, @ref)
= form_tag(project_commits_path(@project, @id), method: :get, class: 'commits-search-form', data: { 'signatures-path' => namespace_project_signatures_path }) do
= search_field_tag :search, params[:search], { placeholder: _('Filter by commit message'), id: 'commits-search', class: 'form-control search-text-input input-short', spellcheck: false }
.control
= link_to _("Create merge request"), create_mr_path(@repository.root_ref, @ref), class: 'btn btn-success'
= link_to project_commits_path(@project, @ref, rss_url_options), title: _("Commits feed"), class: 'btn' do
= icon("rss")
.control
= form_tag(project_commits_path(@project, @id), method: :get, class: 'commits-search-form', data: { 'signatures-path' => namespace_project_signatures_path }) do
= search_field_tag :search, params[:search], { placeholder: _('Filter by commit message'), id: 'commits-search', class: 'form-control search-text-input input-short', spellcheck: false }
.control
= link_to project_commits_path(@project, @ref, rss_url_options), title: _("Commits feed"), class: 'btn' do
= icon("rss")
%div{ id: dom_id(@project) }
%ol#commits-list.list-unstyled.content_list
= render 'commits', project: @project, ref: @ref
= spinner
:javascript
CommitsList.init(#{@limit});
%div{ id: dom_id(@project) }
%ol#commits-list.list-unstyled.content_list
= render 'commits', project: @project, ref: @ref
= spinner

View File

@ -1,7 +1,7 @@
- page_title "Find File", @ref
= render "projects/commits/head"
.file-finder-holder.tree-holder.clearfix
.file-finder-holder.tree-holder.clearfix.js-file-finder{ 'data-file-find-url': "#{escape_javascript(project_files_path(@project, @ref, @options.merge(format: :json)))}", 'data-find-tree-url': escape_javascript(project_tree_path(@project, @ref)), 'data-blob-url-template': escape_javascript(project_blob_path(@project, @id || @commit.id)) }
.nav-block
.tree-ref-holder
= render 'shared/ref_switcher', destination: 'find_file', path: @path
@ -17,11 +17,3 @@
%table.table.files-slider{ class: "table_#{@hex_path} tree-table table-striped" }
%tbody
= spinner nil, true
:javascript
var projectFindFile = new ProjectFindFile($(".file-finder-holder"), {
url: "#{escape_javascript(project_files_path(@project, @ref, @options.merge(format: :json)))}",
treeUrl: "#{escape_javascript(project_tree_path(@project, @ref))}",
blobUrlTemplate: "#{escape_javascript(project_blob_path(@project, @id || @commit.id))}"
});
new ShortcutsFindFile(projectFindFile);

View File

@ -3,8 +3,9 @@
- if show_new_nav?
- add_to_breadcrumbs("Repository", project_tree_path(@project))
- content_for :page_specific_javascripts do
= page_specific_javascript_bundle_tag('common_d3')
= page_specific_javascript_bundle_tag('graphs')
= webpack_bundle_tag('common_d3')
= webpack_bundle_tag('graphs')
= webpack_bundle_tag('graphs_charts')
= render "projects/commits/head"
.repo-charts{ class: container_class }
@ -75,55 +76,10 @@
Commits per day hour (UTC)
%canvas#hour-chart
:javascript
var responsiveChart = function (selector, data) {
var options = { "scaleOverlay": true, responsive: true, pointHitDetectionRadius: 2, maintainAspectRatio: false };
// get selector by context
var ctx = selector.get(0).getContext("2d");
// pointing parent container to make chart.js inherit its width
var container = $(selector).parent();
var generateChart = function() {
selector.attr('width', $(container).width());
if (window.innerWidth < 768) {
// Scale fonts if window width lower than 768px (iPad portrait)
options.scaleFontSize = 8
}
return new Chart(ctx).Bar(data, options);
};
// enabling auto-resizing
$(window).resize(generateChart);
return generateChart();
};
var chartData = function (keys, values) {
var data = {
labels : keys,
datasets : [{
fillColor : "rgba(220,220,220,0.5)",
strokeColor : "rgba(220,220,220,1)",
barStrokeWidth: 1,
barValueSpacing: 1,
barDatasetSpacing: 1,
data : values
}]
};
return data;
};
var hourData = chartData(#{@commits_per_time.keys.to_json}, #{@commits_per_time.values.to_json});
responsiveChart($('#hour-chart'), hourData);
var dayData = chartData(#{@commits_per_week_days.keys.to_json}, #{@commits_per_week_days.values.to_json});
responsiveChart($('#weekday-chart'), dayData);
var monthData = chartData(#{@commits_per_month.keys.to_json}, #{@commits_per_month.values.to_json});
responsiveChart($('#month-chart'), monthData);
var data = #{@languages.to_json};
var ctx = $("#languages-chart").get(0).getContext("2d");
var options = {
scaleOverlay: true,
responsive: true,
maintainAspectRatio: false
}
var myPieChart = new Chart(ctx).Pie(data, options);
%script#projectChartData{ type: "application/json" }
- projectChartData = {};
- projectChartData['hour'] = { 'keys' => @commits_per_time.keys, 'values' => @commits_per_time.values }
- projectChartData['weekDays'] = { 'keys' => @commits_per_week_days.keys, 'values' => @commits_per_week_days.values }
- projectChartData['month'] = { 'keys' => @commits_per_month.keys, 'values' => @commits_per_month.values }
- projectChartData['languages'] = @languages
= projectChartData.to_json.html_safe

View File

@ -1,15 +1,16 @@
- @no_container = true
- page_title "Contributors"
- content_for :page_specific_javascripts do
= page_specific_javascript_bundle_tag('common_d3')
= page_specific_javascript_bundle_tag('graphs')
= webpack_bundle_tag('common_d3')
= webpack_bundle_tag('graphs')
= webpack_bundle_tag('graphs_show')
- if show_new_nav?
- add_to_breadcrumbs("Repository", project_tree_path(@project))
= render 'projects/commits/head'
%div{ class: container_class }
.js-graphs-show{ class: container_class, 'data-project-graph-path': project_graph_path(@project, current_ref, format: :json) }
.sub-header-block
.tree-ref-holder
= render 'shared/ref_switcher', destination: 'graphs'
@ -33,24 +34,3 @@
#contributors-master
#contributors.clearfix
%ol.contributors-list.clearfix
:javascript
$.ajax({
type: "GET",
url: "#{project_graph_path(@project, current_ref, format: :json)}",
dataType: "json",
success: function (data) {
var graph = new ContributorsStatGraph();
graph.init(data);
$("#brush_change").change(function(){
graph.change_date_header();
graph.redraw_authors();
});
$(".stat-graph").fadeIn();
$(".loading-graph").hide();
}
});

View File

@ -10,5 +10,3 @@
- if @project.external_import?
%p.monospace git clone --bare #{@project.safe_import_url}
%p Please wait while we import the repository for you. Refresh at will.
:javascript
new ProjectImport();

View File

@ -33,7 +33,7 @@
Suggestions:
%code= 'gitlab'
%code= @project.path # Path contains no spaces, but dashes
%code= @project.path_with_namespace
%code= @project.full_path
%p
Reserved:
= link_to 'https://docs.mattermost.com/help/messaging/executing-commands.html#built-in-commands', target: '__blank' do

View File

@ -41,7 +41,7 @@
- projects = target_projects(@project)
.merge-request-select.dropdown
= f.hidden_field :target_project_id
= dropdown_toggle f.object.target_project.path_with_namespace, { toggle: "dropdown", field_name: "#{f.object_name}[target_project_id]", disabled: @merge_request.persisted? }, { toggle_class: "js-compare-dropdown js-target-project" }
= dropdown_toggle f.object.target_project.full_path, { toggle: "dropdown", field_name: "#{f.object_name}[target_project_id]", disabled: @merge_request.persisted? }, { toggle_class: "js-compare-dropdown js-target-project" }
.dropdown-menu.dropdown-menu-selectable.dropdown-target-project
= dropdown_title("Select target project")
= dropdown_filter("Search projects")

View File

@ -2,4 +2,4 @@
- projects.each do |project|
%li
%a{ href: "#", class: "#{('is-active' if selected == project.id)}", data: { id: project.id } }
= project.path_with_namespace
= project.full_path

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