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

View File

@ -6,6 +6,7 @@ inherit_from: .rubocop_todo.yml
AllCops: AllCops:
TargetRubyVersion: 2.3 TargetRubyVersion: 2.3
TargetRailsVersion: 4.2
# Cop names are not d§splayed in offense messages by default. Change behavior # Cop names are not d§splayed in offense messages by default. Change behavior
# by overriding DisplayCopNames, or by giving the -D/--display-cop-names # by overriding DisplayCopNames, or by giving the -D/--display-cop-names
# option. # option.
@ -29,12 +30,221 @@ AllCops:
Bundler/OrderedGems: Bundler/OrderedGems:
Enabled: false Enabled: false
# Style ####################################################################### # Layout ######################################################################
# Check indentation of private/protected visibility modifiers. # Check indentation of private/protected visibility modifiers.
Style/AccessModifierIndentation: Layout/AccessModifierIndentation:
Enabled: true 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_. # Check the naming of accessor methods for get_/set_.
Style/AccessorMethodName: Style/AccessorMethodName:
Enabled: false Enabled: false
@ -44,19 +254,6 @@ Style/Alias:
EnforcedStyle: prefer_alias_method EnforcedStyle: prefer_alias_method
Enabled: true 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) # Whether `and` and `or` are banned only in conditionals (conditionals)
# or completely (always). # or completely (always).
Style/AndOr: Style/AndOr:
@ -91,10 +288,6 @@ Style/BlockComments:
Style/BlockDelimiters: Style/BlockDelimiters:
Enabled: true 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 # This cop checks for braces around the last parameter in a method call
# if the last parameter is a hash. # if the last parameter is a hash.
Style/BracesAroundHashParameters: Style/BracesAroundHashParameters:
@ -104,10 +297,6 @@ Style/BracesAroundHashParameters:
Style/CaseEquality: Style/CaseEquality:
Enabled: false Enabled: false
# Indentation of when in a case/when/[else/]end.
Style/CaseIndentation:
Enabled: true
# Checks for uses of character literals. # Checks for uses of character literals.
Style/CharacterLiteral: Style/CharacterLiteral:
Enabled: true Enabled: true
@ -142,10 +331,6 @@ Style/ColonMethodCall:
Style/CommentAnnotation: Style/CommentAnnotation:
Enabled: false Enabled: false
# Indentation of comments.
Style/CommentIndentation:
Enabled: true
# Check for `if` and `case` statements where each branch is used for # Check for `if` and `case` statements where each branch is used for
# assignment to the same variable when using the return of the # assignment to the same variable when using the return of the
# condition can be used instead. # condition can be used instead.
@ -164,57 +349,16 @@ Style/DefWithParentheses:
Style/Documentation: Style/Documentation:
Enabled: false 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 # This cop checks for uses of double negation (!!) to convert something
# to a boolean value. As this is both cryptic and usually redundant, it # to a boolean value. As this is both cryptic and usually redundant, it
# should be avoided. # should be avoided.
Style/DoubleNegation: Style/DoubleNegation:
Enabled: false 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. # Avoid the use of END blocks.
Style/EndBlock: Style/EndBlock:
Enabled: true Enabled: true
# Use Unix-style line endings.
Style/EndOfLine:
Enabled: true
# Favor the use of Fixnum#even? && Fixnum#odd? # Favor the use of Fixnum#even? && Fixnum#odd?
Style/EvenOdd: Style/EvenOdd:
Enabled: true Enabled: true
@ -223,11 +367,6 @@ Style/EvenOdd:
Style/FileName: Style/FileName:
Enabled: true 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. # Checks for flip flops.
Style/FlipFlop: Style/FlipFlop:
Enabled: true Enabled: true
@ -236,6 +375,10 @@ Style/FlipFlop:
Style/For: Style/For:
Enabled: true 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 # Checks if there is a magic comment to enforce string literals
Style/FrozenStringLiteralComment: Style/FrozenStringLiteralComment:
Enabled: false Enabled: false
@ -261,31 +404,19 @@ Style/IdenticalConditionalBranches:
Style/IfWithSemicolon: Style/IfWithSemicolon:
Enabled: true 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. # Use Kernel#loop for infinite loops.
Style/InfiniteLoop: Style/InfiniteLoop:
Enabled: true 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.(...). # Use lambda.call(...) instead of lambda.(...).
Style/LambdaCall: Style/LambdaCall:
Enabled: true Enabled: true
# Comments should start with a space.
Style/LeadingCommentSpace:
Enabled: true
# Checks if the method definitions have or don't have parentheses. # Checks if the method definitions have or don't have parentheses.
Style/MethodDefParentheses: Style/MethodDefParentheses:
Enabled: true Enabled: true
@ -298,55 +429,23 @@ Style/MethodName:
Style/ModuleFunction: Style/ModuleFunction:
Enabled: false 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. # Avoid multi-line chains of blocks.
Style/MultilineBlockChain: Style/MultilineBlockChain:
Enabled: true 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. # Do not use then for multi-line if/unless.
Style/MultilineIfThen: Style/MultilineIfThen:
Enabled: true 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. # Avoid multi-line `? :` (the ternary operator), use if/unless instead.
Style/MultilineTernaryOperator: Style/MultilineTernaryOperator:
Enabled: true 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 # This cop checks whether some constant value isn't a
# mutable literal (e.g. array or hash). # mutable literal (e.g. array or hash).
Style/MutableConstant: Style/MutableConstant:
@ -421,68 +520,6 @@ Style/SignalException:
EnforcedStyle: only_raise EnforcedStyle: only_raise
Enabled: true 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. # Check for the usage of parentheses around stabby lambda arguments.
Style/StabbyLambdaParentheses: Style/StabbyLambdaParentheses:
EnforcedStyle: require_parentheses EnforcedStyle: require_parentheses
@ -498,13 +535,9 @@ Style/StringMethods:
intern: to_sym intern: to_sym
Enabled: true Enabled: true
# No hard tabs. # Use %i or %I for arrays of symbols.
Style/Tab: Style/SymbolArray:
Enabled: true Enabled: false
# Checks trailing blank lines and final newline.
Style/TrailingBlankLines:
Enabled: true
# This cop checks for trailing comma in array and hash literals. # This cop checks for trailing comma in array and hash literals.
Style/TrailingCommaInLiteral: Style/TrailingCommaInLiteral:
@ -553,6 +586,10 @@ Style/WhileUntilModifier:
Style/WordArray: Style/WordArray:
Enabled: true Enabled: true
# Do not use literals as the first operand of a comparison.
Style/YodaCondition:
Enabled: false
# Use `proc` instead of `Proc.new`. # Use `proc` instead of `Proc.new`.
Style/Proc: Style/Proc:
Enabled: true Enabled: true
@ -608,6 +645,11 @@ Metrics/PerceivedComplexity:
# Lint ######################################################################## # 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 # Checks for ambiguous operators in the first argument of a method invocation
# without parentheses. # without parentheses.
Lint/AmbiguousOperator: Lint/AmbiguousOperator:
@ -809,6 +851,10 @@ Lint/Void:
# Performance ################################################################# # Performance #################################################################
# Use `caller(n..n)` instead of `caller`.
Performance/Caller:
Enabled: false
# Use `casecmp` rather than `downcase ==`. # Use `casecmp` rather than `downcase ==`.
Performance/Casecmp: Performance/Casecmp:
Enabled: true Enabled: true
@ -883,6 +929,14 @@ Rails/ActionFilter:
Enabled: true Enabled: true
EnforcedStyle: action 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`, # Checks the correct usage of date aware methods, such as `Date.today`,
# `Date.current`, etc. # `Date.current`, etc.
Rails/Date: Rails/Date:
@ -939,10 +993,18 @@ Rails/OutputSafety:
Rails/PluralizationGrammar: Rails/PluralizationGrammar:
Enabled: true Enabled: true
# Enforce using `blank?` and `present?`.
Rails/Present:
Enabled: false
# Checks for `read_attribute(:attr)` and `write_attribute(:attr, val)`. # Checks for `read_attribute(:attr)` and `write_attribute(:attr, val)`.
Rails/ReadWriteAttribute: Rails/ReadWriteAttribute:
Enabled: false Enabled: false
# Do not assign relative date to constants.
Rails/RelativeDateConstant:
Enabled: false
# Checks the arguments of ActiveRecord scopes. # Checks the arguments of ActiveRecord scopes.
Rails/ScopeArgs: Rails/ScopeArgs:
Enabled: true Enabled: true

View File

@ -1,26 +1,89 @@
# This configuration was generated by # This configuration was generated by
# `rubocop --auto-gen-config --exclude-limit 0` # `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 # The point is for the user to remove these configuration records
# one by one as the offenses are removed from the code base. # one by one as the offenses are removed from the code base.
# Note that changes in the inspected code, or installation of new # Note that changes in the inspected code, or installation of new
# versions of RuboCop, may require this file to be generated again. # 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: RSpec/EmptyLineAfterFinalLet:
Enabled: false Enabled: false
# Offense count: 167 # Offense count: 181
RSpec/EmptyLineAfterSubject: RSpec/EmptyLineAfterSubject:
Enabled: false Enabled: false
# Offense count: 72 # Offense count: 78
# Configuration parameters: EnforcedStyle, SupportedStyles. # Configuration parameters: EnforcedStyle, SupportedStyles.
# SupportedStyles: implicit, each, example # SupportedStyles: implicit, each, example
RSpec/HookArgument: RSpec/HookArgument:
Enabled: false Enabled: false
# Offense count: 11 # Offense count: 9
# Configuration parameters: EnforcedStyle, SupportedStyles. # Configuration parameters: EnforcedStyle, SupportedStyles.
# SupportedStyles: it_behaves_like, it_should_behave_like # SupportedStyles: it_behaves_like, it_should_behave_like
RSpec/ItBehavesLike: RSpec/ItBehavesLike:
@ -30,19 +93,19 @@ RSpec/ItBehavesLike:
RSpec/IteratedExpectation: RSpec/IteratedExpectation:
Enabled: false Enabled: false
# Offense count: 3 # Offense count: 2
RSpec/OverwritingSetup: RSpec/OverwritingSetup:
Enabled: false Enabled: false
# Offense count: 34 # Offense count: 36
RSpec/RepeatedExample: RSpec/RepeatedExample:
Enabled: false Enabled: false
# Offense count: 43 # Offense count: 86
RSpec/ScatteredLet: RSpec/ScatteredLet:
Enabled: false Enabled: false
# Offense count: 32 # Offense count: 20
RSpec/ScatteredSetup: RSpec/ScatteredSetup:
Enabled: false Enabled: false
@ -50,7 +113,7 @@ RSpec/ScatteredSetup:
RSpec/SharedContext: RSpec/SharedContext:
Enabled: false Enabled: false
# Offense count: 150 # Offense count: 115
Rails/FilePath: Rails/FilePath:
Enabled: false Enabled: false
@ -60,90 +123,71 @@ Rails/FilePath:
Rails/ReversibleMigration: Rails/ReversibleMigration:
Enabled: false Enabled: false
# Offense count: 302 # Offense count: 336
# Configuration parameters: Blacklist. # Configuration parameters: Blacklist.
# Blacklist: decrement!, decrement_counter, increment!, increment_counter, toggle!, touch, update_all, update_attribute, update_column, update_columns, update_counters # Blacklist: decrement!, decrement_counter, increment!, increment_counter, toggle!, touch, update_all, update_attribute, update_column, update_columns, update_counters
Rails/SkipsModelValidations: Rails/SkipsModelValidations:
Enabled: false Enabled: false
# Offense count: 7 # Offense count: 11
# Cop supports --auto-correct. # Cop supports --auto-correct.
Security/YAMLLoad: Security/YAMLLoad:
Enabled: false Enabled: false
# Offense count: 59 # Offense count: 58
# Cop supports --auto-correct. # Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle, SupportedStyles. # Configuration parameters: EnforcedStyle, SupportedStyles.
# SupportedStyles: percent_q, bare_percent # SupportedStyles: percent_q, bare_percent
Style/BarePercentLiterals: Style/BarePercentLiterals:
Enabled: false Enabled: false
# Offense count: 5 # Offense count: 6
# Cop supports --auto-correct. # Cop supports --auto-correct.
Style/EachWithObject: Style/EachWithObject:
Enabled: false Enabled: false
# Offense count: 28 # Offense count: 31
# Cop supports --auto-correct. # Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle, SupportedStyles. # Configuration parameters: EnforcedStyle, SupportedStyles.
# SupportedStyles: empty, nil, both # SupportedStyles: empty, nil, both
Style/EmptyElse: Style/EmptyElse:
Enabled: false Enabled: false
# Offense count: 4 # Offense count: 9
# Cop supports --auto-correct. # Cop supports --auto-correct.
Style/EmptyLiteral: Style/EmptyLiteral:
Enabled: false Enabled: false
# Offense count: 59 # Offense count: 78
# Cop supports --auto-correct. # Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle, SupportedStyles. # Configuration parameters: EnforcedStyle, SupportedStyles.
# SupportedStyles: compact, expanded # SupportedStyles: compact, expanded
Style/EmptyMethod: Style/EmptyMethod:
Enabled: false Enabled: false
# Offense count: 214 # Offense count: 23
# Cop supports --auto-correct. # Cop supports --auto-correct.
# Configuration parameters: AllowForAlignment, ForceEqualSignAlignment.
Style/ExtraSpacing:
Enabled: false
# Offense count: 9
# Configuration parameters: EnforcedStyle, SupportedStyles. # Configuration parameters: EnforcedStyle, SupportedStyles.
# SupportedStyles: format, sprintf, percent # SupportedStyles: format, sprintf, percent
Style/FormatString: Style/FormatString:
Enabled: false Enabled: false
# Offense count: 285 # Offense count: 301
# Configuration parameters: MinBodyLength. # Configuration parameters: MinBodyLength.
Style/GuardClause: Style/GuardClause:
Enabled: false Enabled: false
# Offense count: 16 # Offense count: 18
Style/IfInsideElse: Style/IfInsideElse:
Enabled: false Enabled: false
# Offense count: 186 # Offense count: 182
# Cop supports --auto-correct. # Cop supports --auto-correct.
# Configuration parameters: MaxLineLength. # Configuration parameters: MaxLineLength.
Style/IfUnlessModifier: Style/IfUnlessModifier:
Enabled: false Enabled: false
# Offense count: 99 # Offense count: 52
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle, SupportedStyles, IndentationWidth.
# SupportedStyles: special_inside_parentheses, consistent, align_brackets
Style/IndentArray:
Enabled: false
# Offense count: 160
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle, SupportedStyles, IndentationWidth.
# SupportedStyles: special_inside_parentheses, consistent, align_braces
Style/IndentHash:
Enabled: false
# Offense count: 50
# Cop supports --auto-correct. # Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle, SupportedStyles. # Configuration parameters: EnforcedStyle, SupportedStyles.
# SupportedStyles: line_count_dependent, lambda, literal # SupportedStyles: line_count_dependent, lambda, literal
@ -155,63 +199,63 @@ Style/Lambda:
Style/LineEndConcatenation: Style/LineEndConcatenation:
Enabled: false Enabled: false
# Offense count: 34 # Offense count: 40
# Cop supports --auto-correct. # Cop supports --auto-correct.
Style/MethodCallWithoutArgsParentheses: Style/MethodCallWithoutArgsParentheses:
Enabled: false Enabled: false
# Offense count: 10 # Offense count: 13
Style/MethodMissing: Style/MethodMissing:
Enabled: false Enabled: false
# Offense count: 3 # Offense count: 6
# Cop supports --auto-correct. # Cop supports --auto-correct.
Style/MultilineIfModifier: Style/MultilineIfModifier:
Enabled: false Enabled: false
# Offense count: 24 # Offense count: 26
# Cop supports --auto-correct. # Cop supports --auto-correct.
Style/NestedParenthesizedCalls: Style/NestedParenthesizedCalls:
Enabled: false Enabled: false
# Offense count: 18 # Offense count: 20
# Cop supports --auto-correct. # Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle, MinBodyLength, SupportedStyles. # Configuration parameters: EnforcedStyle, MinBodyLength, SupportedStyles.
# SupportedStyles: skip_modifier_ifs, always # SupportedStyles: skip_modifier_ifs, always
Style/Next: Style/Next:
Enabled: false Enabled: false
# Offense count: 37 # Offense count: 45
# Cop supports --auto-correct. # Cop supports --auto-correct.
# Configuration parameters: EnforcedOctalStyle, SupportedOctalStyles. # Configuration parameters: EnforcedOctalStyle, SupportedOctalStyles.
# SupportedOctalStyles: zero_with_o, zero_only # SupportedOctalStyles: zero_with_o, zero_only
Style/NumericLiteralPrefix: Style/NumericLiteralPrefix:
Enabled: false Enabled: false
# Offense count: 88 # Offense count: 98
# Cop supports --auto-correct. # Cop supports --auto-correct.
# Configuration parameters: AutoCorrect, EnforcedStyle, SupportedStyles. # Configuration parameters: AutoCorrect, EnforcedStyle, SupportedStyles.
# SupportedStyles: predicate, comparison # SupportedStyles: predicate, comparison
Style/NumericPredicate: Style/NumericPredicate:
Enabled: false Enabled: false
# Offense count: 36 # Offense count: 42
# Cop supports --auto-correct. # Cop supports --auto-correct.
Style/ParallelAssignment: Style/ParallelAssignment:
Enabled: false Enabled: false
# Offense count: 570 # Offense count: 800
# Cop supports --auto-correct. # Cop supports --auto-correct.
# Configuration parameters: PreferredDelimiters. # Configuration parameters: PreferredDelimiters.
Style/PercentLiteralDelimiters: Style/PercentLiteralDelimiters:
Enabled: false Enabled: false
# Offense count: 14 # Offense count: 15
# Cop supports --auto-correct. # Cop supports --auto-correct.
Style/PerlBackrefs: Style/PerlBackrefs:
Enabled: false Enabled: false
# Offense count: 83 # Offense count: 105
# Configuration parameters: NamePrefix, NamePrefixBlacklist, NameWhitelist. # Configuration parameters: NamePrefix, NamePrefixBlacklist, NameWhitelist.
# NamePrefix: is_, has_, have_ # NamePrefix: is_, has_, have_
# NamePrefixBlacklist: is_, has_, have_ # NamePrefixBlacklist: is_, has_, have_
@ -219,47 +263,47 @@ Style/PerlBackrefs:
Style/PredicateName: Style/PredicateName:
Enabled: false Enabled: false
# Offense count: 65 # Offense count: 58
# Cop supports --auto-correct. # Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle, SupportedStyles. # Configuration parameters: EnforcedStyle, SupportedStyles.
# SupportedStyles: compact, exploded # SupportedStyles: compact, exploded
Style/RaiseArgs: Style/RaiseArgs:
Enabled: false Enabled: false
# Offense count: 5 # Offense count: 6
# Cop supports --auto-correct. # Cop supports --auto-correct.
Style/RedundantBegin: Style/RedundantBegin:
Enabled: false Enabled: false
# Offense count: 32 # Offense count: 37
# Cop supports --auto-correct. # Cop supports --auto-correct.
Style/RedundantFreeze: Style/RedundantFreeze:
Enabled: false Enabled: false
# Offense count: 15 # Offense count: 14
# Cop supports --auto-correct. # Cop supports --auto-correct.
# Configuration parameters: AllowMultipleReturnValues. # Configuration parameters: AllowMultipleReturnValues.
Style/RedundantReturn: Style/RedundantReturn:
Enabled: false Enabled: false
# Offense count: 382 # Offense count: 406
# Cop supports --auto-correct. # Cop supports --auto-correct.
Style/RedundantSelf: Style/RedundantSelf:
Enabled: false Enabled: false
# Offense count: 111 # Offense count: 115
# Cop supports --auto-correct. # Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle, SupportedStyles, AllowInnerSlashes. # Configuration parameters: EnforcedStyle, SupportedStyles, AllowInnerSlashes.
# SupportedStyles: slashes, percent_r, mixed # SupportedStyles: slashes, percent_r, mixed
Style/RegexpLiteral: Style/RegexpLiteral:
Enabled: false Enabled: false
# Offense count: 24 # Offense count: 29
# Cop supports --auto-correct. # Cop supports --auto-correct.
Style/RescueModifier: Style/RescueModifier:
Enabled: false Enabled: false
# Offense count: 7 # Offense count: 8
# Cop supports --auto-correct. # Cop supports --auto-correct.
Style/SelfAssignment: Style/SelfAssignment:
Enabled: false Enabled: false
@ -270,101 +314,58 @@ Style/SelfAssignment:
Style/SingleLineMethods: Style/SingleLineMethods:
Enabled: false Enabled: false
# Offense count: 168 # Offense count: 64
# 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
# Cop supports --auto-correct. # Cop supports --auto-correct.
# Configuration parameters: SupportedStyles. # Configuration parameters: SupportedStyles.
# SupportedStyles: use_perl_names, use_english_names # SupportedStyles: use_perl_names, use_english_names
Style/SpecialGlobalVars: Style/SpecialGlobalVars:
EnforcedStyle: use_perl_names EnforcedStyle: use_perl_names
# Offense count: 42 # Offense count: 44
# Cop supports --auto-correct. # Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle, SupportedStyles. # Configuration parameters: EnforcedStyle, SupportedStyles.
# SupportedStyles: single_quotes, double_quotes # SupportedStyles: single_quotes, double_quotes
Style/StringLiteralsInInterpolation: Style/StringLiteralsInInterpolation:
Enabled: false Enabled: false
# Offense count: 64 # Offense count: 84
# Cop supports --auto-correct. # Cop supports --auto-correct.
# Configuration parameters: IgnoredMethods. # Configuration parameters: IgnoredMethods.
# IgnoredMethods: respond_to, define_method # IgnoredMethods: respond_to, define_method
Style/SymbolProc: Style/SymbolProc:
Enabled: false Enabled: false
# Offense count: 6 # Offense count: 8
# Cop supports --auto-correct. # Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle, SupportedStyles, AllowSafeAssignment. # Configuration parameters: EnforcedStyle, SupportedStyles, AllowSafeAssignment.
# SupportedStyles: require_parentheses, require_no_parentheses, require_parentheses_when_complex # SupportedStyles: require_parentheses, require_no_parentheses, require_parentheses_when_complex
Style/TernaryParentheses: Style/TernaryParentheses:
Enabled: false Enabled: false
# Offense count: 18 # Offense count: 17
# Cop supports --auto-correct. # Cop supports --auto-correct.
# Configuration parameters: AllowNamedUnderscoreVariables. # Configuration parameters: AllowNamedUnderscoreVariables.
Style/TrailingUnderscoreVariable: Style/TrailingUnderscoreVariable:
Enabled: false Enabled: false
# Offense count: 78 # Offense count: 4
# Cop supports --auto-correct.
Style/TrailingWhitespace:
Enabled: false
# Offense count: 3
# Cop supports --auto-correct. # Cop supports --auto-correct.
# Configuration parameters: ExactNameMatch, AllowPredicates, AllowDSLWriters, IgnoreClassMethods, Whitelist. # 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 # 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: Style/TrivialAccessors:
Enabled: false Enabled: false
# Offense count: 6 # Offense count: 5
# Cop supports --auto-correct. # Cop supports --auto-correct.
Style/UnlessElse: Style/UnlessElse:
Enabled: false Enabled: false
# Offense count: 24 # Offense count: 28
# Cop supports --auto-correct. # Cop supports --auto-correct.
Style/UnneededInterpolation: Style/UnneededInterpolation:
Enabled: false Enabled: false
# Offense count: 8 # Offense count: 11
# Cop supports --auto-correct. # Cop supports --auto-correct.
Style/ZeroLengthPredicate: Style/ZeroLengthPredicate:
Enabled: false Enabled: false

View File

@ -2,6 +2,16 @@
documentation](doc/development/changelog.md) for instructions on adding your own documentation](doc/development/changelog.md) for instructions on adding your own
entry. 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) ## 9.4.2 (2017-07-28)
- Fix job merge request link to a forked source project. !12965 - 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-rspec', '~> 1.0.4'
gem 'spring-commands-spinach', '~> 1.1.0' gem 'spring-commands-spinach', '~> 1.1.0'
gem 'rubocop', '~> 0.47.1', require: false gem 'rubocop', '~> 0.49.1', require: false
gem 'rubocop-rspec', '~> 1.15.0', require: false gem 'rubocop-rspec', '~> 1.15.1', require: false
gem 'scss_lint', '~> 0.54.0', require: false gem 'scss_lint', '~> 0.54.0', require: false
gem 'haml_lint', '~> 0.21.0', require: false gem 'haml_lint', '~> 0.21.0', require: false
gem 'simplecov', '~> 0.14.0', require: false gem 'simplecov', '~> 0.14.0', require: false

View File

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

View File

@ -128,7 +128,7 @@ information, see
### After the 7th ### 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. 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. 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. 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 Merge requests without a milestone and this label will
not be merged into any stable branches. 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 ## Release retrospective and kickoff
### Retrospective ### Retrospective

View File

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

View File

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

View File

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

View File

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

View File

@ -1,6 +1,4 @@
import Chart from 'vendor/Chart'; import Chart from 'vendor/Chart';
import ContributorsStatGraph from './stat_graph_contributors';
// export to global scope // export to global scope
window.Chart = Chart; 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 { class RefSelectDropdown {
constructor($dropdownButton, availableRefs) { constructor($dropdownButton, availableRefs) {
const availableRefsValue = availableRefs || JSON.parse(document.getElementById('availableRefs').innerHTML);
$dropdownButton.glDropdown({ $dropdownButton.glDropdown({
data: availableRefs, data: availableRefsValue,
filterable: true, filterable: true,
filterByText: true, filterByText: true,
remote: false, 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; overflow: hidden;
display: flex; display: flex;
a {
display: flex;
}
.avatar { .avatar {
border-radius: 0; border-radius: 0;
border: none; border: none;

View File

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

View File

@ -313,6 +313,29 @@ header {
.impersonation i { .impersonation i {
color: $red-500; 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 { .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 { .page-with-sidebar {
-webkit-overflow-scrolling: auto; -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 { .scrolling-tabs-container {
position: relative; 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 { .nav-block {
&.activities { &.activities {
border-bottom: 1px solid $border-color; 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 { @mixin maintain-sidebar-dimensions {
display: block; display: block;
width: $gutter-width; width: $gutter-width;

View File

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

View File

@ -309,6 +309,25 @@ header.navbar-gitlab-new {
outline: 0; 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 { .breadcrumbs-container {
@ -325,6 +344,7 @@ header.navbar-gitlab-new {
.breadcrumbs-links { .breadcrumbs-links {
flex: 1; flex: 1;
min-width: 0;
align-self: center; align-self: center;
color: $gl-text-color-quaternary; color: $gl-text-color-quaternary;
@ -343,7 +363,7 @@ header.navbar-gitlab-new {
} }
.title { .title {
white-space: nowrap; display: inline-block;
> a { > a {
&:last-of-type:not(:first-child) { &:last-of-type:not(:first-child) {

View File

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

View File

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

View File

@ -110,6 +110,10 @@
.js-ca-dropdown { .js-ca-dropdown {
top: $gl-padding-top; top: $gl-padding-top;
.dropdown-menu-align-right {
margin-top: 2px;
}
} }
.content-list { .content-list {
@ -442,6 +446,24 @@
margin-bottom: 20px; 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 { .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 { .detail-page-description {
padding: 16px 0; 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 { .merge-request-tabs {
display: flex; display: flex;
margin-bottom: 0; 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 { .blob-commit-info {

View File

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

View File

@ -43,23 +43,7 @@ class Projects::GraphsController < Projects::ApplicationController
end end
def get_languages def get_languages
@languages = Linguist::Repository.new(@repository.rugged, @repository.rugged.head.target_id).languages @languages = @project.repository.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
end end
def fetch_graph def fetch_graph

View File

@ -264,7 +264,11 @@ module ApplicationHelper
end end
def page_class 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 end
# Returns active css class when condition returns true # Returns active css class when condition returns true

View File

@ -48,8 +48,12 @@ module GitlabRoutingHelper
end end
def milestone_path(entity, *args) def milestone_path(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) project_milestone_path(entity.project, entity, *args)
end end
end
def issue_url(entity, *args) def issue_url(entity, *args)
project_issue_url(entity.project, entity, *args) project_issue_url(entity.project, entity, *args)
@ -63,6 +67,14 @@ module GitlabRoutingHelper
project_pipeline_url(pipeline.project, pipeline.id, *args) project_pipeline_url(pipeline.project, pipeline.id, *args)
end 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) def pipeline_job_url(pipeline, build, *args)
project_job_url(pipeline.project, build.id, *args) project_job_url(pipeline.project, build.id, *args)
end end

View File

@ -40,7 +40,7 @@ module MergeRequestsHelper
def merge_path_description(merge_request, separator) def merge_path_description(merge_request, separator)
if merge_request.for_fork? 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 else
"Branches: #{@merge_request.source_branch} #{separator} #{@merge_request.target_branch}" "Branches: #{@merge_request.source_branch} #{separator} #{@merge_request.target_branch}"
end end

View File

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

View File

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

View File

@ -34,6 +34,8 @@ module WebpackHelper
end end
def webpack_public_path 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
end end

View File

@ -165,7 +165,7 @@ class Notify < BaseMailer
headers['X-GitLab-Project'] = @project.name headers['X-GitLab-Project'] = @project.name
headers['X-GitLab-Project-Id'] = @project.id 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 end
def add_unsubscription_headers_and_links def add_unsubscription_headers_and_links

View File

@ -317,7 +317,7 @@ module Ci
return @config_processor if defined?(@config_processor) return @config_processor if defined?(@config_processor)
@config_processor ||= begin @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 rescue Ci::GitlabCiYamlProcessor::ValidationError, Psych::SyntaxError => e
self.yaml_errors = e.message self.yaml_errors = e.message
nil 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 def target_project_path
if target_project if target_project
target_project.path_with_namespace target_project.full_path
else else
"(removed)" "(removed)"
end end
@ -638,7 +638,7 @@ class MergeRequest < ActiveRecord::Base
def source_project_path def source_project_path
if source_project if source_project
source_project.path_with_namespace source_project.full_path
else else
"(removed)" "(removed)"
end end

View File

@ -8,6 +8,7 @@ class Namespace < ActiveRecord::Base
include Gitlab::VisibilityLevel include Gitlab::VisibilityLevel
include Routable include Routable
include AfterCommitQueue include AfterCommitQueue
include Storage::LegacyNamespace
# Prevent users from creating unreasonably deep level of nesting. # Prevent users from creating unreasonably deep level of nesting.
# The number 20 was taken based on maximum nesting level of # 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 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') } 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 } before_destroy(prepend: true) { prepare_for_destroy }
after_destroy :rm_dir after_destroy :rm_dir
@ -118,43 +120,6 @@ class Namespace < ActiveRecord::Base
owner_name owner_name
end 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? def any_project_has_container_registry_tags?
all_projects.any?(&:has_container_registry_tags?) all_projects.any?(&:has_container_registry_tags?)
end end
@ -206,14 +171,6 @@ class Namespace < ActiveRecord::Base
parent_id_changed? parent_id_changed?
end 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 # Includes projects from this namespace and projects from all subgroups
# that belongs to this namespace # that belongs to this namespace
def all_projects def all_projects
@ -232,37 +189,6 @@ class Namespace < ActiveRecord::Base
private 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 def refresh_access_of_projects_invited_groups
Group Group
.joins(project_group_links: :project) .joins(project_group_links: :project)
@ -270,22 +196,6 @@ class Namespace < ActiveRecord::Base
.find_each(&:refresh_members_authorized_projects) .find_each(&:refresh_members_authorized_projects)
end 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 def nesting_level_allowed
if ancestors.count > Group::NUMBER_OF_ANCESTORS_ALLOWED if ancestors.count > Group::NUMBER_OF_ANCESTORS_ALLOWED
errors.add(:parent_id, "has too deep level of nesting") errors.add(:parent_id, "has too deep level of nesting")

View File

@ -1,4 +1,8 @@
class NotificationSetting < ActiveRecord::Base class NotificationSetting < ActiveRecord::Base
include IgnorableColumn
ignore_column :events
enum level: { global: 3, watch: 2, mention: 4, participating: 1, disabled: 0, custom: 5 } enum level: { global: 3, watch: 2, mention: 4, participating: 1, disabled: 0, custom: 5 }
default_value_for :level, NotificationSetting.levels[:global] default_value_for :level, NotificationSetting.levels[:global]
@ -41,9 +45,6 @@ class NotificationSetting < ActiveRecord::Base
:success_pipeline :success_pipeline
].freeze ].freeze
store :events, coder: JSON
before_save :convert_events
def self.find_or_create_for(source) def self.find_or_create_for(source)
setting = find_or_initialize_by(source: source) setting = find_or_initialize_by(source: source)
@ -54,42 +55,17 @@ class NotificationSetting < ActiveRecord::Base
setting setting
end 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 # Allow people to receive failed pipeline notifications if they already have
# custom notifications enabled, as these are more like mentions than the other # custom notifications enabled, as these are more like mentions than the other
# custom settings. # custom settings.
def failed_pipeline def failed_pipeline
bool = super bool = super
bool = events[:failed_pipeline] if bool.nil?
bool.nil? || bool bool.nil? || bool
end end
alias_method :failed_pipeline?, :failed_pipeline alias_method :failed_pipeline?, :failed_pipeline
def event_enabled?(event) def event_enabled?(event)
respond_to?(event) && public_send(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)
end end
end end

View File

@ -17,6 +17,7 @@ class Project < ActiveRecord::Base
include ProjectFeaturesCompatibility include ProjectFeaturesCompatibility
include SelectForProjectAuthorization include SelectForProjectAuthorization
include Routable include Routable
include Storage::LegacyProject
extend Gitlab::ConfigHelper extend Gitlab::ConfigHelper
@ -43,9 +44,8 @@ class Project < ActiveRecord::Base
default_value_for :snippets_enabled, gitlab_config_features.snippets default_value_for :snippets_enabled, gitlab_config_features.snippets
default_value_for :only_allow_merge_if_all_discussions_are_resolved, false 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_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? after_save :update_project_statistics, if: :namespace_id_changed?
# set last_activity_at to the same as created_at # set last_activity_at to the same as created_at
@ -67,6 +67,10 @@ class Project < ActiveRecord::Base
after_validation :check_pending_delete after_validation :check_pending_delete
# Legacy Storage specific hooks
after_save :ensure_storage_path_exist, if: :namespace_id_changed?
acts_as_taggable acts_as_taggable
attr_accessor :new_default_branch attr_accessor :new_default_branch
@ -375,7 +379,7 @@ class Project < ActiveRecord::Base
begin begin
Projects::HousekeepingService.new(project).execute Projects::HousekeepingService.new(project).execute
rescue Projects::HousekeepingService::LeaseTaken => e 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 end
end end
@ -476,12 +480,12 @@ class Project < ActiveRecord::Base
end end
def repository def repository
@repository ||= Repository.new(path_with_namespace, self) @repository ||= Repository.new(full_path, self, disk_path: disk_path)
end end
def container_registry_url def container_registry_url
if Gitlab.config.registry.enabled if Gitlab.config.registry.enabled
"#{Gitlab.config.registry.host_port}/#{path_with_namespace.downcase}" "#{Gitlab.config.registry.host_port}/#{full_path.downcase}"
end end
end end
@ -520,16 +524,16 @@ class Project < ActiveRecord::Base
job_id = job_id =
if forked? if forked?
RepositoryForkWorker.perform_async(id, forked_from_project.repository_storage_path, 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) self.namespace.full_path)
else else
RepositoryImportWorker.perform_async(self.id) RepositoryImportWorker.perform_async(self.id)
end end
if job_id 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 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
end end
@ -690,7 +694,7 @@ class Project < ActiveRecord::Base
# `from` argument can be a Namespace or Project. # `from` argument can be a Namespace or Project.
def to_reference(from = nil, full: false) def to_reference(from = nil, full: false)
if full || cross_namespace_reference?(from) if full || cross_namespace_reference?(from)
path_with_namespace full_path
elsif cross_project_reference?(from) elsif cross_project_reference?(from)
path path
end end
@ -714,7 +718,7 @@ class Project < ActiveRecord::Base
author.ensure_incoming_email_token! author.ensure_incoming_email_token!
Gitlab::IncomingEmail.reply_address( Gitlab::IncomingEmail.reply_address(
"#{path_with_namespace}+#{author.incoming_email_token}") "#{full_path}+#{author.incoming_email_token}")
end end
def build_commit_note(commit) def build_commit_note(commit)
@ -941,7 +945,7 @@ class Project < ActiveRecord::Base
end end
def url_to_repo def url_to_repo
gitlab_shell.url_to_repo(path_with_namespace) gitlab_shell.url_to_repo(full_path)
end end
def repo_exists? def repo_exists?
@ -974,56 +978,6 @@ class Project < ActiveRecord::Base
!group !group
end 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. # Expires various caches before a project is renamed.
def expire_caches_before_rename(old_path) def expire_caches_before_rename(old_path)
repo = Repository.new(old_path, self) repo = Repository.new(old_path, self)
@ -1048,7 +1002,7 @@ class Project < ActiveRecord::Base
git_http_url: http_url_to_repo, git_http_url: http_url_to_repo,
namespace: namespace.name, namespace: namespace.name,
visibility_level: visibility_level, visibility_level: visibility_level,
path_with_namespace: path_with_namespace, path_with_namespace: full_path,
default_branch: default_branch, default_branch: default_branch,
ci_config_path: ci_config_path ci_config_path: ci_config_path
} }
@ -1109,19 +1063,6 @@ class Project < ActiveRecord::Base
merge_requests.where(source_project_id: self.id) merge_requests.where(source_project_id: self.id)
end 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 def ensure_repository
create_repository(force: true) unless repository_exists? create_repository(force: true) unless repository_exists?
end end
@ -1257,7 +1198,7 @@ class Project < ActiveRecord::Base
end end
def pages_path def pages_path
File.join(Settings.pages.path, path_with_namespace) File.join(Settings.pages.path, disk_path)
end end
def public_pages_path def public_pages_path
@ -1265,9 +1206,21 @@ class Project < ActiveRecord::Base
end end
def remove_private_deploy_keys 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 end
# TODO: what to do here when not using Legacy Storage? Do we still need to rename and delay removal?
def remove_pages def remove_pages
::Projects::UpdatePagesConfigurationService.new(self).execute ::Projects::UpdatePagesConfigurationService.new(self).execute
@ -1315,7 +1268,7 @@ class Project < ActiveRecord::Base
end end
def export_path def export_path
File.join(Gitlab::ImportExport.storage_path, path_with_namespace) File.join(Gitlab::ImportExport.storage_path, disk_path)
end end
def export_project_path def export_project_path
@ -1327,16 +1280,12 @@ class Project < ActiveRecord::Base
status.zero? status.zero?
end end
def ensure_dir_exist
gitlab_shell.add_namespace(repository_storage_path, namespace.full_path)
end
def predefined_variables def predefined_variables
[ [
{ key: 'CI_PROJECT_ID', value: id.to_s, public: true }, { key: 'CI_PROJECT_ID', value: id.to_s, public: true },
{ key: 'CI_PROJECT_NAME', value: path, public: true }, { key: 'CI_PROJECT_NAME', value: path, public: true },
{ key: 'CI_PROJECT_PATH', value: path_with_namespace, public: true }, { key: 'CI_PROJECT_PATH', value: full_path, public: true },
{ key: 'CI_PROJECT_PATH_SLUG', value: path_with_namespace.parameterize, 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_NAMESPACE', value: namespace.full_path, public: true },
{ key: 'CI_PROJECT_URL', value: web_url, 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 :name_with_namespace, :full_name
alias_method :human_name, :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 alias_method :path_with_namespace, :full_path
private private
@ -1495,7 +1445,7 @@ class Project < ActiveRecord::Base
def pending_delete_twin def pending_delete_twin
return false unless path return false unless path
Project.pending_delete.find_by_full_path(path_with_namespace) Project.pending_delete.find_by_full_path(full_path)
end end
## ##

View File

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

View File

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

View File

@ -1,5 +1,6 @@
class ProjectWiki class ProjectWiki
include Gitlab::ShellAdapter include Gitlab::ShellAdapter
include Storage::LegacyProjectWiki
MARKUPS = { MARKUPS = {
'Markdown' => :markdown, 'Markdown' => :markdown,
@ -26,16 +27,19 @@ class ProjectWiki
@project.path + '.wiki' @project.path + '.wiki'
end end
def path_with_namespace def full_path
@project.path_with_namespace + ".wiki" @project.full_path + '.wiki'
end 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 def web_url
Gitlab::Routing.url_helpers.project_wiki_url(@project, :home) Gitlab::Routing.url_helpers.project_wiki_url(@project, :home)
end end
def url_to_repo def url_to_repo
gitlab_shell.url_to_repo(path_with_namespace) gitlab_shell.url_to_repo(full_path)
end end
def ssh_url_to_repo def ssh_url_to_repo
@ -43,11 +47,11 @@ class ProjectWiki
end end
def http_url_to_repo def http_url_to_repo
"#{Gitlab.config.gitlab.url}/#{path_with_namespace}.git" "#{Gitlab.config.gitlab.url}/#{full_path}.git"
end end
def wiki_base_path 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 end
# Returns the Gollum::Wiki object. # Returns the Gollum::Wiki object.
@ -134,7 +138,7 @@ class ProjectWiki
end end
def repository def repository
@repository ||= Repository.new(path_with_namespace, @project) @repository ||= Repository.new(full_path, @project, disk_path: disk_path)
end end
def default_branch def default_branch
@ -142,7 +146,7 @@ class ProjectWiki
end end
def create_repo! def create_repo!
if init_repo(path_with_namespace) if init_repo(disk_path)
wiki = Gollum::Wiki.new(path_to_repo) wiki = Gollum::Wiki.new(path_to_repo)
else else
raise CouldNotCreateWikiError raise CouldNotCreateWikiError
@ -162,15 +166,15 @@ class ProjectWiki
web_url: web_url, web_url: web_url,
git_ssh_url: ssh_url_to_repo, git_ssh_url: ssh_url_to_repo,
git_http_url: http_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 default_branch: default_branch
} }
end end
private private
def init_repo(path_with_namespace) def init_repo(disk_path)
gitlab_shell.add_repository(project.repository_storage_path, path_with_namespace) gitlab_shell.add_repository(project.repository_storage_path, disk_path)
end end
def commit_details(action, message = nil, title = nil) def commit_details(action, message = nil, title = nil)
@ -184,7 +188,7 @@ class ProjectWiki
end end
def path_to_repo 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 end
def update_project_activity def update_project_activity

View File

@ -4,7 +4,7 @@ class Repository
include Gitlab::ShellAdapter include Gitlab::ShellAdapter
include RepositoryMirroring include RepositoryMirroring
attr_accessor :path_with_namespace, :project attr_accessor :full_path, :disk_path, :project
delegate :ref_name_for_sha, to: :raw_repository delegate :ref_name_for_sha, to: :raw_repository
@ -52,13 +52,14 @@ class Repository
end end
end end
def initialize(path_with_namespace, project) def initialize(full_path, project, disk_path: nil)
@path_with_namespace = path_with_namespace @full_path = full_path
@disk_path = disk_path || full_path
@project = project @project = project
end end
def raw_repository def raw_repository
return nil unless path_with_namespace return nil unless full_path
@raw_repository ||= initialize_raw_repository @raw_repository ||= initialize_raw_repository
end end
@ -66,7 +67,7 @@ class Repository
# Return absolute path to repository # Return absolute path to repository
def path_to_repo def path_to_repo
@path_to_repo ||= File.expand_path( @path_to_repo ||= File.expand_path(
File.join(repository_storage_path, path_with_namespace + ".git") File.join(repository_storage_path, disk_path + '.git')
) )
end end
@ -469,7 +470,7 @@ class Repository
# Gitaly migration: https://gitlab.com/gitlab-org/gitaly/issues/314 # Gitaly migration: https://gitlab.com/gitlab-org/gitaly/issues/314
def exists? def exists?
return false unless path_with_namespace return false unless full_path
Gitlab::GitalyClient.migrate(:repository_exists) do |enabled| Gitlab::GitalyClient.migrate(:repository_exists) do |enabled|
if enabled if enabled
@ -1005,7 +1006,7 @@ class Repository
end end
def fetch_remote(remote, forced: false, no_tags: false) 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 end
def fetch_ref(source_path, source_ref, target_ref) def fetch_ref(source_path, source_ref, target_ref)
@ -1104,7 +1105,8 @@ class Repository
end end
def cache 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 end
def tags_sorted_by_committed_date def tags_sorted_by_committed_date
@ -1127,7 +1129,7 @@ class Repository
end end
def repository_event(event, tags = {}) 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 end
def create_commit(params = {}) def create_commit(params = {})
@ -1141,6 +1143,6 @@ class Repository
end end
def initialize_raw_repository 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
end end

View File

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

View File

@ -60,7 +60,7 @@ class GitOperationService
start_branch_name = nil if start_repository.empty_repo? start_branch_name = nil if start_repository.empty_repo?
if start_branch_name && !start_repository.branch_exists?(start_branch_name) 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 end
update_branch_with_hooks(branch_name) do update_branch_with_hooks(branch_name) do

View File

@ -9,7 +9,7 @@ module Projects
def async_execute def async_execute
project.update_attribute(:pending_delete, true) project.update_attribute(:pending_delete, true)
job_id = ProjectDestroyWorker.perform_async(project.id, current_user.id, params) 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 end
def execute def execute
@ -40,7 +40,7 @@ module Projects
private private
def repo_path def repo_path
project.path_with_namespace project.disk_path
end end
def wiki_path def wiki_path
@ -127,7 +127,7 @@ module Projects
def flush_caches(project) def flush_caches(project)
project.repository.before_delete 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 end
end end

View File

@ -2,7 +2,7 @@ module Projects
module ImportExport module ImportExport
class ExportService < BaseService class ExportService < BaseService
def execute(_options = {}) 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 save_all
end end

View File

@ -11,7 +11,7 @@ module Projects
success success
rescue => e 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 end
private private
@ -51,7 +51,7 @@ module Projects
end end
def clone_repository 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 end
def fetch_repository def fetch_repository

View File

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

View File

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

View File

@ -79,7 +79,7 @@ class SystemHooksService
{ {
name: model.name, name: model.name,
path: model.path, path: model.path,
path_with_namespace: model.path_with_namespace, path_with_namespace: model.full_path,
project_id: model.id, project_id: model.id,
owner_name: owner.name, owner_name: owner.name,
owner_email: owner.respond_to?(:email) ? owner.email : "", owner_email: owner.respond_to?(:email) ? owner.email : "",
@ -93,7 +93,7 @@ class SystemHooksService
{ {
project_name: project.name, project_name: project.name,
project_path: project.path, project_path: project.path,
project_path_with_namespace: project.path_with_namespace, project_path_with_namespace: project.full_path,
project_id: project.id, project_id: project.id,
user_username: model.user.username, user_username: model.user.username,
user_name: model.user.name, user_name: model.user.name,

View File

@ -30,7 +30,7 @@ class FileUploader < GitlabUploader
# #
# Returns a String without a trailing slash # Returns a String without a trailing slash
def self.dynamic_path_segment(model) 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 end
attr_accessor :model attr_accessor :model

View File

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

View File

@ -1,5 +1,7 @@
- page_title "UI Development Kit", "Help" - 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." - 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 .gitlab-ui-dev-kit
%h1 GitLab UI development kit %h1 GitLab UI development kit
@ -407,29 +409,6 @@
.dropdown-content .dropdown-content
.dropdown-loading .dropdown-loading
= icon('spinner spin') = 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 .example
%div %div

View File

@ -25,7 +25,7 @@
%td %td
= provider_project_link(provider, project.import_source) = provider_project_link(provider, project.import_source)
%td %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 %td.job-status
- if project.import_status == 'finished' - if project.import_status == 'finished'
%span %span

View File

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

View File

@ -35,7 +35,7 @@
%td %td
= link_to project.import_source, "https://bitbucket.org/#{project.import_source}", target: '_blank', rel: 'noopener noreferrer' = link_to project.import_source, "https://bitbucket.org/#{project.import_source}", target: '_blank', rel: 'noopener noreferrer'
%td %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 %td.job-status
- if project.import_status == 'finished' - if project.import_status == 'finished'
%span %span

View File

@ -33,7 +33,7 @@
%td %td
= project.import_source = project.import_source
%td %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 %td.job-status
- if project.import_status == 'finished' - if project.import_status == 'finished'
%span %span

View File

@ -28,7 +28,7 @@
%td %td
= link_to project.import_source, "https://gitlab.com/#{project.import_source}", target: "_blank" = link_to project.import_source, "https://gitlab.com/#{project.import_source}", target: "_blank"
%td %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 %td.job-status
- if project.import_status == 'finished' - if project.import_status == 'finished'
%span %span

View File

@ -38,7 +38,7 @@
%td %td
= link_to project.import_source, "https://code.google.com/p/#{project.import_source}", target: "_blank", rel: 'noopener noreferrer' = link_to project.import_source, "https://code.google.com/p/#{project.import_source}", target: "_blank", rel: 'noopener noreferrer'
%td %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 %td.job-status
- if project.import_status == 'finished' - if project.import_status == 'finished'
%span %span

View File

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

View File

@ -2,6 +2,7 @@
- noteable_type = @noteable.class if @noteable.present? - noteable_type = @noteable.class if @noteable.present?
- if project - if project
-# haml-lint:disable InlineJavaScript
:javascript :javascript
gl.GfmAutoComplete = gl.GfmAutoComplete || {}; gl.GfmAutoComplete = gl.GfmAutoComplete || {};
gl.GfmAutoComplete.dataSources = { 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 show_new_nav?
- if defined?(nav) && nav - if defined?(nav) && nav
= render "layouts/nav/#{nav}" = render "layouts/nav/#{nav}"
@ -9,7 +9,7 @@
= render "layouts/nav/#{nav}" = render "layouts/nav/#{nav}"
- if content_for?(:sub_nav) - if content_for?(:sub_nav)
= yield :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? - if show_new_nav?
.mobile-overlay .mobile-overlay
.alert-wrapper .alert-wrapper

View File

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

View File

@ -1,8 +1,9 @@
!!! 5 !!! 5
%html{ lang: I18n.locale, class: "#{page_class}" } %html{ lang: I18n.locale, class: page_class }
= render "layouts/head" = 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 } } %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 "layouts/init_auto_complete" if @gfm_form
= render 'peek/bar'
- if show_new_nav? - if show_new_nav?
= render "layouts/header/new" = render "layouts/header/new"
- else - else
@ -10,5 +11,3 @@
= render 'layouts/page', sidebar: sidebar, nav: nav = render 'layouts/page', sidebar: sidebar, nav: nav
= yield :scripts_body = yield :scripts_body
= render 'peek/bar'

View File

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

View File

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

View File

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

View File

@ -2,6 +2,7 @@
- content_for :page_specific_javascripts do - content_for :page_specific_javascripts do
- if @snippet && current_user - if @snippet && current_user
-# haml-lint:disable InlineJavaScript
:javascript :javascript
window.uploads_path = "#{upload_path('personal_snippet', id: @snippet.id)}"; 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" - page_title "Personal Access Tokens"
- @content_class = "limit-container-width" unless fluid_layout - @content_class = "limit-container-width" unless fluid_layout
= render 'profiles/head' = render 'profiles/head'
.row.prepend-top-default .row.prepend-top-default
@ -19,7 +20,7 @@
%h5.prepend-top-0 %h5.prepend-top-0
Your New Personal Access Token Your New Personal Access Token
.form-group .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") = 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. %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_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 = 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,11 +7,13 @@
= render 'profiles/head' = 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('u2f')
= page_specific_javascript_bundle_tag('two_factor_auth')
.row.prepend-top-default .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 .col-lg-4
%h4.prepend-top-0 %h4.prepend-top-0
Register Two-Factor Authentication App Register Two-Factor Authentication App
@ -51,10 +53,9 @@
.prepend-top-default .prepend-top-default
= submit_tag 'Register with two-factor app', class: 'btn btn-success' = submit_tag 'Register with two-factor app', class: 'btn btn-success'
%hr %hr
.row.prepend-top-default
.row.prepend-top-default
.col-lg-4 .col-lg-4
%h4.prepend-top-0 %h4.prepend-top-0
Register Universal Two-Factor (U2F) Device Register Universal Two-Factor (U2F) Device
@ -95,9 +96,3 @@
- else - else
.settings-message.text-center .settings-message.text-center
You don't have any U2F devices registered yet. 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);

View File

@ -8,9 +8,3 @@
.content_list.project-activity{ :"data-href" => activity_project_path(@project) } .content_list.project-activity{ :"data-href" => activity_project_path(@project) }
= spinner = 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) - unless can?(current_user, :push_code, @project)
.inline.prepend-left-10 .inline.prepend-left-10
= commit_in_fork_help = commit_in_fork_help
:javascript
new NewCommitForm($('.js-create-dir-form'))

View File

@ -13,6 +13,3 @@
.col-sm-offset-2.col-sm-10 .col-sm-offset-2.col-sm-10
= button_tag 'Delete file', class: 'btn btn-remove btn-remove-file' = button_tag 'Delete file', class: 'btn btn-remove btn-remove-file'
= link_to "Cancel", '#', class: "btn btn-cancel", "data-dismiss" => "modal" = 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 .form-actions
= button_tag 'Create branch', class: 'btn btn-create', tabindex: 3 = button_tag 'Create branch', class: 'btn btn-create', tabindex: 3
= link_to 'Cancel', project_branches_path(@project), class: 'btn btn-cancel' = link_to 'Cancel', project_branches_path(@project), class: 'btn btn-cancel'
%script#availableRefs{ type: "application/json" }= @project.repository.ref_names.to_json.html_safe
:javascript
var availableRefs = #{@project.repository.ref_names.to_json};
new NewBranchForm($('.js-create-branch-form'), availableRefs)

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 .header-main-content
= render partial: 'signature', object: @commit.signature = render partial: 'signature', object: @commit.signature
%strong %strong
@ -79,6 +79,3 @@
= render 'shared/mini_pipeline_graph', pipeline: last_pipeline, klass: 'js-commit-pipeline-graph' = render 'shared/mini_pipeline_graph', pipeline: last_pipeline, klass: 'js-commit-pipeline-graph'
in in
= time_interval_in_words last_pipeline.duration = 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 - notes = commit.notes
- note_count = notes.user.count - 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_key.push(commit.status(ref)) if commit.status(ref)
= cache(cache_key, expires_in: 1.day) do = cache(cache_key, expires_in: 1.day) do

View File

@ -11,7 +11,8 @@
= content_for :sub_nav do = content_for :sub_nav do
= render "head" = render "head"
%div{ class: container_class } .js-project-commits-show{ 'data-commits-limit' => @limit }
%div{ class: container_class }
.tree-holder .tree-holder
.nav-block .nav-block
.tree-ref-container .tree-ref-container
@ -39,6 +40,3 @@
%ol#commits-list.list-unstyled.content_list %ol#commits-list.list-unstyled.content_list
= render 'commits', project: @project, ref: @ref = render 'commits', project: @project, ref: @ref
= spinner = spinner
:javascript
CommitsList.init(#{@limit});

View File

@ -1,7 +1,7 @@
- page_title "Find File", @ref - page_title "Find File", @ref
= render "projects/commits/head" = 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 .nav-block
.tree-ref-holder .tree-ref-holder
= render 'shared/ref_switcher', destination: 'find_file', path: @path = 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" } %table.table.files-slider{ class: "table_#{@hex_path} tree-table table-striped" }
%tbody %tbody
= spinner nil, true = 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? - if show_new_nav?
- add_to_breadcrumbs("Repository", project_tree_path(@project)) - add_to_breadcrumbs("Repository", project_tree_path(@project))
- content_for :page_specific_javascripts do - content_for :page_specific_javascripts do
= page_specific_javascript_bundle_tag('common_d3') = webpack_bundle_tag('common_d3')
= page_specific_javascript_bundle_tag('graphs') = webpack_bundle_tag('graphs')
= webpack_bundle_tag('graphs_charts')
= render "projects/commits/head" = render "projects/commits/head"
.repo-charts{ class: container_class } .repo-charts{ class: container_class }
@ -75,55 +76,10 @@
Commits per day hour (UTC) Commits per day hour (UTC)
%canvas#hour-chart %canvas#hour-chart
:javascript %script#projectChartData{ type: "application/json" }
var responsiveChart = function (selector, data) { - projectChartData = {};
var options = { "scaleOverlay": true, responsive: true, pointHitDetectionRadius: 2, maintainAspectRatio: false }; - projectChartData['hour'] = { 'keys' => @commits_per_time.keys, 'values' => @commits_per_time.values }
// get selector by context - projectChartData['weekDays'] = { 'keys' => @commits_per_week_days.keys, 'values' => @commits_per_week_days.values }
var ctx = selector.get(0).getContext("2d"); - projectChartData['month'] = { 'keys' => @commits_per_month.keys, 'values' => @commits_per_month.values }
// pointing parent container to make chart.js inherit its width - projectChartData['languages'] = @languages
var container = $(selector).parent(); = projectChartData.to_json.html_safe
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);

View File

@ -1,15 +1,16 @@
- @no_container = true - @no_container = true
- page_title "Contributors" - page_title "Contributors"
- content_for :page_specific_javascripts do - content_for :page_specific_javascripts do
= page_specific_javascript_bundle_tag('common_d3') = webpack_bundle_tag('common_d3')
= page_specific_javascript_bundle_tag('graphs') = webpack_bundle_tag('graphs')
= webpack_bundle_tag('graphs_show')
- if show_new_nav? - if show_new_nav?
- add_to_breadcrumbs("Repository", project_tree_path(@project)) - add_to_breadcrumbs("Repository", project_tree_path(@project))
= render 'projects/commits/head' = 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 .sub-header-block
.tree-ref-holder .tree-ref-holder
= render 'shared/ref_switcher', destination: 'graphs' = render 'shared/ref_switcher', destination: 'graphs'
@ -33,24 +34,3 @@
#contributors-master #contributors-master
#contributors.clearfix #contributors.clearfix
%ol.contributors-list.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? - if @project.external_import?
%p.monospace git clone --bare #{@project.safe_import_url} %p.monospace git clone --bare #{@project.safe_import_url}
%p Please wait while we import the repository for you. Refresh at will. %p Please wait while we import the repository for you. Refresh at will.
:javascript
new ProjectImport();

View File

@ -33,7 +33,7 @@
Suggestions: Suggestions:
%code= 'gitlab' %code= 'gitlab'
%code= @project.path # Path contains no spaces, but dashes %code= @project.path # Path contains no spaces, but dashes
%code= @project.path_with_namespace %code= @project.full_path
%p %p
Reserved: Reserved:
= link_to 'https://docs.mattermost.com/help/messaging/executing-commands.html#built-in-commands', target: '__blank' do = 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) - projects = target_projects(@project)
.merge-request-select.dropdown .merge-request-select.dropdown
= f.hidden_field :target_project_id = 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-menu.dropdown-menu-selectable.dropdown-target-project
= dropdown_title("Select target project") = dropdown_title("Select target project")
= dropdown_filter("Search projects") = dropdown_filter("Search projects")

View File

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