Merge branch 'master' into 'docs-specific-review-examples'
# Conflicts: # doc/development/code_review.md
This commit is contained in:
commit
9ba8685ea7
281 changed files with 3383 additions and 1627 deletions
|
@ -96,6 +96,7 @@ stages:
|
|||
- export KNAPSACK_GENERATE_REPORT=true
|
||||
- export CACHE_CLASSES=true
|
||||
- cp ${KNAPSACK_RSPEC_SUITE_REPORT_PATH} ${KNAPSACK_REPORT_PATH}
|
||||
- scripts/gitaly-test-spawn
|
||||
- knapsack rspec "--color --format documentation"
|
||||
artifacts:
|
||||
expire_in: 31d
|
||||
|
@ -221,6 +222,7 @@ setup-test-env:
|
|||
- bundle exec rake gettext:po_to_json
|
||||
- bundle exec rake gitlab:assets:compile
|
||||
- bundle exec ruby -Ispec -e 'require "spec_helper" ; TestEnv.init'
|
||||
- scripts/gitaly-test-build # Do not use 'bundle exec' here
|
||||
artifacts:
|
||||
expire_in: 7d
|
||||
paths:
|
||||
|
@ -486,6 +488,7 @@ karma:
|
|||
BABEL_ENV: "coverage"
|
||||
CHROME_LOG_FILE: "chrome_debug.log"
|
||||
script:
|
||||
- scripts/gitaly-test-spawn
|
||||
- bundle exec rake gettext:po_to_json
|
||||
- bundle exec rake karma
|
||||
coverage: '/^Statements *: (\d+\.\d+%)/'
|
||||
|
|
454
.rubocop.yml
454
.rubocop.yml
|
@ -6,6 +6,7 @@ inherit_from: .rubocop_todo.yml
|
|||
|
||||
AllCops:
|
||||
TargetRubyVersion: 2.3
|
||||
TargetRailsVersion: 4.2
|
||||
# Cop names are not d§splayed in offense messages by default. Change behavior
|
||||
# by overriding DisplayCopNames, or by giving the -D/--display-cop-names
|
||||
# option.
|
||||
|
@ -29,12 +30,221 @@ AllCops:
|
|||
Bundler/OrderedGems:
|
||||
Enabled: false
|
||||
|
||||
# Style #######################################################################
|
||||
# Layout ######################################################################
|
||||
|
||||
# Check indentation of private/protected visibility modifiers.
|
||||
Style/AccessModifierIndentation:
|
||||
Layout/AccessModifierIndentation:
|
||||
Enabled: true
|
||||
|
||||
# Align the elements of an array literal if they span more than one line.
|
||||
Layout/AlignArray:
|
||||
Enabled: true
|
||||
|
||||
# Align the elements of a hash literal if they span more than one line.
|
||||
Layout/AlignHash:
|
||||
Enabled: true
|
||||
|
||||
# Here we check if the parameters on a multi-line method call or
|
||||
# definition are aligned.
|
||||
Layout/AlignParameters:
|
||||
Enabled: false
|
||||
|
||||
# Put end statement of multiline block on its own line.
|
||||
Layout/BlockEndNewline:
|
||||
Enabled: true
|
||||
|
||||
# Indentation of when in a case/when/[else/]end.
|
||||
Layout/CaseIndentation:
|
||||
Enabled: true
|
||||
|
||||
# Indentation of comments.
|
||||
Layout/CommentIndentation:
|
||||
Enabled: true
|
||||
|
||||
# Multi-line method chaining should be done with leading dots.
|
||||
Layout/DotPosition:
|
||||
Enabled: true
|
||||
EnforcedStyle: leading
|
||||
|
||||
# Align elses and elsifs correctly.
|
||||
Layout/ElseAlignment:
|
||||
Enabled: true
|
||||
|
||||
# Add an empty line after magic comments to separate them from code.
|
||||
Layout/EmptyLineAfterMagicComment:
|
||||
Enabled: false
|
||||
|
||||
# Use empty lines between defs.
|
||||
Layout/EmptyLineBetweenDefs:
|
||||
Enabled: true
|
||||
|
||||
# Don't use several empty lines in a row.
|
||||
Layout/EmptyLines:
|
||||
Enabled: true
|
||||
|
||||
# Keep blank lines around access modifiers.
|
||||
Layout/EmptyLinesAroundAccessModifier:
|
||||
Enabled: true
|
||||
|
||||
# Keeps track of empty lines around block bodies.
|
||||
Layout/EmptyLinesAroundBlockBody:
|
||||
Enabled: true
|
||||
|
||||
# Keeps track of empty lines around class bodies.
|
||||
Layout/EmptyLinesAroundClassBody:
|
||||
Enabled: true
|
||||
|
||||
# Keeps track of empty lines around exception handling keywords.
|
||||
Layout/EmptyLinesAroundExceptionHandlingKeywords:
|
||||
Enabled: false
|
||||
|
||||
# Keeps track of empty lines around method bodies.
|
||||
Layout/EmptyLinesAroundMethodBody:
|
||||
Enabled: true
|
||||
|
||||
# Keeps track of empty lines around module bodies.
|
||||
Layout/EmptyLinesAroundModuleBody:
|
||||
Enabled: true
|
||||
|
||||
# Use Unix-style line endings.
|
||||
Layout/EndOfLine:
|
||||
Enabled: true
|
||||
|
||||
# Checks for a line break before the first parameter in a multi-line method
|
||||
# parameter definition.
|
||||
Layout/FirstMethodParameterLineBreak:
|
||||
Enabled: true
|
||||
|
||||
# Keep indentation straight.
|
||||
Layout/IndentationConsistency:
|
||||
Enabled: true
|
||||
|
||||
# Use 2 spaces for indentation.
|
||||
Layout/IndentationWidth:
|
||||
Enabled: true
|
||||
|
||||
# Checks the indentation of the first line of the right-hand-side of a
|
||||
# multi-line assignment.
|
||||
Layout/IndentAssignment:
|
||||
Enabled: true
|
||||
|
||||
# This cops checks the indentation of the here document bodies.
|
||||
Layout/IndentHeredoc:
|
||||
Enabled: false
|
||||
|
||||
# Comments should start with a space.
|
||||
Layout/LeadingCommentSpace:
|
||||
Enabled: true
|
||||
|
||||
# Checks that the closing brace in an array literal is either on the same line
|
||||
# as the last array element, or a new line.
|
||||
Layout/MultilineArrayBraceLayout:
|
||||
Enabled: true
|
||||
EnforcedStyle: symmetrical
|
||||
|
||||
# Ensures newlines after multiline block do statements.
|
||||
Layout/MultilineBlockLayout:
|
||||
Enabled: true
|
||||
|
||||
# Checks that the closing brace in a hash literal is either on the same line as
|
||||
# the last hash element, or a new line.
|
||||
Layout/MultilineHashBraceLayout:
|
||||
Enabled: true
|
||||
EnforcedStyle: symmetrical
|
||||
|
||||
# Checks that the closing brace in a method call is either on the same line as
|
||||
# the last method argument, or a new line.
|
||||
Layout/MultilineMethodCallBraceLayout:
|
||||
Enabled: false
|
||||
EnforcedStyle: symmetrical
|
||||
|
||||
# Checks indentation of method calls with the dot operator that span more than
|
||||
# one line.
|
||||
Layout/MultilineMethodCallIndentation:
|
||||
Enabled: false
|
||||
|
||||
# Checks that the closing brace in a method definition is symmetrical with
|
||||
# respect to the opening brace and the method parameters.
|
||||
Layout/MultilineMethodDefinitionBraceLayout:
|
||||
Enabled: false
|
||||
|
||||
# Checks indentation of binary operations that span more than one line.
|
||||
Layout/MultilineOperationIndentation:
|
||||
Enabled: true
|
||||
EnforcedStyle: indented
|
||||
|
||||
# Use spaces after colons.
|
||||
Layout/SpaceAfterColon:
|
||||
Enabled: true
|
||||
|
||||
# Use spaces after commas.
|
||||
Layout/SpaceAfterComma:
|
||||
Enabled: true
|
||||
|
||||
# Do not put a space between a method name and the opening parenthesis in a
|
||||
# method definition.
|
||||
Layout/SpaceAfterMethodName:
|
||||
Enabled: true
|
||||
|
||||
# Tracks redundant space after the ! operator.
|
||||
Layout/SpaceAfterNot:
|
||||
Enabled: true
|
||||
|
||||
# Use spaces after semicolons.
|
||||
Layout/SpaceAfterSemicolon:
|
||||
Enabled: true
|
||||
|
||||
# Use space around equals in parameter default
|
||||
Layout/SpaceAroundEqualsInParameterDefault:
|
||||
Enabled: true
|
||||
|
||||
# Use a space around keywords if appropriate.
|
||||
Layout/SpaceAroundKeyword:
|
||||
Enabled: true
|
||||
|
||||
# Use a single space around operators.
|
||||
Layout/SpaceAroundOperators:
|
||||
Enabled: true
|
||||
|
||||
# No spaces before commas.
|
||||
Layout/SpaceBeforeComma:
|
||||
Enabled: true
|
||||
|
||||
# Checks for missing space between code and a comment on the same line.
|
||||
Layout/SpaceBeforeComment:
|
||||
Enabled: true
|
||||
|
||||
# No spaces before semicolons.
|
||||
Layout/SpaceBeforeSemicolon:
|
||||
Enabled: true
|
||||
|
||||
# Checks for spaces inside square brackets.
|
||||
Layout/SpaceInsideBrackets:
|
||||
Enabled: true
|
||||
|
||||
# Use spaces inside hash literal braces - or don't.
|
||||
Layout/SpaceInsideHashLiteralBraces:
|
||||
Enabled: true
|
||||
|
||||
# No spaces inside range literals.
|
||||
Layout/SpaceInsideRangeLiteral:
|
||||
Enabled: true
|
||||
|
||||
# Checks for padding/surrounding spaces inside string interpolation.
|
||||
Layout/SpaceInsideStringInterpolation:
|
||||
EnforcedStyle: no_space
|
||||
Enabled: true
|
||||
|
||||
# No hard tabs.
|
||||
Layout/Tab:
|
||||
Enabled: true
|
||||
|
||||
# Checks trailing blank lines and final newline.
|
||||
Layout/TrailingBlankLines:
|
||||
Enabled: true
|
||||
|
||||
# Style #######################################################################
|
||||
|
||||
# Check the naming of accessor methods for get_/set_.
|
||||
Style/AccessorMethodName:
|
||||
Enabled: false
|
||||
|
@ -44,19 +254,6 @@ Style/Alias:
|
|||
EnforcedStyle: prefer_alias_method
|
||||
Enabled: true
|
||||
|
||||
# Align the elements of an array literal if they span more than one line.
|
||||
Style/AlignArray:
|
||||
Enabled: true
|
||||
|
||||
# Align the elements of a hash literal if they span more than one line.
|
||||
Style/AlignHash:
|
||||
Enabled: true
|
||||
|
||||
# Here we check if the parameters on a multi-line method call or
|
||||
# definition are aligned.
|
||||
Style/AlignParameters:
|
||||
Enabled: false
|
||||
|
||||
# Whether `and` and `or` are banned only in conditionals (conditionals)
|
||||
# or completely (always).
|
||||
Style/AndOr:
|
||||
|
@ -91,10 +288,6 @@ Style/BlockComments:
|
|||
Style/BlockDelimiters:
|
||||
Enabled: true
|
||||
|
||||
# Put end statement of multiline block on its own line.
|
||||
Style/BlockEndNewline:
|
||||
Enabled: true
|
||||
|
||||
# This cop checks for braces around the last parameter in a method call
|
||||
# if the last parameter is a hash.
|
||||
Style/BracesAroundHashParameters:
|
||||
|
@ -104,10 +297,6 @@ Style/BracesAroundHashParameters:
|
|||
Style/CaseEquality:
|
||||
Enabled: false
|
||||
|
||||
# Indentation of when in a case/when/[else/]end.
|
||||
Style/CaseIndentation:
|
||||
Enabled: true
|
||||
|
||||
# Checks for uses of character literals.
|
||||
Style/CharacterLiteral:
|
||||
Enabled: true
|
||||
|
@ -142,10 +331,6 @@ Style/ColonMethodCall:
|
|||
Style/CommentAnnotation:
|
||||
Enabled: false
|
||||
|
||||
# Indentation of comments.
|
||||
Style/CommentIndentation:
|
||||
Enabled: true
|
||||
|
||||
# Check for `if` and `case` statements where each branch is used for
|
||||
# assignment to the same variable when using the return of the
|
||||
# condition can be used instead.
|
||||
|
@ -164,57 +349,16 @@ Style/DefWithParentheses:
|
|||
Style/Documentation:
|
||||
Enabled: false
|
||||
|
||||
# Multi-line method chaining should be done with leading dots.
|
||||
Style/DotPosition:
|
||||
Enabled: true
|
||||
EnforcedStyle: leading
|
||||
|
||||
# This cop checks for uses of double negation (!!) to convert something
|
||||
# to a boolean value. As this is both cryptic and usually redundant, it
|
||||
# should be avoided.
|
||||
Style/DoubleNegation:
|
||||
Enabled: false
|
||||
|
||||
# Align elses and elsifs correctly.
|
||||
Style/ElseAlignment:
|
||||
Enabled: true
|
||||
|
||||
# Use empty lines between defs.
|
||||
Style/EmptyLineBetweenDefs:
|
||||
Enabled: true
|
||||
|
||||
# Don't use several empty lines in a row.
|
||||
Style/EmptyLines:
|
||||
Enabled: true
|
||||
|
||||
# Keep blank lines around access modifiers.
|
||||
Style/EmptyLinesAroundAccessModifier:
|
||||
Enabled: true
|
||||
|
||||
# Keeps track of empty lines around block bodies.
|
||||
Style/EmptyLinesAroundBlockBody:
|
||||
Enabled: true
|
||||
|
||||
# Keeps track of empty lines around class bodies.
|
||||
Style/EmptyLinesAroundClassBody:
|
||||
Enabled: true
|
||||
|
||||
# Keeps track of empty lines around method bodies.
|
||||
Style/EmptyLinesAroundMethodBody:
|
||||
Enabled: true
|
||||
|
||||
# Keeps track of empty lines around module bodies.
|
||||
Style/EmptyLinesAroundModuleBody:
|
||||
Enabled: true
|
||||
|
||||
# Avoid the use of END blocks.
|
||||
Style/EndBlock:
|
||||
Enabled: true
|
||||
|
||||
# Use Unix-style line endings.
|
||||
Style/EndOfLine:
|
||||
Enabled: true
|
||||
|
||||
# Favor the use of Fixnum#even? && Fixnum#odd?
|
||||
Style/EvenOdd:
|
||||
Enabled: true
|
||||
|
@ -223,11 +367,6 @@ Style/EvenOdd:
|
|||
Style/FileName:
|
||||
Enabled: true
|
||||
|
||||
# Checks for a line break before the first parameter in a multi-line method
|
||||
# parameter definition.
|
||||
Style/FirstMethodParameterLineBreak:
|
||||
Enabled: true
|
||||
|
||||
# Checks for flip flops.
|
||||
Style/FlipFlop:
|
||||
Enabled: true
|
||||
|
@ -236,6 +375,10 @@ Style/FlipFlop:
|
|||
Style/For:
|
||||
Enabled: true
|
||||
|
||||
# Use a consistent style for format string tokens.
|
||||
Style/FormatStringToken:
|
||||
Enabled: false
|
||||
|
||||
# Checks if there is a magic comment to enforce string literals
|
||||
Style/FrozenStringLiteralComment:
|
||||
Enabled: false
|
||||
|
@ -261,31 +404,19 @@ Style/IdenticalConditionalBranches:
|
|||
Style/IfWithSemicolon:
|
||||
Enabled: true
|
||||
|
||||
# Checks the indentation of the first line of the right-hand-side of a
|
||||
# multi-line assignment.
|
||||
Style/IndentAssignment:
|
||||
Enabled: true
|
||||
|
||||
# Keep indentation straight.
|
||||
Style/IndentationConsistency:
|
||||
Enabled: true
|
||||
|
||||
# Use 2 spaces for indentation.
|
||||
Style/IndentationWidth:
|
||||
Enabled: true
|
||||
|
||||
# Use Kernel#loop for infinite loops.
|
||||
Style/InfiniteLoop:
|
||||
Enabled: true
|
||||
|
||||
# Use the inverse method instead of `!.method`
|
||||
# if an inverse method is defined.
|
||||
Style/InverseMethods:
|
||||
Enabled: false
|
||||
|
||||
# Use lambda.call(...) instead of lambda.(...).
|
||||
Style/LambdaCall:
|
||||
Enabled: true
|
||||
|
||||
# Comments should start with a space.
|
||||
Style/LeadingCommentSpace:
|
||||
Enabled: true
|
||||
|
||||
# Checks if the method definitions have or don't have parentheses.
|
||||
Style/MethodDefParentheses:
|
||||
Enabled: true
|
||||
|
@ -298,55 +429,23 @@ Style/MethodName:
|
|||
Style/ModuleFunction:
|
||||
Enabled: false
|
||||
|
||||
# Checks that the closing brace in an array literal is either on the same line
|
||||
# as the last array element, or a new line.
|
||||
Style/MultilineArrayBraceLayout:
|
||||
Enabled: true
|
||||
EnforcedStyle: symmetrical
|
||||
|
||||
# Avoid multi-line chains of blocks.
|
||||
Style/MultilineBlockChain:
|
||||
Enabled: true
|
||||
|
||||
# Ensures newlines after multiline block do statements.
|
||||
Style/MultilineBlockLayout:
|
||||
Enabled: true
|
||||
|
||||
# Checks that the closing brace in a hash literal is either on the same line as
|
||||
# the last hash element, or a new line.
|
||||
Style/MultilineHashBraceLayout:
|
||||
Enabled: true
|
||||
EnforcedStyle: symmetrical
|
||||
|
||||
# Do not use then for multi-line if/unless.
|
||||
Style/MultilineIfThen:
|
||||
Enabled: true
|
||||
|
||||
# Checks that the closing brace in a method call is either on the same line as
|
||||
# the last method argument, or a new line.
|
||||
Style/MultilineMethodCallBraceLayout:
|
||||
Enabled: false
|
||||
EnforcedStyle: symmetrical
|
||||
|
||||
# Checks indentation of method calls with the dot operator that span more than
|
||||
# one line.
|
||||
Style/MultilineMethodCallIndentation:
|
||||
Enabled: false
|
||||
|
||||
# Checks that the closing brace in a method definition is symmetrical with
|
||||
# respect to the opening brace and the method parameters.
|
||||
Style/MultilineMethodDefinitionBraceLayout:
|
||||
Enabled: false
|
||||
|
||||
# Checks indentation of binary operations that span more than one line.
|
||||
Style/MultilineOperationIndentation:
|
||||
Enabled: true
|
||||
EnforcedStyle: indented
|
||||
|
||||
# Avoid multi-line `? :` (the ternary operator), use if/unless instead.
|
||||
Style/MultilineTernaryOperator:
|
||||
Enabled: true
|
||||
|
||||
# Avoid comparing a variable with multiple items in a conditional,
|
||||
# use Array#include? instead.
|
||||
Style/MultipleComparison:
|
||||
Enabled: false
|
||||
|
||||
# This cop checks whether some constant value isn't a
|
||||
# mutable literal (e.g. array or hash).
|
||||
Style/MutableConstant:
|
||||
|
@ -421,68 +520,6 @@ Style/SignalException:
|
|||
EnforcedStyle: only_raise
|
||||
Enabled: true
|
||||
|
||||
# Use spaces after colons.
|
||||
Style/SpaceAfterColon:
|
||||
Enabled: true
|
||||
|
||||
# Use spaces after commas.
|
||||
Style/SpaceAfterComma:
|
||||
Enabled: true
|
||||
|
||||
# Do not put a space between a method name and the opening parenthesis in a
|
||||
# method definition.
|
||||
Style/SpaceAfterMethodName:
|
||||
Enabled: true
|
||||
|
||||
# Tracks redundant space after the ! operator.
|
||||
Style/SpaceAfterNot:
|
||||
Enabled: true
|
||||
|
||||
# Use spaces after semicolons.
|
||||
Style/SpaceAfterSemicolon:
|
||||
Enabled: true
|
||||
|
||||
# Use space around equals in parameter default
|
||||
Style/SpaceAroundEqualsInParameterDefault:
|
||||
Enabled: true
|
||||
|
||||
# Use a space around keywords if appropriate.
|
||||
Style/SpaceAroundKeyword:
|
||||
Enabled: true
|
||||
|
||||
# Use a single space around operators.
|
||||
Style/SpaceAroundOperators:
|
||||
Enabled: true
|
||||
|
||||
# No spaces before commas.
|
||||
Style/SpaceBeforeComma:
|
||||
Enabled: true
|
||||
|
||||
# Checks for missing space between code and a comment on the same line.
|
||||
Style/SpaceBeforeComment:
|
||||
Enabled: true
|
||||
|
||||
# No spaces before semicolons.
|
||||
Style/SpaceBeforeSemicolon:
|
||||
Enabled: true
|
||||
|
||||
# Checks for spaces inside square brackets.
|
||||
Style/SpaceInsideBrackets:
|
||||
Enabled: true
|
||||
|
||||
# Use spaces inside hash literal braces - or don't.
|
||||
Style/SpaceInsideHashLiteralBraces:
|
||||
Enabled: true
|
||||
|
||||
# No spaces inside range literals.
|
||||
Style/SpaceInsideRangeLiteral:
|
||||
Enabled: true
|
||||
|
||||
# Checks for padding/surrounding spaces inside string interpolation.
|
||||
Style/SpaceInsideStringInterpolation:
|
||||
EnforcedStyle: no_space
|
||||
Enabled: true
|
||||
|
||||
# Check for the usage of parentheses around stabby lambda arguments.
|
||||
Style/StabbyLambdaParentheses:
|
||||
EnforcedStyle: require_parentheses
|
||||
|
@ -498,13 +535,9 @@ Style/StringMethods:
|
|||
intern: to_sym
|
||||
Enabled: true
|
||||
|
||||
# No hard tabs.
|
||||
Style/Tab:
|
||||
Enabled: true
|
||||
|
||||
# Checks trailing blank lines and final newline.
|
||||
Style/TrailingBlankLines:
|
||||
Enabled: true
|
||||
# Use %i or %I for arrays of symbols.
|
||||
Style/SymbolArray:
|
||||
Enabled: false
|
||||
|
||||
# This cop checks for trailing comma in array and hash literals.
|
||||
Style/TrailingCommaInLiteral:
|
||||
|
@ -553,6 +586,10 @@ Style/WhileUntilModifier:
|
|||
Style/WordArray:
|
||||
Enabled: true
|
||||
|
||||
# Do not use literals as the first operand of a comparison.
|
||||
Style/YodaCondition:
|
||||
Enabled: false
|
||||
|
||||
# Use `proc` instead of `Proc.new`.
|
||||
Style/Proc:
|
||||
Enabled: true
|
||||
|
@ -608,6 +645,11 @@ Metrics/PerceivedComplexity:
|
|||
|
||||
# Lint ########################################################################
|
||||
|
||||
# Checks for ambiguous block association with method when param passed without
|
||||
# parentheses.
|
||||
Lint/AmbiguousBlockAssociation:
|
||||
Enabled: false
|
||||
|
||||
# Checks for ambiguous operators in the first argument of a method invocation
|
||||
# without parentheses.
|
||||
Lint/AmbiguousOperator:
|
||||
|
@ -809,6 +851,10 @@ Lint/Void:
|
|||
|
||||
# Performance #################################################################
|
||||
|
||||
# Use `caller(n..n)` instead of `caller`.
|
||||
Performance/Caller:
|
||||
Enabled: false
|
||||
|
||||
# Use `casecmp` rather than `downcase ==`.
|
||||
Performance/Casecmp:
|
||||
Enabled: true
|
||||
|
@ -883,6 +929,14 @@ Rails/ActionFilter:
|
|||
Enabled: true
|
||||
EnforcedStyle: action
|
||||
|
||||
# Check that models subclass ApplicationRecord.
|
||||
Rails/ApplicationRecord:
|
||||
Enabled: false
|
||||
|
||||
# Enforce using `blank?` and `present?`.
|
||||
Rails/Blank:
|
||||
Enabled: false
|
||||
|
||||
# Checks the correct usage of date aware methods, such as `Date.today`,
|
||||
# `Date.current`, etc.
|
||||
Rails/Date:
|
||||
|
@ -939,10 +993,18 @@ Rails/OutputSafety:
|
|||
Rails/PluralizationGrammar:
|
||||
Enabled: true
|
||||
|
||||
# Enforce using `blank?` and `present?`.
|
||||
Rails/Present:
|
||||
Enabled: false
|
||||
|
||||
# Checks for `read_attribute(:attr)` and `write_attribute(:attr, val)`.
|
||||
Rails/ReadWriteAttribute:
|
||||
Enabled: false
|
||||
|
||||
# Do not assign relative date to constants.
|
||||
Rails/RelativeDateConstant:
|
||||
Enabled: false
|
||||
|
||||
# Checks the arguments of ActiveRecord scopes.
|
||||
Rails/ScopeArgs:
|
||||
Enabled: true
|
||||
|
|
|
@ -1,26 +1,89 @@
|
|||
# This configuration was generated by
|
||||
# `rubocop --auto-gen-config --exclude-limit 0`
|
||||
# on 2017-04-07 20:17:35 -0400 using RuboCop version 0.47.1.
|
||||
# on 2017-07-10 01:48:30 +0900 using RuboCop version 0.49.1.
|
||||
# The point is for the user to remove these configuration records
|
||||
# one by one as the offenses are removed from the code base.
|
||||
# Note that changes in the inspected code, or installation of new
|
||||
# versions of RuboCop, may require this file to be generated again.
|
||||
|
||||
# Offense count: 233
|
||||
# Offense count: 181
|
||||
# Cop supports --auto-correct.
|
||||
# Configuration parameters: AllowForAlignment, ForceEqualSignAlignment.
|
||||
Layout/ExtraSpacing:
|
||||
Enabled: false
|
||||
|
||||
# Offense count: 119
|
||||
# Cop supports --auto-correct.
|
||||
# Configuration parameters: EnforcedStyle, SupportedStyles, IndentationWidth.
|
||||
# SupportedStyles: special_inside_parentheses, consistent, align_brackets
|
||||
Layout/IndentArray:
|
||||
Enabled: false
|
||||
|
||||
# Offense count: 208
|
||||
# Cop supports --auto-correct.
|
||||
# Configuration parameters: EnforcedStyle, SupportedStyles, IndentationWidth.
|
||||
# SupportedStyles: special_inside_parentheses, consistent, align_braces
|
||||
Layout/IndentHash:
|
||||
Enabled: false
|
||||
|
||||
# Offense count: 174
|
||||
# Cop supports --auto-correct.
|
||||
# Configuration parameters: EnforcedStyle, SupportedStyles.
|
||||
# SupportedStyles: space, no_space
|
||||
Layout/SpaceBeforeBlockBraces:
|
||||
Enabled: false
|
||||
|
||||
# Offense count: 8
|
||||
# Cop supports --auto-correct.
|
||||
# Configuration parameters: AllowForAlignment.
|
||||
Layout/SpaceBeforeFirstArg:
|
||||
Enabled: false
|
||||
|
||||
# Offense count: 64
|
||||
# Cop supports --auto-correct.
|
||||
# Configuration parameters: EnforcedStyle, SupportedStyles.
|
||||
# SupportedStyles: require_no_space, require_space
|
||||
Layout/SpaceInLambdaLiteral:
|
||||
Enabled: false
|
||||
|
||||
# Offense count: 256
|
||||
# Cop supports --auto-correct.
|
||||
# Configuration parameters: EnforcedStyle, SupportedStyles, EnforcedStyleForEmptyBraces, SupportedStylesForEmptyBraces, SpaceBeforeBlockParameters.
|
||||
# SupportedStyles: space, no_space
|
||||
# SupportedStylesForEmptyBraces: space, no_space
|
||||
Layout/SpaceInsideBlockBraces:
|
||||
Enabled: false
|
||||
|
||||
# Offense count: 135
|
||||
# Cop supports --auto-correct.
|
||||
Layout/SpaceInsideParens:
|
||||
Enabled: false
|
||||
|
||||
# Offense count: 14
|
||||
# Cop supports --auto-correct.
|
||||
Layout/SpaceInsidePercentLiteralDelimiters:
|
||||
Enabled: false
|
||||
|
||||
# Offense count: 89
|
||||
# Cop supports --auto-correct.
|
||||
Layout/TrailingWhitespace:
|
||||
Enabled: false
|
||||
|
||||
# Offense count: 272
|
||||
RSpec/EmptyLineAfterFinalLet:
|
||||
Enabled: false
|
||||
|
||||
# Offense count: 167
|
||||
# Offense count: 181
|
||||
RSpec/EmptyLineAfterSubject:
|
||||
Enabled: false
|
||||
|
||||
# Offense count: 72
|
||||
# Offense count: 78
|
||||
# Configuration parameters: EnforcedStyle, SupportedStyles.
|
||||
# SupportedStyles: implicit, each, example
|
||||
RSpec/HookArgument:
|
||||
Enabled: false
|
||||
|
||||
# Offense count: 11
|
||||
# Offense count: 9
|
||||
# Configuration parameters: EnforcedStyle, SupportedStyles.
|
||||
# SupportedStyles: it_behaves_like, it_should_behave_like
|
||||
RSpec/ItBehavesLike:
|
||||
|
@ -30,19 +93,19 @@ RSpec/ItBehavesLike:
|
|||
RSpec/IteratedExpectation:
|
||||
Enabled: false
|
||||
|
||||
# Offense count: 3
|
||||
# Offense count: 2
|
||||
RSpec/OverwritingSetup:
|
||||
Enabled: false
|
||||
|
||||
# Offense count: 34
|
||||
# Offense count: 36
|
||||
RSpec/RepeatedExample:
|
||||
Enabled: false
|
||||
|
||||
# Offense count: 43
|
||||
# Offense count: 86
|
||||
RSpec/ScatteredLet:
|
||||
Enabled: false
|
||||
|
||||
# Offense count: 32
|
||||
# Offense count: 20
|
||||
RSpec/ScatteredSetup:
|
||||
Enabled: false
|
||||
|
||||
|
@ -50,7 +113,7 @@ RSpec/ScatteredSetup:
|
|||
RSpec/SharedContext:
|
||||
Enabled: false
|
||||
|
||||
# Offense count: 150
|
||||
# Offense count: 115
|
||||
Rails/FilePath:
|
||||
Enabled: false
|
||||
|
||||
|
@ -60,90 +123,71 @@ Rails/FilePath:
|
|||
Rails/ReversibleMigration:
|
||||
Enabled: false
|
||||
|
||||
# Offense count: 302
|
||||
# Offense count: 336
|
||||
# Configuration parameters: Blacklist.
|
||||
# Blacklist: decrement!, decrement_counter, increment!, increment_counter, toggle!, touch, update_all, update_attribute, update_column, update_columns, update_counters
|
||||
Rails/SkipsModelValidations:
|
||||
Enabled: false
|
||||
|
||||
# Offense count: 7
|
||||
# Offense count: 11
|
||||
# Cop supports --auto-correct.
|
||||
Security/YAMLLoad:
|
||||
Enabled: false
|
||||
|
||||
# Offense count: 59
|
||||
# Offense count: 58
|
||||
# Cop supports --auto-correct.
|
||||
# Configuration parameters: EnforcedStyle, SupportedStyles.
|
||||
# SupportedStyles: percent_q, bare_percent
|
||||
Style/BarePercentLiterals:
|
||||
Enabled: false
|
||||
|
||||
# Offense count: 5
|
||||
# Offense count: 6
|
||||
# Cop supports --auto-correct.
|
||||
Style/EachWithObject:
|
||||
Enabled: false
|
||||
|
||||
# Offense count: 28
|
||||
# Offense count: 31
|
||||
# Cop supports --auto-correct.
|
||||
# Configuration parameters: EnforcedStyle, SupportedStyles.
|
||||
# SupportedStyles: empty, nil, both
|
||||
Style/EmptyElse:
|
||||
Enabled: false
|
||||
|
||||
# Offense count: 4
|
||||
# Offense count: 9
|
||||
# Cop supports --auto-correct.
|
||||
Style/EmptyLiteral:
|
||||
Enabled: false
|
||||
|
||||
# Offense count: 59
|
||||
# Offense count: 78
|
||||
# Cop supports --auto-correct.
|
||||
# Configuration parameters: EnforcedStyle, SupportedStyles.
|
||||
# SupportedStyles: compact, expanded
|
||||
Style/EmptyMethod:
|
||||
Enabled: false
|
||||
|
||||
# Offense count: 214
|
||||
# Offense count: 23
|
||||
# Cop supports --auto-correct.
|
||||
# Configuration parameters: AllowForAlignment, ForceEqualSignAlignment.
|
||||
Style/ExtraSpacing:
|
||||
Enabled: false
|
||||
|
||||
# Offense count: 9
|
||||
# Configuration parameters: EnforcedStyle, SupportedStyles.
|
||||
# SupportedStyles: format, sprintf, percent
|
||||
Style/FormatString:
|
||||
Enabled: false
|
||||
|
||||
# Offense count: 285
|
||||
# Offense count: 301
|
||||
# Configuration parameters: MinBodyLength.
|
||||
Style/GuardClause:
|
||||
Enabled: false
|
||||
|
||||
# Offense count: 16
|
||||
# Offense count: 18
|
||||
Style/IfInsideElse:
|
||||
Enabled: false
|
||||
|
||||
# Offense count: 186
|
||||
# Offense count: 182
|
||||
# Cop supports --auto-correct.
|
||||
# Configuration parameters: MaxLineLength.
|
||||
Style/IfUnlessModifier:
|
||||
Enabled: false
|
||||
|
||||
# Offense count: 99
|
||||
# Cop supports --auto-correct.
|
||||
# Configuration parameters: EnforcedStyle, SupportedStyles, IndentationWidth.
|
||||
# SupportedStyles: special_inside_parentheses, consistent, align_brackets
|
||||
Style/IndentArray:
|
||||
Enabled: false
|
||||
|
||||
# Offense count: 160
|
||||
# Cop supports --auto-correct.
|
||||
# Configuration parameters: EnforcedStyle, SupportedStyles, IndentationWidth.
|
||||
# SupportedStyles: special_inside_parentheses, consistent, align_braces
|
||||
Style/IndentHash:
|
||||
Enabled: false
|
||||
|
||||
# Offense count: 50
|
||||
# Offense count: 52
|
||||
# Cop supports --auto-correct.
|
||||
# Configuration parameters: EnforcedStyle, SupportedStyles.
|
||||
# SupportedStyles: line_count_dependent, lambda, literal
|
||||
|
@ -155,63 +199,63 @@ Style/Lambda:
|
|||
Style/LineEndConcatenation:
|
||||
Enabled: false
|
||||
|
||||
# Offense count: 34
|
||||
# Offense count: 40
|
||||
# Cop supports --auto-correct.
|
||||
Style/MethodCallWithoutArgsParentheses:
|
||||
Enabled: false
|
||||
|
||||
# Offense count: 10
|
||||
# Offense count: 13
|
||||
Style/MethodMissing:
|
||||
Enabled: false
|
||||
|
||||
# Offense count: 3
|
||||
# Offense count: 6
|
||||
# Cop supports --auto-correct.
|
||||
Style/MultilineIfModifier:
|
||||
Enabled: false
|
||||
|
||||
# Offense count: 24
|
||||
# Offense count: 26
|
||||
# Cop supports --auto-correct.
|
||||
Style/NestedParenthesizedCalls:
|
||||
Enabled: false
|
||||
|
||||
# Offense count: 18
|
||||
# Offense count: 20
|
||||
# Cop supports --auto-correct.
|
||||
# Configuration parameters: EnforcedStyle, MinBodyLength, SupportedStyles.
|
||||
# SupportedStyles: skip_modifier_ifs, always
|
||||
Style/Next:
|
||||
Enabled: false
|
||||
|
||||
# Offense count: 37
|
||||
# Offense count: 45
|
||||
# Cop supports --auto-correct.
|
||||
# Configuration parameters: EnforcedOctalStyle, SupportedOctalStyles.
|
||||
# SupportedOctalStyles: zero_with_o, zero_only
|
||||
Style/NumericLiteralPrefix:
|
||||
Enabled: false
|
||||
|
||||
# Offense count: 88
|
||||
# Offense count: 98
|
||||
# Cop supports --auto-correct.
|
||||
# Configuration parameters: AutoCorrect, EnforcedStyle, SupportedStyles.
|
||||
# SupportedStyles: predicate, comparison
|
||||
Style/NumericPredicate:
|
||||
Enabled: false
|
||||
|
||||
# Offense count: 36
|
||||
# Offense count: 42
|
||||
# Cop supports --auto-correct.
|
||||
Style/ParallelAssignment:
|
||||
Enabled: false
|
||||
|
||||
# Offense count: 570
|
||||
# Offense count: 800
|
||||
# Cop supports --auto-correct.
|
||||
# Configuration parameters: PreferredDelimiters.
|
||||
Style/PercentLiteralDelimiters:
|
||||
Enabled: false
|
||||
|
||||
# Offense count: 14
|
||||
# Offense count: 15
|
||||
# Cop supports --auto-correct.
|
||||
Style/PerlBackrefs:
|
||||
Enabled: false
|
||||
|
||||
# Offense count: 83
|
||||
# Offense count: 105
|
||||
# Configuration parameters: NamePrefix, NamePrefixBlacklist, NameWhitelist.
|
||||
# NamePrefix: is_, has_, have_
|
||||
# NamePrefixBlacklist: is_, has_, have_
|
||||
|
@ -219,47 +263,47 @@ Style/PerlBackrefs:
|
|||
Style/PredicateName:
|
||||
Enabled: false
|
||||
|
||||
# Offense count: 65
|
||||
# Offense count: 58
|
||||
# Cop supports --auto-correct.
|
||||
# Configuration parameters: EnforcedStyle, SupportedStyles.
|
||||
# SupportedStyles: compact, exploded
|
||||
Style/RaiseArgs:
|
||||
Enabled: false
|
||||
|
||||
# Offense count: 5
|
||||
# Offense count: 6
|
||||
# Cop supports --auto-correct.
|
||||
Style/RedundantBegin:
|
||||
Enabled: false
|
||||
|
||||
# Offense count: 32
|
||||
# Offense count: 37
|
||||
# Cop supports --auto-correct.
|
||||
Style/RedundantFreeze:
|
||||
Enabled: false
|
||||
|
||||
# Offense count: 15
|
||||
# Offense count: 14
|
||||
# Cop supports --auto-correct.
|
||||
# Configuration parameters: AllowMultipleReturnValues.
|
||||
Style/RedundantReturn:
|
||||
Enabled: false
|
||||
|
||||
# Offense count: 382
|
||||
# Offense count: 406
|
||||
# Cop supports --auto-correct.
|
||||
Style/RedundantSelf:
|
||||
Enabled: false
|
||||
|
||||
# Offense count: 111
|
||||
# Offense count: 115
|
||||
# Cop supports --auto-correct.
|
||||
# Configuration parameters: EnforcedStyle, SupportedStyles, AllowInnerSlashes.
|
||||
# SupportedStyles: slashes, percent_r, mixed
|
||||
Style/RegexpLiteral:
|
||||
Enabled: false
|
||||
|
||||
# Offense count: 24
|
||||
# Offense count: 29
|
||||
# Cop supports --auto-correct.
|
||||
Style/RescueModifier:
|
||||
Enabled: false
|
||||
|
||||
# Offense count: 7
|
||||
# Offense count: 8
|
||||
# Cop supports --auto-correct.
|
||||
Style/SelfAssignment:
|
||||
Enabled: false
|
||||
|
@ -270,101 +314,58 @@ Style/SelfAssignment:
|
|||
Style/SingleLineMethods:
|
||||
Enabled: false
|
||||
|
||||
# Offense count: 168
|
||||
# Cop supports --auto-correct.
|
||||
# Configuration parameters: EnforcedStyle, SupportedStyles.
|
||||
# SupportedStyles: space, no_space
|
||||
Style/SpaceBeforeBlockBraces:
|
||||
Enabled: false
|
||||
|
||||
# Offense count: 8
|
||||
# Cop supports --auto-correct.
|
||||
# Configuration parameters: AllowForAlignment.
|
||||
Style/SpaceBeforeFirstArg:
|
||||
Enabled: false
|
||||
|
||||
# Offense count: 46
|
||||
# Cop supports --auto-correct.
|
||||
# Configuration parameters: EnforcedStyle, SupportedStyles.
|
||||
# SupportedStyles: require_no_space, require_space
|
||||
Style/SpaceInLambdaLiteral:
|
||||
Enabled: false
|
||||
|
||||
# Offense count: 229
|
||||
# Cop supports --auto-correct.
|
||||
# Configuration parameters: EnforcedStyle, SupportedStyles, EnforcedStyleForEmptyBraces, SupportedStylesForEmptyBraces, SpaceBeforeBlockParameters.
|
||||
# SupportedStyles: space, no_space
|
||||
# SupportedStylesForEmptyBraces: space, no_space
|
||||
Style/SpaceInsideBlockBraces:
|
||||
Enabled: false
|
||||
|
||||
# Offense count: 116
|
||||
# Cop supports --auto-correct.
|
||||
Style/SpaceInsideParens:
|
||||
Enabled: false
|
||||
|
||||
# Offense count: 12
|
||||
# Cop supports --auto-correct.
|
||||
Style/SpaceInsidePercentLiteralDelimiters:
|
||||
Enabled: false
|
||||
|
||||
# Offense count: 57
|
||||
# Offense count: 64
|
||||
# Cop supports --auto-correct.
|
||||
# Configuration parameters: SupportedStyles.
|
||||
# SupportedStyles: use_perl_names, use_english_names
|
||||
Style/SpecialGlobalVars:
|
||||
EnforcedStyle: use_perl_names
|
||||
|
||||
# Offense count: 42
|
||||
# Offense count: 44
|
||||
# Cop supports --auto-correct.
|
||||
# Configuration parameters: EnforcedStyle, SupportedStyles.
|
||||
# SupportedStyles: single_quotes, double_quotes
|
||||
Style/StringLiteralsInInterpolation:
|
||||
Enabled: false
|
||||
|
||||
# Offense count: 64
|
||||
# Offense count: 84
|
||||
# Cop supports --auto-correct.
|
||||
# Configuration parameters: IgnoredMethods.
|
||||
# IgnoredMethods: respond_to, define_method
|
||||
Style/SymbolProc:
|
||||
Enabled: false
|
||||
|
||||
# Offense count: 6
|
||||
# Offense count: 8
|
||||
# Cop supports --auto-correct.
|
||||
# Configuration parameters: EnforcedStyle, SupportedStyles, AllowSafeAssignment.
|
||||
# SupportedStyles: require_parentheses, require_no_parentheses, require_parentheses_when_complex
|
||||
Style/TernaryParentheses:
|
||||
Enabled: false
|
||||
|
||||
# Offense count: 18
|
||||
# Offense count: 17
|
||||
# Cop supports --auto-correct.
|
||||
# Configuration parameters: AllowNamedUnderscoreVariables.
|
||||
Style/TrailingUnderscoreVariable:
|
||||
Enabled: false
|
||||
|
||||
# Offense count: 78
|
||||
# Cop supports --auto-correct.
|
||||
Style/TrailingWhitespace:
|
||||
Enabled: false
|
||||
|
||||
# Offense count: 3
|
||||
# Offense count: 4
|
||||
# Cop supports --auto-correct.
|
||||
# Configuration parameters: ExactNameMatch, AllowPredicates, AllowDSLWriters, IgnoreClassMethods, Whitelist.
|
||||
# Whitelist: to_ary, to_a, to_c, to_enum, to_h, to_hash, to_i, to_int, to_io, to_open, to_path, to_proc, to_r, to_regexp, to_str, to_s, to_sym
|
||||
Style/TrivialAccessors:
|
||||
Enabled: false
|
||||
|
||||
# Offense count: 6
|
||||
# Offense count: 5
|
||||
# Cop supports --auto-correct.
|
||||
Style/UnlessElse:
|
||||
Enabled: false
|
||||
|
||||
# Offense count: 24
|
||||
# Offense count: 28
|
||||
# Cop supports --auto-correct.
|
||||
Style/UnneededInterpolation:
|
||||
Enabled: false
|
||||
|
||||
# Offense count: 8
|
||||
# Offense count: 11
|
||||
# Cop supports --auto-correct.
|
||||
Style/ZeroLengthPredicate:
|
||||
Enabled: false
|
||||
|
|
10
CHANGELOG.md
10
CHANGELOG.md
|
@ -2,6 +2,16 @@
|
|||
documentation](doc/development/changelog.md) for instructions on adding your own
|
||||
entry.
|
||||
|
||||
## 9.4.3 (2017-07-31)
|
||||
|
||||
- Fix Prometheus client PID reuse bug. !13130
|
||||
- Improve deploy environment chatops slash command. !13150
|
||||
- Fix asynchronous javascript paths when GitLab is installed under a relative URL. !13165
|
||||
- Fix LDAP authentication to Git repository or container registry.
|
||||
- Fixed new navigation breadcrumb title on help pages.
|
||||
- Ensure filesystem metrics test files are deleted.
|
||||
- Properly affixes nav bar in job view in microsoft edge.
|
||||
|
||||
## 9.4.2 (2017-07-28)
|
||||
|
||||
- Fix job merge request link to a forked source project. !12965
|
||||
|
|
|
@ -1 +1 @@
|
|||
0.25.0
|
||||
0.26.0
|
||||
|
|
4
Gemfile
4
Gemfile
|
@ -339,8 +339,8 @@ group :development, :test do
|
|||
gem 'spring-commands-rspec', '~> 1.0.4'
|
||||
gem 'spring-commands-spinach', '~> 1.1.0'
|
||||
|
||||
gem 'rubocop', '~> 0.47.1', require: false
|
||||
gem 'rubocop-rspec', '~> 1.15.0', require: false
|
||||
gem 'rubocop', '~> 0.49.1', require: false
|
||||
gem 'rubocop-rspec', '~> 1.15.1', require: false
|
||||
gem 'scss_lint', '~> 0.54.0', require: false
|
||||
gem 'haml_lint', '~> 0.21.0', require: false
|
||||
gem 'simplecov', '~> 0.14.0', require: false
|
||||
|
|
14
Gemfile.lock
14
Gemfile.lock
|
@ -323,7 +323,7 @@ GEM
|
|||
multi_json (~> 1.10)
|
||||
retriable (~> 1.4)
|
||||
signet (~> 0.6)
|
||||
google-protobuf (3.2.0.2)
|
||||
google-protobuf (3.3.0)
|
||||
googleauth (0.5.1)
|
||||
faraday (~> 0.9)
|
||||
jwt (~> 1.4)
|
||||
|
@ -545,6 +545,7 @@ GEM
|
|||
rubypants (~> 0.2)
|
||||
orm_adapter (0.5.0)
|
||||
os (0.9.6)
|
||||
parallel (1.11.2)
|
||||
paranoia (2.3.1)
|
||||
activerecord (>= 4.0, < 5.2)
|
||||
parser (2.4.0.0)
|
||||
|
@ -730,13 +731,14 @@ GEM
|
|||
pg
|
||||
rails
|
||||
sqlite3
|
||||
rubocop (0.47.1)
|
||||
rubocop (0.49.1)
|
||||
parallel (~> 1.10)
|
||||
parser (>= 2.3.3.1, < 3.0)
|
||||
powerpack (~> 0.1)
|
||||
rainbow (>= 1.99.1, < 3.0)
|
||||
ruby-progressbar (~> 1.7)
|
||||
unicode-display_width (~> 1.0, >= 1.0.1)
|
||||
rubocop-rspec (1.15.0)
|
||||
rubocop-rspec (1.15.1)
|
||||
rubocop (>= 0.42.0)
|
||||
ruby-fogbugz (0.2.1)
|
||||
crack (~> 0.4)
|
||||
|
@ -868,7 +870,7 @@ GEM
|
|||
unf (0.1.4)
|
||||
unf_ext
|
||||
unf_ext (0.0.7.2)
|
||||
unicode-display_width (1.1.3)
|
||||
unicode-display_width (1.3.0)
|
||||
unicorn (5.1.0)
|
||||
kgio (~> 2.6)
|
||||
raindrops (~> 0.7)
|
||||
|
@ -1078,8 +1080,8 @@ DEPENDENCIES
|
|||
rspec-retry (~> 0.4.5)
|
||||
rspec-set (~> 0.1.3)
|
||||
rspec_profiling (~> 0.0.5)
|
||||
rubocop (~> 0.47.1)
|
||||
rubocop-rspec (~> 1.15.0)
|
||||
rubocop (~> 0.49.1)
|
||||
rubocop-rspec (~> 1.15.1)
|
||||
ruby-fogbugz (~> 0.2.1)
|
||||
ruby-prof (~> 0.16.2)
|
||||
ruby_parser (~> 3.8)
|
||||
|
|
20
PROCESS.md
20
PROCESS.md
|
@ -128,7 +128,7 @@ information, see
|
|||
|
||||
### After the 7th
|
||||
|
||||
Once the stable branch is frozen, only fixes for regressions (bugs introduced in that same release)
|
||||
Once the stable branch is frozen, only fixes for [regressions](#regressions)
|
||||
and security issues will be cherry-picked into the stable branch.
|
||||
Any merge requests cherry-picked into the stable branch for a previous release will also be picked into the latest stable branch.
|
||||
These fixes will be shipped in the next RC for that release if it is before the 22nd.
|
||||
|
@ -158,6 +158,24 @@ release should have the correct milestone assigned _and_ have the label
|
|||
Merge requests without a milestone and this label will
|
||||
not be merged into any stable branches.
|
||||
|
||||
### Regressions
|
||||
|
||||
A regression for a particular monthly release is a bug that exists in that
|
||||
release, but wasn't present in the release before. This includes bugs in
|
||||
features that were only added in that monthly release. Every regression **must**
|
||||
have the milestone of the release it was introduced in - if a regression doesn't
|
||||
have a milestone, it might be 'just' a bug!
|
||||
|
||||
For instance, if 10.5.0 adds a feature, and that feature doesn't work correctly,
|
||||
then this is a regression in 10.5. If 10.5.1 then fixes that, but 10.5.3 somehow
|
||||
reintroduces the bug, then this bug is still a regression in 10.5.
|
||||
|
||||
Because GitLab.com runs release candidates of new releases, a regression can be
|
||||
reported in a release before its 'official' release date on the 22nd of the
|
||||
month. When we say 'the most recent monthly release', this can refer to either
|
||||
the version currently running on GitLab.com, or the most recent version
|
||||
available in the package repositories.
|
||||
|
||||
## Release retrospective and kickoff
|
||||
|
||||
### Retrospective
|
||||
|
|
|
@ -8,6 +8,7 @@ import BlobFileDropzone from '../blob/blob_file_dropzone';
|
|||
$(() => {
|
||||
const editBlobForm = $('.js-edit-blob-form');
|
||||
const uploadBlobForm = $('.js-upload-blob-form');
|
||||
const deleteBlobForm = $('.js-delete-blob-form');
|
||||
|
||||
if (editBlobForm.length) {
|
||||
const urlRoot = editBlobForm.data('relative-url-root');
|
||||
|
@ -30,4 +31,8 @@ $(() => {
|
|||
'.btn-upload-file',
|
||||
);
|
||||
}
|
||||
|
||||
if (deleteBlobForm.length) {
|
||||
new NewCommitForm(deleteBlobForm);
|
||||
}
|
||||
});
|
||||
|
|
|
@ -64,7 +64,7 @@ window.Build = (function () {
|
|||
$(window)
|
||||
.off('scroll')
|
||||
.on('scroll', () => {
|
||||
const contentHeight = this.$buildTraceOutput.prop('scrollHeight');
|
||||
const contentHeight = this.$buildTraceOutput.height();
|
||||
if (contentHeight > this.windowSize) {
|
||||
// means the user did not scroll, the content was updated.
|
||||
this.windowSize = contentHeight;
|
||||
|
@ -105,16 +105,17 @@ window.Build = (function () {
|
|||
};
|
||||
|
||||
Build.prototype.canScroll = function () {
|
||||
return document.body.scrollHeight > window.innerHeight;
|
||||
return $(document).height() > $(window).height();
|
||||
};
|
||||
|
||||
Build.prototype.toggleScroll = function () {
|
||||
const currentPosition = document.body.scrollTop;
|
||||
const windowHeight = window.innerHeight;
|
||||
const currentPosition = $(document).scrollTop();
|
||||
const scrollHeight = $(document).height();
|
||||
|
||||
const windowHeight = $(window).height();
|
||||
if (this.canScroll()) {
|
||||
if (currentPosition > 0 &&
|
||||
(document.body.scrollHeight - currentPosition !== windowHeight)) {
|
||||
(scrollHeight - currentPosition !== windowHeight)) {
|
||||
// User is in the middle of the log
|
||||
|
||||
this.toggleDisableButton(this.$scrollTopBtn, false);
|
||||
|
@ -124,7 +125,7 @@ window.Build = (function () {
|
|||
|
||||
this.toggleDisableButton(this.$scrollTopBtn, true);
|
||||
this.toggleDisableButton(this.$scrollBottomBtn, false);
|
||||
} else if (document.body.scrollHeight - currentPosition === windowHeight) {
|
||||
} else if (scrollHeight - currentPosition === windowHeight) {
|
||||
// User is at the bottom of the build log.
|
||||
|
||||
this.toggleDisableButton(this.$scrollTopBtn, false);
|
||||
|
@ -137,7 +138,7 @@ window.Build = (function () {
|
|||
};
|
||||
|
||||
Build.prototype.scrollDown = function () {
|
||||
document.body.scrollTop = document.body.scrollHeight;
|
||||
$(document).scrollTop($(document).height());
|
||||
};
|
||||
|
||||
Build.prototype.scrollToBottom = function () {
|
||||
|
@ -147,7 +148,7 @@ window.Build = (function () {
|
|||
};
|
||||
|
||||
Build.prototype.scrollToTop = function () {
|
||||
document.body.scrollTop = 0;
|
||||
$(document).scrollTop(0);
|
||||
this.hasBeenScrolled = true;
|
||||
this.toggleScroll();
|
||||
};
|
||||
|
@ -178,7 +179,7 @@ window.Build = (function () {
|
|||
this.state = log.state;
|
||||
}
|
||||
|
||||
this.windowSize = this.$buildTraceOutput.prop('scrollHeight');
|
||||
this.windowSize = this.$buildTraceOutput.height();
|
||||
|
||||
if (log.append) {
|
||||
this.$buildTraceOutput.append(log.html);
|
||||
|
|
|
@ -8,6 +8,8 @@
|
|||
/* global LabelsSelect */
|
||||
/* global MilestoneSelect */
|
||||
/* global Commit */
|
||||
/* global CommitsList */
|
||||
/* global NewBranchForm */
|
||||
/* global NotificationsForm */
|
||||
/* global NotificationsDropdown */
|
||||
/* global GroupAvatar */
|
||||
|
@ -18,15 +20,20 @@
|
|||
/* global Search */
|
||||
/* global Admin */
|
||||
/* global NamespaceSelects */
|
||||
/* global NewCommitForm */
|
||||
/* global NewBranchForm */
|
||||
/* global Project */
|
||||
/* global ProjectAvatar */
|
||||
/* global MergeRequest */
|
||||
/* global Compare */
|
||||
/* global CompareAutocomplete */
|
||||
/* global ProjectFindFile */
|
||||
/* global ProjectNew */
|
||||
/* global ProjectShow */
|
||||
/* global ProjectImport */
|
||||
/* global Labels */
|
||||
/* global Shortcuts */
|
||||
/* global ShortcutsFindFile */
|
||||
/* global Sidebar */
|
||||
/* global ShortcutsWiki */
|
||||
|
||||
|
@ -194,7 +201,6 @@ import GpgBadges from './gpg_badges';
|
|||
break;
|
||||
case 'explore:groups:index':
|
||||
new GroupsList();
|
||||
|
||||
const landingElement = document.querySelector('.js-explore-groups-landing');
|
||||
if (!landingElement) break;
|
||||
const exploreGroupsLanding = new Landing(
|
||||
|
@ -217,6 +223,10 @@ import GpgBadges from './gpg_badges';
|
|||
case 'projects:compare:show':
|
||||
new gl.Diff();
|
||||
break;
|
||||
case 'projects:branches:new':
|
||||
case 'projects:branches:create':
|
||||
new NewBranchForm($('.js-create-branch-form'), JSON.parse(document.getElementById('availableRefs').innerHTML));
|
||||
break;
|
||||
case 'projects:branches:index':
|
||||
gl.AjaxLoadingSpinner.init();
|
||||
new DeleteModal();
|
||||
|
@ -258,7 +268,7 @@ import GpgBadges from './gpg_badges';
|
|||
case 'projects:tags:new':
|
||||
new ZenMode();
|
||||
new gl.GLForm($('.tag-form'), true);
|
||||
new RefSelectDropdown($('.js-branch-select'), window.gl.availableRefs);
|
||||
new RefSelectDropdown($('.js-branch-select'));
|
||||
break;
|
||||
case 'projects:snippets:show':
|
||||
initNotes();
|
||||
|
@ -304,19 +314,24 @@ import GpgBadges from './gpg_badges';
|
|||
container: '.js-commit-pipeline-graph',
|
||||
}).bindEvents();
|
||||
initNotes();
|
||||
$('.commit-info.branches').load(document.querySelector('.js-commit-box').dataset.commitPath);
|
||||
break;
|
||||
case 'projects:commit:pipelines':
|
||||
new MiniPipelineGraph({
|
||||
container: '.js-commit-pipeline-graph',
|
||||
}).bindEvents();
|
||||
break;
|
||||
case 'projects:commits:show':
|
||||
shortcut_handler = new ShortcutsNavigation();
|
||||
GpgBadges.fetch();
|
||||
$('.commit-info.branches').load(document.querySelector('.js-commit-box').dataset.commitPath);
|
||||
break;
|
||||
case 'projects:activity':
|
||||
new gl.Activities();
|
||||
shortcut_handler = new ShortcutsNavigation();
|
||||
break;
|
||||
case 'projects:commits:show':
|
||||
CommitsList.init(document.querySelector('.js-project-commits-show').dataset.commitsLimit);
|
||||
new gl.Activities();
|
||||
shortcut_handler = new ShortcutsNavigation();
|
||||
GpgBadges.fetch();
|
||||
break;
|
||||
case 'projects:show':
|
||||
shortcut_handler = new ShortcutsNavigation();
|
||||
new NotificationsForm();
|
||||
|
@ -330,6 +345,12 @@ import GpgBadges from './gpg_badges';
|
|||
case 'projects:edit':
|
||||
setupProjectEdit();
|
||||
break;
|
||||
case 'projects:imports:show':
|
||||
new ProjectImport();
|
||||
break;
|
||||
case 'projects:pipelines:new':
|
||||
new NewBranchForm($('.js-new-pipeline-form'));
|
||||
break;
|
||||
case 'projects:pipelines:builds':
|
||||
case 'projects:pipelines:failures':
|
||||
case 'projects:pipelines:show':
|
||||
|
@ -383,8 +404,19 @@ import GpgBadges from './gpg_badges';
|
|||
shortcut_handler = new ShortcutsNavigation();
|
||||
new TreeView();
|
||||
new BlobViewer();
|
||||
new NewCommitForm($('.js-create-dir-form'));
|
||||
$('#tree-slider').waitForImages(function() {
|
||||
gl.utils.ajaxGet(document.querySelector('.js-tree-content').dataset.logsPath);
|
||||
});
|
||||
break;
|
||||
case 'projects:find_file:show':
|
||||
const findElement = document.querySelector('.js-file-finder');
|
||||
const projectFindFile = new ProjectFindFile($(".file-finder-holder"), {
|
||||
url: findElement.dataset.fileFindUrl,
|
||||
treeUrl: findElement.dataset.findTreeUrl,
|
||||
blobUrlTemplate: findElement.dataset.blobUrlTemplate,
|
||||
});
|
||||
new ShortcutsFindFile(projectFindFile);
|
||||
shortcut_handler = true;
|
||||
break;
|
||||
case 'projects:blob:show':
|
||||
|
@ -540,6 +572,7 @@ import GpgBadges from './gpg_badges';
|
|||
shortcut_handler = new ShortcutsWiki();
|
||||
new ZenMode();
|
||||
new gl.GLForm($('.wiki-form'), true);
|
||||
new Sidebar();
|
||||
break;
|
||||
case 'snippets':
|
||||
shortcut_handler = new ShortcutsNavigation();
|
||||
|
|
|
@ -730,10 +730,10 @@ GitLabDropdown = (function() {
|
|||
|
||||
GitLabDropdown.prototype.focusTextInput = function(triggerFocus = false) {
|
||||
if (this.options.filterable) {
|
||||
$(':focus').blur();
|
||||
|
||||
this.dropdown.one('transitionend', () => {
|
||||
this.filterInput.focus();
|
||||
if (this.dropdown.is('.open')) {
|
||||
this.filterInput.focus();
|
||||
}
|
||||
});
|
||||
|
||||
if (triggerFocus) {
|
||||
|
|
|
@ -1,6 +1,4 @@
|
|||
import Chart from 'vendor/Chart';
|
||||
import ContributorsStatGraph from './stat_graph_contributors';
|
||||
|
||||
// export to global scope
|
||||
window.Chart = Chart;
|
||||
window.ContributorsStatGraph = ContributorsStatGraph;
|
||||
|
|
63
app/assets/javascripts/graphs/graphs_charts.js
Normal file
63
app/assets/javascripts/graphs/graphs_charts.js
Normal 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);
|
||||
});
|
21
app/assets/javascripts/graphs/graphs_show.js
Normal file
21
app/assets/javascripts/graphs/graphs_show.js
Normal 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();
|
||||
},
|
||||
});
|
||||
});
|
38
app/assets/javascripts/pipelines/pipelines_charts.js
Normal file
38
app/assets/javascripts/pipelines/pipelines_charts.js
Normal 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));
|
||||
});
|
27
app/assets/javascripts/pipelines/pipelines_times.js
Normal file
27
app/assets/javascripts/pipelines/pipelines_times.js
Normal 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);
|
||||
});
|
85
app/assets/javascripts/projects/project_new.js
Normal file
85
app/assets/javascripts/projects/project_new.js
Normal 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,
|
||||
};
|
|
@ -1,7 +1,8 @@
|
|||
class RefSelectDropdown {
|
||||
constructor($dropdownButton, availableRefs) {
|
||||
const availableRefsValue = availableRefs || JSON.parse(document.getElementById('availableRefs').innerHTML);
|
||||
$dropdownButton.glDropdown({
|
||||
data: availableRefs,
|
||||
data: availableRefsValue,
|
||||
filterable: true,
|
||||
filterByText: true,
|
||||
remote: false,
|
||||
|
|
13
app/assets/javascripts/two_factor_auth.js
Normal file
13
app/assets/javascripts/two_factor_auth.js
Normal 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();
|
||||
});
|
22
app/assets/javascripts/ui_development_kit.js
Normal file
22
app/assets/javascripts/ui_development_kit.js
Normal 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),
|
||||
});
|
||||
});
|
|
@ -88,6 +88,10 @@
|
|||
overflow: hidden;
|
||||
display: flex;
|
||||
|
||||
a {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.avatar {
|
||||
border-radius: 0;
|
||||
border: none;
|
||||
|
|
|
@ -414,13 +414,16 @@
|
|||
background-color: $dropdown-hover-color;
|
||||
color: $white-light;
|
||||
text-decoration: none;
|
||||
outline: 0;
|
||||
|
||||
.avatar {
|
||||
border-color: $white-light;
|
||||
}
|
||||
}
|
||||
|
||||
.filter-dropdown-item {
|
||||
.droplab-dropdown .dropdown-menu .filter-dropdown-item {
|
||||
padding: 0;
|
||||
|
||||
.btn {
|
||||
border: none;
|
||||
width: 100%;
|
||||
|
@ -455,14 +458,11 @@
|
|||
}
|
||||
|
||||
.dropdown-user {
|
||||
display: -webkit-flex;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.dropdown-user-details {
|
||||
display: -webkit-flex;
|
||||
display: flex;
|
||||
-webkit-flex-direction: column;
|
||||
flex-direction: column;
|
||||
|
||||
> span {
|
||||
|
|
|
@ -313,6 +313,29 @@ header {
|
|||
.impersonation i {
|
||||
color: $red-500;
|
||||
}
|
||||
|
||||
// TODO: fallback to global style
|
||||
.dropdown-menu,
|
||||
.dropdown-menu-nav {
|
||||
li {
|
||||
padding: 0 1px;
|
||||
|
||||
a {
|
||||
border-radius: 0;
|
||||
padding: 8px 16px;
|
||||
|
||||
&:hover,
|
||||
&:active,
|
||||
&:focus {
|
||||
background-color: $gray-darker;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.with-performance-bar header.navbar-gitlab {
|
||||
top: $performance-bar-height;
|
||||
}
|
||||
|
||||
.navbar-nav {
|
||||
|
|
|
@ -120,3 +120,7 @@ of the body element here, we negate cascading side effects but allow momentum sc
|
|||
.page-with-sidebar {
|
||||
-webkit-overflow-scrolling: auto;
|
||||
}
|
||||
|
||||
.with-performance-bar .page-with-sidebar {
|
||||
margin-top: $header-height + $performance-bar-height;
|
||||
}
|
||||
|
|
|
@ -347,6 +347,10 @@
|
|||
}
|
||||
}
|
||||
|
||||
.with-performance-bar .layout-nav {
|
||||
margin-top: $header-height + $performance-bar-height;
|
||||
}
|
||||
|
||||
.scrolling-tabs-container {
|
||||
position: relative;
|
||||
|
||||
|
@ -441,6 +445,22 @@
|
|||
}
|
||||
}
|
||||
|
||||
.with-performance-bar .page-with-layout-nav {
|
||||
.right-sidebar {
|
||||
top: ($header-height + 1) * 2 + $performance-bar-height;
|
||||
}
|
||||
|
||||
&.page-with-sub-nav {
|
||||
.right-sidebar {
|
||||
top: ($header-height + 1) * 3 + $performance-bar-height;
|
||||
|
||||
&.affix {
|
||||
top: $header-height + $performance-bar-height;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.nav-block {
|
||||
&.activities {
|
||||
border-bottom: 1px solid $border-color;
|
||||
|
|
|
@ -89,6 +89,10 @@
|
|||
}
|
||||
}
|
||||
|
||||
.with-performance-bar .right-sidebar.affix {
|
||||
top: $header-height + $performance-bar-height;
|
||||
}
|
||||
|
||||
@mixin maintain-sidebar-dimensions {
|
||||
display: block;
|
||||
width: $gutter-width;
|
||||
|
|
|
@ -204,6 +204,7 @@ $divergence-graph-separator-bg: #ccc;
|
|||
$general-hover-transition-duration: 100ms;
|
||||
$general-hover-transition-curve: linear;
|
||||
$highlight-changes-color: rgb(235, 255, 232);
|
||||
$performance-bar-height: 35px;
|
||||
|
||||
|
||||
/*
|
||||
|
|
|
@ -309,6 +309,25 @@ header.navbar-gitlab-new {
|
|||
outline: 0;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: fallback to global style
|
||||
.dropdown-menu {
|
||||
li {
|
||||
padding: 0 1px;
|
||||
|
||||
a {
|
||||
border-radius: 0;
|
||||
padding: 8px 16px;
|
||||
|
||||
&.is-focused,
|
||||
&:hover,
|
||||
&:active,
|
||||
&:focus {
|
||||
background-color: $gray-darker;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.breadcrumbs-container {
|
||||
|
@ -325,6 +344,7 @@ header.navbar-gitlab-new {
|
|||
|
||||
.breadcrumbs-links {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
align-self: center;
|
||||
color: $gl-text-color-quaternary;
|
||||
|
||||
|
@ -343,7 +363,7 @@ header.navbar-gitlab-new {
|
|||
}
|
||||
|
||||
.title {
|
||||
white-space: nowrap;
|
||||
display: inline-block;
|
||||
|
||||
> a {
|
||||
&:last-of-type:not(:first-child) {
|
||||
|
|
|
@ -118,7 +118,7 @@ $new-sidebar-width: 220px;
|
|||
z-index: 400;
|
||||
width: $new-sidebar-width;
|
||||
transition: left $sidebar-transition-duration;
|
||||
top: 50px;
|
||||
top: $header-height;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
overflow: auto;
|
||||
|
@ -163,6 +163,10 @@ $new-sidebar-width: 220px;
|
|||
}
|
||||
}
|
||||
|
||||
.with-performance-bar .nav-sidebar {
|
||||
top: $header-height + $performance-bar-height;
|
||||
}
|
||||
|
||||
.sidebar-sub-level-items {
|
||||
display: none;
|
||||
padding-bottom: 8px;
|
||||
|
@ -260,7 +264,7 @@ $new-sidebar-width: 220px;
|
|||
// Make issue boards full-height now that sub-nav is gone
|
||||
|
||||
.boards-list {
|
||||
height: calc(100vh - 50px);
|
||||
height: calc(100vh - #{$header-height});
|
||||
|
||||
@media (min-width: $screen-sm-min) {
|
||||
height: 475px; // Needed for PhantomJS
|
||||
|
@ -270,6 +274,10 @@ $new-sidebar-width: 220px;
|
|||
}
|
||||
}
|
||||
|
||||
.with-performance-bar .boards-list {
|
||||
height: calc(100vh - #{$header-height} - #{$performance-bar-height});
|
||||
}
|
||||
|
||||
|
||||
// Change color of all horizontal tabs to match the new indigo color
|
||||
.nav-links li.active a {
|
||||
|
|
|
@ -64,10 +64,10 @@
|
|||
color: $gl-text-color;
|
||||
position: sticky;
|
||||
position: -webkit-sticky;
|
||||
top: 50px;
|
||||
top: $header-height;
|
||||
|
||||
&.affix {
|
||||
top: 50px;
|
||||
top: $header-height;
|
||||
}
|
||||
|
||||
// with sidebar
|
||||
|
@ -86,6 +86,7 @@
|
|||
position: absolute;
|
||||
right: 0;
|
||||
left: 0;
|
||||
top: 0;
|
||||
}
|
||||
|
||||
.truncated-info {
|
||||
|
@ -171,6 +172,16 @@
|
|||
}
|
||||
}
|
||||
|
||||
.with-performance-bar .build-page {
|
||||
.top-bar {
|
||||
top: $header-height + $performance-bar-height;
|
||||
|
||||
&.affix {
|
||||
top: $header-height + $performance-bar-height;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.build-header {
|
||||
.ci-header-container,
|
||||
.header-action-buttons {
|
||||
|
@ -300,9 +311,7 @@
|
|||
}
|
||||
|
||||
.dropdown-menu {
|
||||
right: $gl-padding;
|
||||
left: $gl-padding;
|
||||
width: auto;
|
||||
margin-top: -$gl-padding;
|
||||
}
|
||||
|
||||
svg {
|
||||
|
|
|
@ -110,6 +110,10 @@
|
|||
|
||||
.js-ca-dropdown {
|
||||
top: $gl-padding-top;
|
||||
|
||||
.dropdown-menu-align-right {
|
||||
margin-top: 2px;
|
||||
}
|
||||
}
|
||||
|
||||
.content-list {
|
||||
|
@ -442,6 +446,24 @@
|
|||
margin-bottom: 20px;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: fallback to global style
|
||||
.dropdown-menu {
|
||||
li {
|
||||
padding: 0 1px;
|
||||
|
||||
a {
|
||||
border-radius: 0;
|
||||
padding: 8px 16px;
|
||||
|
||||
&:hover,
|
||||
&:active,
|
||||
&:focus {
|
||||
background-color: $gray-darker;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.cycle-analytics-overview {
|
||||
|
|
|
@ -445,6 +445,14 @@
|
|||
}
|
||||
}
|
||||
|
||||
.with-performance-bar .right-sidebar {
|
||||
top: $header-height + $performance-bar-height;
|
||||
|
||||
.issuable-sidebar {
|
||||
height: calc(100% - #{$header-height} - #{$performance-bar-height});
|
||||
}
|
||||
}
|
||||
|
||||
.detail-page-description {
|
||||
padding: 16px 0;
|
||||
|
||||
|
|
|
@ -759,6 +759,10 @@
|
|||
}
|
||||
}
|
||||
|
||||
.with-performance-bar .merge-request-tabs-holder {
|
||||
top: $header-height + $performance-bar-height;
|
||||
}
|
||||
|
||||
.merge-request-tabs {
|
||||
display: flex;
|
||||
margin-bottom: 0;
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -3,9 +3,16 @@
|
|||
@import "peek/views/rblineprof";
|
||||
|
||||
#peek {
|
||||
height: 35px;
|
||||
position: fixed;
|
||||
left: 0;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
z-index: 2000;
|
||||
overflow-x: hidden;
|
||||
|
||||
height: $performance-bar-height;
|
||||
background: $black;
|
||||
line-height: 35px;
|
||||
line-height: $performance-bar-height;
|
||||
color: $perf-bar-text;
|
||||
|
||||
&.disabled {
|
||||
|
@ -25,7 +32,8 @@
|
|||
}
|
||||
|
||||
.wrapper {
|
||||
width: 1000px;
|
||||
width: 80%;
|
||||
height: $performance-bar-height;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
|
|
|
@ -43,23 +43,7 @@ class Projects::GraphsController < Projects::ApplicationController
|
|||
end
|
||||
|
||||
def get_languages
|
||||
@languages = Linguist::Repository.new(@repository.rugged, @repository.rugged.head.target_id).languages
|
||||
total = @languages.map(&:last).sum
|
||||
|
||||
@languages = @languages.map do |language|
|
||||
name, share = language
|
||||
color = Linguist::Language[name].color || "##{Digest::SHA256.hexdigest(name)[0...6]}"
|
||||
{
|
||||
value: (share.to_f * 100 / total).round(2),
|
||||
label: name,
|
||||
color: color,
|
||||
highlight: color
|
||||
}
|
||||
end
|
||||
|
||||
@languages.sort! do |x, y|
|
||||
y[:value] <=> x[:value]
|
||||
end
|
||||
@languages = @project.repository.languages
|
||||
end
|
||||
|
||||
def fetch_graph
|
||||
|
|
|
@ -264,7 +264,11 @@ module ApplicationHelper
|
|||
end
|
||||
|
||||
def page_class
|
||||
"issue-boards-page" if current_controller?(:boards)
|
||||
class_names = []
|
||||
class_names << 'issue-boards-page' if current_controller?(:boards)
|
||||
class_names << 'with-performance-bar' if performance_bar_enabled?
|
||||
|
||||
class_names
|
||||
end
|
||||
|
||||
# Returns active css class when condition returns true
|
||||
|
|
|
@ -48,7 +48,11 @@ module GitlabRoutingHelper
|
|||
end
|
||||
|
||||
def milestone_path(entity, *args)
|
||||
project_milestone_path(entity.project, entity, *args)
|
||||
if entity.is_group_milestone?
|
||||
group_milestone_path(entity.group, entity, *args)
|
||||
elsif entity.is_project_milestone?
|
||||
project_milestone_path(entity.project, entity, *args)
|
||||
end
|
||||
end
|
||||
|
||||
def issue_url(entity, *args)
|
||||
|
@ -63,6 +67,14 @@ module GitlabRoutingHelper
|
|||
project_pipeline_url(pipeline.project, pipeline.id, *args)
|
||||
end
|
||||
|
||||
def milestone_url(entity, *args)
|
||||
if entity.is_group_milestone?
|
||||
group_milestone_url(entity.group, entity, *args)
|
||||
elsif entity.is_project_milestone?
|
||||
project_milestone_url(entity.project, entity, *args)
|
||||
end
|
||||
end
|
||||
|
||||
def pipeline_job_url(pipeline, build, *args)
|
||||
project_job_url(pipeline.project, build.id, *args)
|
||||
end
|
||||
|
|
|
@ -40,7 +40,7 @@ module MergeRequestsHelper
|
|||
|
||||
def merge_path_description(merge_request, separator)
|
||||
if merge_request.for_fork?
|
||||
"Project:Branches: #{@merge_request.source_project_path}:#{@merge_request.source_branch} #{separator} #{@merge_request.target_project.path_with_namespace}:#{@merge_request.target_branch}"
|
||||
"Project:Branches: #{@merge_request.source_project_path}:#{@merge_request.source_branch} #{separator} #{@merge_request.target_project.full_path}:#{@merge_request.target_branch}"
|
||||
else
|
||||
"Branches: #{@merge_request.source_branch} #{separator} #{@merge_request.target_branch}"
|
||||
end
|
||||
|
|
|
@ -1,38 +1,49 @@
|
|||
module NavHelper
|
||||
def page_with_sidebar_class
|
||||
class_name = page_gutter_class
|
||||
class_name << 'page-with-new-sidebar' if defined?(@new_sidebar) && @new_sidebar
|
||||
|
||||
class_name
|
||||
end
|
||||
|
||||
def page_gutter_class
|
||||
if current_path?('merge_requests#show') ||
|
||||
current_path?('projects/merge_requests/conflicts#show') ||
|
||||
current_path?('issues#show') ||
|
||||
current_path?('milestones#show')
|
||||
if cookies[:collapsed_gutter] == 'true'
|
||||
"page-gutter right-sidebar-collapsed"
|
||||
%w[page-gutter right-sidebar-collapsed]
|
||||
else
|
||||
"page-gutter right-sidebar-expanded"
|
||||
%w[page-gutter right-sidebar-expanded]
|
||||
end
|
||||
elsif current_path?('jobs#show')
|
||||
"page-gutter build-sidebar right-sidebar-expanded"
|
||||
%w[page-gutter build-sidebar right-sidebar-expanded]
|
||||
elsif current_path?('wikis#show') ||
|
||||
current_path?('wikis#edit') ||
|
||||
current_path?('wikis#update') ||
|
||||
current_path?('wikis#history') ||
|
||||
current_path?('wikis#git_access')
|
||||
"page-gutter wiki-sidebar right-sidebar-expanded"
|
||||
%w[page-gutter wiki-sidebar right-sidebar-expanded]
|
||||
else
|
||||
[]
|
||||
end
|
||||
end
|
||||
|
||||
def nav_header_class
|
||||
class_name = ''
|
||||
class_name << " with-horizontal-nav" if defined?(nav) && nav
|
||||
class_names = []
|
||||
class_names << 'with-horizontal-nav' if defined?(nav) && nav
|
||||
|
||||
class_name
|
||||
class_names
|
||||
end
|
||||
|
||||
def layout_nav_class
|
||||
class_name = ''
|
||||
class_name << " page-with-layout-nav" if defined?(nav) && nav
|
||||
class_name << " page-with-sub-nav" if content_for?(:sub_nav)
|
||||
return [] if show_new_nav?
|
||||
|
||||
class_name
|
||||
class_names = []
|
||||
class_names << 'page-with-layout-nav' if defined?(nav) && nav
|
||||
class_names << 'page-with-sub-nav' if content_for?(:sub_nav)
|
||||
|
||||
class_names
|
||||
end
|
||||
|
||||
def nav_control_class
|
||||
|
|
|
@ -398,7 +398,7 @@ module ProjectsHelper
|
|||
if project
|
||||
import_path = "/Home/Stacks/import"
|
||||
|
||||
repo = project.path_with_namespace
|
||||
repo = project.full_path
|
||||
branch ||= project.default_branch
|
||||
sha ||= project.commit.short_id
|
||||
|
||||
|
@ -458,7 +458,7 @@ module ProjectsHelper
|
|||
|
||||
def readme_cache_key
|
||||
sha = @project.commit.try(:sha) || 'nil'
|
||||
[@project.path_with_namespace, sha, "readme"].join('-')
|
||||
[@project.full_path, sha, "readme"].join('-')
|
||||
end
|
||||
|
||||
def current_ref
|
||||
|
|
|
@ -34,6 +34,8 @@ module WebpackHelper
|
|||
end
|
||||
|
||||
def webpack_public_path
|
||||
"#{webpack_public_host}/#{Rails.application.config.webpack.public_path}/"
|
||||
relative_path = Rails.application.config.relative_url_root
|
||||
webpack_path = Rails.application.config.webpack.public_path
|
||||
File.join(webpack_public_host.to_s, relative_path.to_s, webpack_path.to_s, '')
|
||||
end
|
||||
end
|
||||
|
|
|
@ -165,7 +165,7 @@ class Notify < BaseMailer
|
|||
|
||||
headers['X-GitLab-Project'] = @project.name
|
||||
headers['X-GitLab-Project-Id'] = @project.id
|
||||
headers['X-GitLab-Project-Path'] = @project.path_with_namespace
|
||||
headers['X-GitLab-Project-Path'] = @project.full_path
|
||||
end
|
||||
|
||||
def add_unsubscription_headers_and_links
|
||||
|
|
|
@ -317,7 +317,7 @@ module Ci
|
|||
return @config_processor if defined?(@config_processor)
|
||||
|
||||
@config_processor ||= begin
|
||||
Ci::GitlabCiYamlProcessor.new(ci_yaml_file, project.path_with_namespace)
|
||||
Ci::GitlabCiYamlProcessor.new(ci_yaml_file, project.full_path)
|
||||
rescue Ci::GitlabCiYamlProcessor::ValidationError, Psych::SyntaxError => e
|
||||
self.yaml_errors = e.message
|
||||
nil
|
||||
|
|
102
app/models/concerns/storage/legacy_namespace.rb
Normal file
102
app/models/concerns/storage/legacy_namespace.rb
Normal 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
|
76
app/models/concerns/storage/legacy_project.rb
Normal file
76
app/models/concerns/storage/legacy_project.rb
Normal 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
|
9
app/models/concerns/storage/legacy_project_wiki.rb
Normal file
9
app/models/concerns/storage/legacy_project_wiki.rb
Normal file
|
@ -0,0 +1,9 @@
|
|||
module Storage
|
||||
module LegacyProjectWiki
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
def disk_path
|
||||
project.disk_path + '.wiki'
|
||||
end
|
||||
end
|
||||
end
|
7
app/models/concerns/storage/legacy_repository.rb
Normal file
7
app/models/concerns/storage/legacy_repository.rb
Normal file
|
@ -0,0 +1,7 @@
|
|||
module Storage
|
||||
module LegacyRepository
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
delegate :disk_path, to: :project
|
||||
end
|
||||
end
|
|
@ -630,7 +630,7 @@ class MergeRequest < ActiveRecord::Base
|
|||
|
||||
def target_project_path
|
||||
if target_project
|
||||
target_project.path_with_namespace
|
||||
target_project.full_path
|
||||
else
|
||||
"(removed)"
|
||||
end
|
||||
|
@ -638,7 +638,7 @@ class MergeRequest < ActiveRecord::Base
|
|||
|
||||
def source_project_path
|
||||
if source_project
|
||||
source_project.path_with_namespace
|
||||
source_project.full_path
|
||||
else
|
||||
"(removed)"
|
||||
end
|
||||
|
|
|
@ -8,6 +8,7 @@ class Namespace < ActiveRecord::Base
|
|||
include Gitlab::VisibilityLevel
|
||||
include Routable
|
||||
include AfterCommitQueue
|
||||
include Storage::LegacyNamespace
|
||||
|
||||
# Prevent users from creating unreasonably deep level of nesting.
|
||||
# The number 20 was taken based on maximum nesting level of
|
||||
|
@ -41,10 +42,11 @@ class Namespace < ActiveRecord::Base
|
|||
|
||||
delegate :name, to: :owner, allow_nil: true, prefix: true
|
||||
|
||||
after_update :move_dir, if: :path_changed?
|
||||
after_commit :refresh_access_of_projects_invited_groups, on: :update, if: -> { previous_changes.key?('share_with_group_lock') }
|
||||
|
||||
# Save the storage paths before the projects are destroyed to use them on after destroy
|
||||
# Legacy Storage specific hooks
|
||||
|
||||
after_update :move_dir, if: :path_changed?
|
||||
before_destroy(prepend: true) { prepare_for_destroy }
|
||||
after_destroy :rm_dir
|
||||
|
||||
|
@ -118,43 +120,6 @@ class Namespace < ActiveRecord::Base
|
|||
owner_name
|
||||
end
|
||||
|
||||
def move_dir
|
||||
if any_project_has_container_registry_tags?
|
||||
raise Gitlab::UpdatePathError.new('Namespace cannot be moved, because at least one project has tags in container registry')
|
||||
end
|
||||
|
||||
# Move the namespace directory in all storages paths used by member projects
|
||||
repository_storage_paths.each do |repository_storage_path|
|
||||
# Ensure old directory exists before moving it
|
||||
gitlab_shell.add_namespace(repository_storage_path, full_path_was)
|
||||
|
||||
unless gitlab_shell.mv_namespace(repository_storage_path, full_path_was, full_path)
|
||||
Rails.logger.error "Exception moving path #{repository_storage_path} from #{full_path_was} to #{full_path}"
|
||||
|
||||
# if we cannot move namespace directory we should rollback
|
||||
# db changes in order to prevent out of sync between db and fs
|
||||
raise Gitlab::UpdatePathError.new('namespace directory cannot be moved')
|
||||
end
|
||||
end
|
||||
|
||||
Gitlab::UploadsTransfer.new.rename_namespace(full_path_was, full_path)
|
||||
Gitlab::PagesTransfer.new.rename_namespace(full_path_was, full_path)
|
||||
|
||||
remove_exports!
|
||||
|
||||
# If repositories moved successfully we need to
|
||||
# send update instructions to users.
|
||||
# However we cannot allow rollback since we moved namespace dir
|
||||
# So we basically we mute exceptions in next actions
|
||||
begin
|
||||
send_update_instructions
|
||||
rescue
|
||||
# Returning false does not rollback after_* transaction but gives
|
||||
# us information about failing some of tasks
|
||||
false
|
||||
end
|
||||
end
|
||||
|
||||
def any_project_has_container_registry_tags?
|
||||
all_projects.any?(&:has_container_registry_tags?)
|
||||
end
|
||||
|
@ -206,14 +171,6 @@ class Namespace < ActiveRecord::Base
|
|||
parent_id_changed?
|
||||
end
|
||||
|
||||
def prepare_for_destroy
|
||||
old_repository_storage_paths
|
||||
end
|
||||
|
||||
def old_repository_storage_paths
|
||||
@old_repository_storage_paths ||= repository_storage_paths
|
||||
end
|
||||
|
||||
# Includes projects from this namespace and projects from all subgroups
|
||||
# that belongs to this namespace
|
||||
def all_projects
|
||||
|
@ -232,37 +189,6 @@ class Namespace < ActiveRecord::Base
|
|||
|
||||
private
|
||||
|
||||
def repository_storage_paths
|
||||
# We need to get the storage paths for all the projects, even the ones that are
|
||||
# pending delete. Unscoping also get rids of the default order, which causes
|
||||
# problems with SELECT DISTINCT.
|
||||
Project.unscoped do
|
||||
all_projects.select('distinct(repository_storage)').to_a.map(&:repository_storage_path)
|
||||
end
|
||||
end
|
||||
|
||||
def rm_dir
|
||||
# Remove the namespace directory in all storages paths used by member projects
|
||||
old_repository_storage_paths.each do |repository_storage_path|
|
||||
# Move namespace directory into trash.
|
||||
# We will remove it later async
|
||||
new_path = "#{full_path}+#{id}+deleted"
|
||||
|
||||
if gitlab_shell.mv_namespace(repository_storage_path, full_path, new_path)
|
||||
message = "Namespace directory \"#{full_path}\" moved to \"#{new_path}\""
|
||||
Gitlab::AppLogger.info message
|
||||
|
||||
# Remove namespace directroy async with delay so
|
||||
# GitLab has time to remove all projects first
|
||||
run_after_commit do
|
||||
GitlabShellWorker.perform_in(5.minutes, :rm_namespace, repository_storage_path, new_path)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
remove_exports!
|
||||
end
|
||||
|
||||
def refresh_access_of_projects_invited_groups
|
||||
Group
|
||||
.joins(project_group_links: :project)
|
||||
|
@ -270,22 +196,6 @@ class Namespace < ActiveRecord::Base
|
|||
.find_each(&:refresh_members_authorized_projects)
|
||||
end
|
||||
|
||||
def remove_exports!
|
||||
Gitlab::Popen.popen(%W(find #{export_path} -not -path #{export_path} -delete))
|
||||
end
|
||||
|
||||
def export_path
|
||||
File.join(Gitlab::ImportExport.storage_path, full_path_was)
|
||||
end
|
||||
|
||||
def full_path_was
|
||||
if parent
|
||||
parent.full_path + '/' + path_was
|
||||
else
|
||||
path_was
|
||||
end
|
||||
end
|
||||
|
||||
def nesting_level_allowed
|
||||
if ancestors.count > Group::NUMBER_OF_ANCESTORS_ALLOWED
|
||||
errors.add(:parent_id, "has too deep level of nesting")
|
||||
|
|
|
@ -1,4 +1,8 @@
|
|||
class NotificationSetting < ActiveRecord::Base
|
||||
include IgnorableColumn
|
||||
|
||||
ignore_column :events
|
||||
|
||||
enum level: { global: 3, watch: 2, mention: 4, participating: 1, disabled: 0, custom: 5 }
|
||||
|
||||
default_value_for :level, NotificationSetting.levels[:global]
|
||||
|
@ -41,9 +45,6 @@ class NotificationSetting < ActiveRecord::Base
|
|||
:success_pipeline
|
||||
].freeze
|
||||
|
||||
store :events, coder: JSON
|
||||
before_save :convert_events
|
||||
|
||||
def self.find_or_create_for(source)
|
||||
setting = find_or_initialize_by(source: source)
|
||||
|
||||
|
@ -54,42 +55,17 @@ class NotificationSetting < ActiveRecord::Base
|
|||
setting
|
||||
end
|
||||
|
||||
# 1. Check if this event has a value stored in its database column.
|
||||
# 2. If it does, return that value.
|
||||
# 3. If it doesn't (the value is nil), return the value from the serialized
|
||||
# JSON hash in `events`.
|
||||
(EMAIL_EVENTS - [:failed_pipeline]).each do |event|
|
||||
define_method(event) do
|
||||
bool = super()
|
||||
|
||||
bool.nil? ? !!events[event] : bool
|
||||
end
|
||||
|
||||
alias_method :"#{event}?", event
|
||||
end
|
||||
|
||||
# Allow people to receive failed pipeline notifications if they already have
|
||||
# custom notifications enabled, as these are more like mentions than the other
|
||||
# custom settings.
|
||||
def failed_pipeline
|
||||
bool = super
|
||||
bool = events[:failed_pipeline] if bool.nil?
|
||||
|
||||
bool.nil? || bool
|
||||
end
|
||||
alias_method :failed_pipeline?, :failed_pipeline
|
||||
|
||||
def event_enabled?(event)
|
||||
respond_to?(event) && public_send(event)
|
||||
end
|
||||
|
||||
def convert_events
|
||||
return if events_before_type_cast.nil?
|
||||
|
||||
EMAIL_EVENTS.each do |event|
|
||||
write_attribute(event, public_send(event))
|
||||
end
|
||||
|
||||
write_attribute(:events, nil)
|
||||
respond_to?(event) && !!public_send(event)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -17,6 +17,7 @@ class Project < ActiveRecord::Base
|
|||
include ProjectFeaturesCompatibility
|
||||
include SelectForProjectAuthorization
|
||||
include Routable
|
||||
include Storage::LegacyProject
|
||||
|
||||
extend Gitlab::ConfigHelper
|
||||
|
||||
|
@ -43,9 +44,8 @@ class Project < ActiveRecord::Base
|
|||
default_value_for :snippets_enabled, gitlab_config_features.snippets
|
||||
default_value_for :only_allow_merge_if_all_discussions_are_resolved, false
|
||||
|
||||
after_create :ensure_dir_exist
|
||||
after_create :ensure_storage_path_exist
|
||||
after_create :create_project_feature, unless: :project_feature
|
||||
after_save :ensure_dir_exist, if: :namespace_id_changed?
|
||||
after_save :update_project_statistics, if: :namespace_id_changed?
|
||||
|
||||
# set last_activity_at to the same as created_at
|
||||
|
@ -67,6 +67,10 @@ class Project < ActiveRecord::Base
|
|||
|
||||
after_validation :check_pending_delete
|
||||
|
||||
# Legacy Storage specific hooks
|
||||
|
||||
after_save :ensure_storage_path_exist, if: :namespace_id_changed?
|
||||
|
||||
acts_as_taggable
|
||||
|
||||
attr_accessor :new_default_branch
|
||||
|
@ -375,7 +379,7 @@ class Project < ActiveRecord::Base
|
|||
begin
|
||||
Projects::HousekeepingService.new(project).execute
|
||||
rescue Projects::HousekeepingService::LeaseTaken => e
|
||||
Rails.logger.info("Could not perform housekeeping for project #{project.path_with_namespace} (#{project.id}): #{e}")
|
||||
Rails.logger.info("Could not perform housekeeping for project #{project.full_path} (#{project.id}): #{e}")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -476,12 +480,12 @@ class Project < ActiveRecord::Base
|
|||
end
|
||||
|
||||
def repository
|
||||
@repository ||= Repository.new(path_with_namespace, self)
|
||||
@repository ||= Repository.new(full_path, self, disk_path: disk_path)
|
||||
end
|
||||
|
||||
def container_registry_url
|
||||
if Gitlab.config.registry.enabled
|
||||
"#{Gitlab.config.registry.host_port}/#{path_with_namespace.downcase}"
|
||||
"#{Gitlab.config.registry.host_port}/#{full_path.downcase}"
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -520,16 +524,16 @@ class Project < ActiveRecord::Base
|
|||
job_id =
|
||||
if forked?
|
||||
RepositoryForkWorker.perform_async(id, forked_from_project.repository_storage_path,
|
||||
forked_from_project.path_with_namespace,
|
||||
forked_from_project.full_path,
|
||||
self.namespace.full_path)
|
||||
else
|
||||
RepositoryImportWorker.perform_async(self.id)
|
||||
end
|
||||
|
||||
if job_id
|
||||
Rails.logger.info "Import job started for #{path_with_namespace} with job ID #{job_id}"
|
||||
Rails.logger.info "Import job started for #{full_path} with job ID #{job_id}"
|
||||
else
|
||||
Rails.logger.error "Import job failed to start for #{path_with_namespace}"
|
||||
Rails.logger.error "Import job failed to start for #{full_path}"
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -690,7 +694,7 @@ class Project < ActiveRecord::Base
|
|||
# `from` argument can be a Namespace or Project.
|
||||
def to_reference(from = nil, full: false)
|
||||
if full || cross_namespace_reference?(from)
|
||||
path_with_namespace
|
||||
full_path
|
||||
elsif cross_project_reference?(from)
|
||||
path
|
||||
end
|
||||
|
@ -714,7 +718,7 @@ class Project < ActiveRecord::Base
|
|||
author.ensure_incoming_email_token!
|
||||
|
||||
Gitlab::IncomingEmail.reply_address(
|
||||
"#{path_with_namespace}+#{author.incoming_email_token}")
|
||||
"#{full_path}+#{author.incoming_email_token}")
|
||||
end
|
||||
|
||||
def build_commit_note(commit)
|
||||
|
@ -941,7 +945,7 @@ class Project < ActiveRecord::Base
|
|||
end
|
||||
|
||||
def url_to_repo
|
||||
gitlab_shell.url_to_repo(path_with_namespace)
|
||||
gitlab_shell.url_to_repo(full_path)
|
||||
end
|
||||
|
||||
def repo_exists?
|
||||
|
@ -974,56 +978,6 @@ class Project < ActiveRecord::Base
|
|||
!group
|
||||
end
|
||||
|
||||
def rename_repo
|
||||
path_was = previous_changes['path'].first
|
||||
old_path_with_namespace = File.join(namespace.full_path, path_was)
|
||||
new_path_with_namespace = File.join(namespace.full_path, path)
|
||||
|
||||
Rails.logger.error "Attempting to rename #{old_path_with_namespace} -> #{new_path_with_namespace}"
|
||||
|
||||
if has_container_registry_tags?
|
||||
Rails.logger.error "Project #{old_path_with_namespace} cannot be renamed because container registry tags are present!"
|
||||
|
||||
# we currently doesn't support renaming repository if it contains images in container registry
|
||||
raise StandardError.new('Project cannot be renamed, because images are present in its container registry')
|
||||
end
|
||||
|
||||
expire_caches_before_rename(old_path_with_namespace)
|
||||
|
||||
if gitlab_shell.mv_repository(repository_storage_path, old_path_with_namespace, new_path_with_namespace)
|
||||
# If repository moved successfully we need to send update instructions to users.
|
||||
# However we cannot allow rollback since we moved repository
|
||||
# So we basically we mute exceptions in next actions
|
||||
begin
|
||||
gitlab_shell.mv_repository(repository_storage_path, "#{old_path_with_namespace}.wiki", "#{new_path_with_namespace}.wiki")
|
||||
send_move_instructions(old_path_with_namespace)
|
||||
expires_full_path_cache
|
||||
|
||||
@old_path_with_namespace = old_path_with_namespace
|
||||
|
||||
SystemHooksService.new.execute_hooks_for(self, :rename)
|
||||
|
||||
@repository = nil
|
||||
rescue => e
|
||||
Rails.logger.error "Exception renaming #{old_path_with_namespace} -> #{new_path_with_namespace}: #{e}"
|
||||
# Returning false does not rollback after_* transaction but gives
|
||||
# us information about failing some of tasks
|
||||
false
|
||||
end
|
||||
else
|
||||
Rails.logger.error "Repository could not be renamed: #{old_path_with_namespace} -> #{new_path_with_namespace}"
|
||||
|
||||
# if we cannot move namespace directory we should rollback
|
||||
# db changes in order to prevent out of sync between db and fs
|
||||
raise StandardError.new('repository cannot be renamed')
|
||||
end
|
||||
|
||||
Gitlab::AppLogger.info "Project was renamed: #{old_path_with_namespace} -> #{new_path_with_namespace}"
|
||||
|
||||
Gitlab::UploadsTransfer.new.rename_project(path_was, path, namespace.full_path)
|
||||
Gitlab::PagesTransfer.new.rename_project(path_was, path, namespace.full_path)
|
||||
end
|
||||
|
||||
# Expires various caches before a project is renamed.
|
||||
def expire_caches_before_rename(old_path)
|
||||
repo = Repository.new(old_path, self)
|
||||
|
@ -1048,7 +1002,7 @@ class Project < ActiveRecord::Base
|
|||
git_http_url: http_url_to_repo,
|
||||
namespace: namespace.name,
|
||||
visibility_level: visibility_level,
|
||||
path_with_namespace: path_with_namespace,
|
||||
path_with_namespace: full_path,
|
||||
default_branch: default_branch,
|
||||
ci_config_path: ci_config_path
|
||||
}
|
||||
|
@ -1109,19 +1063,6 @@ class Project < ActiveRecord::Base
|
|||
merge_requests.where(source_project_id: self.id)
|
||||
end
|
||||
|
||||
def create_repository(force: false)
|
||||
# Forked import is handled asynchronously
|
||||
return if forked? && !force
|
||||
|
||||
if gitlab_shell.add_repository(repository_storage_path, path_with_namespace)
|
||||
repository.after_create
|
||||
true
|
||||
else
|
||||
errors.add(:base, 'Failed to create repository via gitlab-shell')
|
||||
false
|
||||
end
|
||||
end
|
||||
|
||||
def ensure_repository
|
||||
create_repository(force: true) unless repository_exists?
|
||||
end
|
||||
|
@ -1257,7 +1198,7 @@ class Project < ActiveRecord::Base
|
|||
end
|
||||
|
||||
def pages_path
|
||||
File.join(Settings.pages.path, path_with_namespace)
|
||||
File.join(Settings.pages.path, disk_path)
|
||||
end
|
||||
|
||||
def public_pages_path
|
||||
|
@ -1265,9 +1206,21 @@ class Project < ActiveRecord::Base
|
|||
end
|
||||
|
||||
def remove_private_deploy_keys
|
||||
deploy_keys.where(public: false).delete_all
|
||||
exclude_keys_linked_to_other_projects = <<-SQL
|
||||
NOT EXISTS (
|
||||
SELECT 1
|
||||
FROM deploy_keys_projects dkp2
|
||||
WHERE dkp2.deploy_key_id = deploy_keys_projects.deploy_key_id
|
||||
AND dkp2.project_id != deploy_keys_projects.project_id
|
||||
)
|
||||
SQL
|
||||
|
||||
deploy_keys.where(public: false)
|
||||
.where(exclude_keys_linked_to_other_projects)
|
||||
.delete_all
|
||||
end
|
||||
|
||||
# TODO: what to do here when not using Legacy Storage? Do we still need to rename and delay removal?
|
||||
def remove_pages
|
||||
::Projects::UpdatePagesConfigurationService.new(self).execute
|
||||
|
||||
|
@ -1315,7 +1268,7 @@ class Project < ActiveRecord::Base
|
|||
end
|
||||
|
||||
def export_path
|
||||
File.join(Gitlab::ImportExport.storage_path, path_with_namespace)
|
||||
File.join(Gitlab::ImportExport.storage_path, disk_path)
|
||||
end
|
||||
|
||||
def export_project_path
|
||||
|
@ -1327,16 +1280,12 @@ class Project < ActiveRecord::Base
|
|||
status.zero?
|
||||
end
|
||||
|
||||
def ensure_dir_exist
|
||||
gitlab_shell.add_namespace(repository_storage_path, namespace.full_path)
|
||||
end
|
||||
|
||||
def predefined_variables
|
||||
[
|
||||
{ key: 'CI_PROJECT_ID', value: id.to_s, public: true },
|
||||
{ key: 'CI_PROJECT_NAME', value: path, public: true },
|
||||
{ key: 'CI_PROJECT_PATH', value: path_with_namespace, public: true },
|
||||
{ key: 'CI_PROJECT_PATH_SLUG', value: path_with_namespace.parameterize, public: true },
|
||||
{ key: 'CI_PROJECT_PATH', value: full_path, public: true },
|
||||
{ key: 'CI_PROJECT_PATH_SLUG', value: full_path.parameterize, public: true },
|
||||
{ key: 'CI_PROJECT_NAMESPACE', value: namespace.full_path, public: true },
|
||||
{ key: 'CI_PROJECT_URL', value: web_url, public: true }
|
||||
]
|
||||
|
@ -1441,6 +1390,7 @@ class Project < ActiveRecord::Base
|
|||
|
||||
alias_method :name_with_namespace, :full_name
|
||||
alias_method :human_name, :full_name
|
||||
# @deprecated cannot remove yet because it has an index with its name in elasticsearch
|
||||
alias_method :path_with_namespace, :full_path
|
||||
|
||||
private
|
||||
|
@ -1495,7 +1445,7 @@ class Project < ActiveRecord::Base
|
|||
def pending_delete_twin
|
||||
return false unless path
|
||||
|
||||
Project.pending_delete.find_by_full_path(path_with_namespace)
|
||||
Project.pending_delete.find_by_full_path(full_path)
|
||||
end
|
||||
|
||||
##
|
||||
|
|
|
@ -35,9 +35,9 @@ class FlowdockService < Service
|
|||
data[:after],
|
||||
token: token,
|
||||
repo: project.repository.path_to_repo,
|
||||
repo_url: "#{Gitlab.config.gitlab.url}/#{project.path_with_namespace}",
|
||||
commit_url: "#{Gitlab.config.gitlab.url}/#{project.path_with_namespace}/commit/%s",
|
||||
diff_url: "#{Gitlab.config.gitlab.url}/#{project.path_with_namespace}/compare/%s...%s"
|
||||
repo_url: "#{Gitlab.config.gitlab.url}/#{project.full_path}",
|
||||
commit_url: "#{Gitlab.config.gitlab.url}/#{project.full_path}/commit/%s",
|
||||
diff_url: "#{Gitlab.config.gitlab.url}/#{project.full_path}/compare/%s...%s"
|
||||
)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -140,7 +140,7 @@ class JiraService < IssueTrackerService
|
|||
url: resource_url(user_path(author))
|
||||
},
|
||||
project: {
|
||||
name: project.path_with_namespace,
|
||||
name: project.full_path,
|
||||
url: resource_url(namespace_project_path(project.namespace, project)) # rubocop:disable Cop/ProjectPathHelper
|
||||
},
|
||||
entity: {
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
class ProjectWiki
|
||||
include Gitlab::ShellAdapter
|
||||
include Storage::LegacyProjectWiki
|
||||
|
||||
MARKUPS = {
|
||||
'Markdown' => :markdown,
|
||||
|
@ -26,16 +27,19 @@ class ProjectWiki
|
|||
@project.path + '.wiki'
|
||||
end
|
||||
|
||||
def path_with_namespace
|
||||
@project.path_with_namespace + ".wiki"
|
||||
def full_path
|
||||
@project.full_path + '.wiki'
|
||||
end
|
||||
|
||||
# @deprecated use full_path when you need it for an URL route or disk_path when you want to point to the filesystem
|
||||
alias_method :path_with_namespace, :full_path
|
||||
|
||||
def web_url
|
||||
Gitlab::Routing.url_helpers.project_wiki_url(@project, :home)
|
||||
end
|
||||
|
||||
def url_to_repo
|
||||
gitlab_shell.url_to_repo(path_with_namespace)
|
||||
gitlab_shell.url_to_repo(full_path)
|
||||
end
|
||||
|
||||
def ssh_url_to_repo
|
||||
|
@ -43,11 +47,11 @@ class ProjectWiki
|
|||
end
|
||||
|
||||
def http_url_to_repo
|
||||
"#{Gitlab.config.gitlab.url}/#{path_with_namespace}.git"
|
||||
"#{Gitlab.config.gitlab.url}/#{full_path}.git"
|
||||
end
|
||||
|
||||
def wiki_base_path
|
||||
[Gitlab.config.gitlab.relative_url_root, "/", @project.path_with_namespace, "/wikis"].join('')
|
||||
[Gitlab.config.gitlab.relative_url_root, '/', @project.full_path, '/wikis'].join('')
|
||||
end
|
||||
|
||||
# Returns the Gollum::Wiki object.
|
||||
|
@ -134,7 +138,7 @@ class ProjectWiki
|
|||
end
|
||||
|
||||
def repository
|
||||
@repository ||= Repository.new(path_with_namespace, @project)
|
||||
@repository ||= Repository.new(full_path, @project, disk_path: disk_path)
|
||||
end
|
||||
|
||||
def default_branch
|
||||
|
@ -142,7 +146,7 @@ class ProjectWiki
|
|||
end
|
||||
|
||||
def create_repo!
|
||||
if init_repo(path_with_namespace)
|
||||
if init_repo(disk_path)
|
||||
wiki = Gollum::Wiki.new(path_to_repo)
|
||||
else
|
||||
raise CouldNotCreateWikiError
|
||||
|
@ -162,15 +166,15 @@ class ProjectWiki
|
|||
web_url: web_url,
|
||||
git_ssh_url: ssh_url_to_repo,
|
||||
git_http_url: http_url_to_repo,
|
||||
path_with_namespace: path_with_namespace,
|
||||
path_with_namespace: full_path,
|
||||
default_branch: default_branch
|
||||
}
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def init_repo(path_with_namespace)
|
||||
gitlab_shell.add_repository(project.repository_storage_path, path_with_namespace)
|
||||
def init_repo(disk_path)
|
||||
gitlab_shell.add_repository(project.repository_storage_path, disk_path)
|
||||
end
|
||||
|
||||
def commit_details(action, message = nil, title = nil)
|
||||
|
@ -184,7 +188,7 @@ class ProjectWiki
|
|||
end
|
||||
|
||||
def path_to_repo
|
||||
@path_to_repo ||= File.join(project.repository_storage_path, "#{path_with_namespace}.git")
|
||||
@path_to_repo ||= File.join(project.repository_storage_path, "#{disk_path}.git")
|
||||
end
|
||||
|
||||
def update_project_activity
|
||||
|
|
|
@ -4,7 +4,7 @@ class Repository
|
|||
include Gitlab::ShellAdapter
|
||||
include RepositoryMirroring
|
||||
|
||||
attr_accessor :path_with_namespace, :project
|
||||
attr_accessor :full_path, :disk_path, :project
|
||||
|
||||
delegate :ref_name_for_sha, to: :raw_repository
|
||||
|
||||
|
@ -52,13 +52,14 @@ class Repository
|
|||
end
|
||||
end
|
||||
|
||||
def initialize(path_with_namespace, project)
|
||||
@path_with_namespace = path_with_namespace
|
||||
def initialize(full_path, project, disk_path: nil)
|
||||
@full_path = full_path
|
||||
@disk_path = disk_path || full_path
|
||||
@project = project
|
||||
end
|
||||
|
||||
def raw_repository
|
||||
return nil unless path_with_namespace
|
||||
return nil unless full_path
|
||||
|
||||
@raw_repository ||= initialize_raw_repository
|
||||
end
|
||||
|
@ -66,7 +67,7 @@ class Repository
|
|||
# Return absolute path to repository
|
||||
def path_to_repo
|
||||
@path_to_repo ||= File.expand_path(
|
||||
File.join(repository_storage_path, path_with_namespace + ".git")
|
||||
File.join(repository_storage_path, disk_path + '.git')
|
||||
)
|
||||
end
|
||||
|
||||
|
@ -469,7 +470,7 @@ class Repository
|
|||
|
||||
# Gitaly migration: https://gitlab.com/gitlab-org/gitaly/issues/314
|
||||
def exists?
|
||||
return false unless path_with_namespace
|
||||
return false unless full_path
|
||||
|
||||
Gitlab::GitalyClient.migrate(:repository_exists) do |enabled|
|
||||
if enabled
|
||||
|
@ -1005,7 +1006,7 @@ class Repository
|
|||
end
|
||||
|
||||
def fetch_remote(remote, forced: false, no_tags: false)
|
||||
gitlab_shell.fetch_remote(repository_storage_path, path_with_namespace, remote, forced: forced, no_tags: no_tags)
|
||||
gitlab_shell.fetch_remote(repository_storage_path, disk_path, remote, forced: forced, no_tags: no_tags)
|
||||
end
|
||||
|
||||
def fetch_ref(source_path, source_ref, target_ref)
|
||||
|
@ -1104,7 +1105,8 @@ class Repository
|
|||
end
|
||||
|
||||
def cache
|
||||
@cache ||= RepositoryCache.new(path_with_namespace, @project.id)
|
||||
# TODO: should we use UUIDs here? We could move repositories without clearing this cache
|
||||
@cache ||= RepositoryCache.new(full_path, @project.id)
|
||||
end
|
||||
|
||||
def tags_sorted_by_committed_date
|
||||
|
@ -1127,7 +1129,7 @@ class Repository
|
|||
end
|
||||
|
||||
def repository_event(event, tags = {})
|
||||
Gitlab::Metrics.add_event(event, { path: path_with_namespace }.merge(tags))
|
||||
Gitlab::Metrics.add_event(event, { path: full_path }.merge(tags))
|
||||
end
|
||||
|
||||
def create_commit(params = {})
|
||||
|
@ -1141,6 +1143,6 @@ class Repository
|
|||
end
|
||||
|
||||
def initialize_raw_repository
|
||||
Gitlab::Git::Repository.new(project.repository_storage, path_with_namespace + '.git')
|
||||
Gitlab::Git::Repository.new(project.repository_storage, disk_path + '.git')
|
||||
end
|
||||
end
|
||||
|
|
|
@ -44,7 +44,7 @@ class GlobalPolicy < BasePolicy
|
|||
prevent :log_in
|
||||
end
|
||||
|
||||
rule { admin | ~restricted_public_level }.policy do
|
||||
rule { ~(anonymous & restricted_public_level) }.policy do
|
||||
enable :read_users_list
|
||||
end
|
||||
end
|
||||
|
|
|
@ -60,7 +60,7 @@ class GitOperationService
|
|||
start_branch_name = nil if start_repository.empty_repo?
|
||||
|
||||
if start_branch_name && !start_repository.branch_exists?(start_branch_name)
|
||||
raise ArgumentError, "Cannot find branch #{start_branch_name} in #{start_repository.path_with_namespace}"
|
||||
raise ArgumentError, "Cannot find branch #{start_branch_name} in #{start_repository.full_path}"
|
||||
end
|
||||
|
||||
update_branch_with_hooks(branch_name) do
|
||||
|
|
|
@ -9,7 +9,7 @@ module Projects
|
|||
def async_execute
|
||||
project.update_attribute(:pending_delete, true)
|
||||
job_id = ProjectDestroyWorker.perform_async(project.id, current_user.id, params)
|
||||
Rails.logger.info("User #{current_user.id} scheduled destruction of project #{project.path_with_namespace} with job ID #{job_id}")
|
||||
Rails.logger.info("User #{current_user.id} scheduled destruction of project #{project.full_path} with job ID #{job_id}")
|
||||
end
|
||||
|
||||
def execute
|
||||
|
@ -40,7 +40,7 @@ module Projects
|
|||
private
|
||||
|
||||
def repo_path
|
||||
project.path_with_namespace
|
||||
project.disk_path
|
||||
end
|
||||
|
||||
def wiki_path
|
||||
|
@ -127,7 +127,7 @@ module Projects
|
|||
def flush_caches(project)
|
||||
project.repository.before_delete
|
||||
|
||||
Repository.new(wiki_path, project).before_delete
|
||||
Repository.new(wiki_path, project, disk_path: repo_path).before_delete
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -2,7 +2,7 @@ module Projects
|
|||
module ImportExport
|
||||
class ExportService < BaseService
|
||||
def execute(_options = {})
|
||||
@shared = Gitlab::ImportExport::Shared.new(relative_path: File.join(project.path_with_namespace, 'work'))
|
||||
@shared = Gitlab::ImportExport::Shared.new(relative_path: File.join(project.disk_path, 'work'))
|
||||
save_all
|
||||
end
|
||||
|
||||
|
|
|
@ -11,7 +11,7 @@ module Projects
|
|||
|
||||
success
|
||||
rescue => e
|
||||
error("Error importing repository #{project.import_url} into #{project.path_with_namespace} - #{e.message}")
|
||||
error("Error importing repository #{project.import_url} into #{project.full_path} - #{e.message}")
|
||||
end
|
||||
|
||||
private
|
||||
|
@ -51,7 +51,7 @@ module Projects
|
|||
end
|
||||
|
||||
def clone_repository
|
||||
gitlab_shell.import_repository(project.repository_storage_path, project.path_with_namespace, project.import_url)
|
||||
gitlab_shell.import_repository(project.repository_storage_path, project.disk_path, project.import_url)
|
||||
end
|
||||
|
||||
def fetch_repository
|
||||
|
|
|
@ -34,7 +34,7 @@ module Projects
|
|||
private
|
||||
|
||||
def transfer(project)
|
||||
@old_path = project.path_with_namespace
|
||||
@old_path = project.full_path
|
||||
@old_group = project.group
|
||||
@new_path = File.join(@new_namespace.try(:full_path) || '', project.path)
|
||||
@old_namespace = project.namespace
|
||||
|
@ -61,11 +61,13 @@ module Projects
|
|||
project.send_move_instructions(@old_path)
|
||||
|
||||
# Move main repository
|
||||
# TODO: check storage type and NOOP when not using Legacy
|
||||
unless move_repo_folder(@old_path, @new_path)
|
||||
raise TransferError.new('Cannot move project')
|
||||
end
|
||||
|
||||
# Move wiki repo also if present
|
||||
# TODO: check storage type and NOOP when not using Legacy
|
||||
move_repo_folder("#{@old_path}.wiki", "#{@new_path}.wiki")
|
||||
|
||||
# Move missing group labels to project
|
||||
|
|
|
@ -4,6 +4,9 @@ module QuickActions
|
|||
|
||||
attr_reader :issuable
|
||||
|
||||
SHRUG = '¯\\_(ツ)_/¯'.freeze
|
||||
TABLEFLIP = '(╯°□°)╯︵ ┻━┻'.freeze
|
||||
|
||||
# Takes a text and interprets the commands that are extracted from it.
|
||||
# Returns the content without commands, and hash of changes to be applied to a record.
|
||||
def execute(content, issuable)
|
||||
|
@ -14,6 +17,7 @@ module QuickActions
|
|||
|
||||
content, commands = extractor.extract_commands(content, context)
|
||||
extract_updates(commands, context)
|
||||
|
||||
[content, @updates]
|
||||
end
|
||||
|
||||
|
@ -423,6 +427,18 @@ module QuickActions
|
|||
@updates[:spend_time] = { duration: :reset, user: current_user }
|
||||
end
|
||||
|
||||
desc "Append the comment with #{SHRUG}"
|
||||
params '<Comment>'
|
||||
substitution :shrug do |comment|
|
||||
"#{comment} #{SHRUG}"
|
||||
end
|
||||
|
||||
desc "Append the comment with #{TABLEFLIP}"
|
||||
params '<Comment>'
|
||||
substitution :tableflip do |comment|
|
||||
"#{comment} #{TABLEFLIP}"
|
||||
end
|
||||
|
||||
# This is a dummy command, so that it appears in the autocomplete commands
|
||||
desc 'CC'
|
||||
params '@user'
|
||||
|
|
|
@ -24,7 +24,7 @@ class SystemHooksService
|
|||
key: model.key,
|
||||
id: model.id
|
||||
)
|
||||
|
||||
|
||||
if model.user
|
||||
data[:username] = model.user.username
|
||||
end
|
||||
|
@ -56,7 +56,7 @@ class SystemHooksService
|
|||
when GroupMember
|
||||
data.merge!(group_member_data(model))
|
||||
end
|
||||
|
||||
|
||||
data
|
||||
end
|
||||
|
||||
|
@ -79,7 +79,7 @@ class SystemHooksService
|
|||
{
|
||||
name: model.name,
|
||||
path: model.path,
|
||||
path_with_namespace: model.path_with_namespace,
|
||||
path_with_namespace: model.full_path,
|
||||
project_id: model.id,
|
||||
owner_name: owner.name,
|
||||
owner_email: owner.respond_to?(:email) ? owner.email : "",
|
||||
|
@ -93,7 +93,7 @@ class SystemHooksService
|
|||
{
|
||||
project_name: project.name,
|
||||
project_path: project.path,
|
||||
project_path_with_namespace: project.path_with_namespace,
|
||||
project_path_with_namespace: project.full_path,
|
||||
project_id: project.id,
|
||||
user_username: model.user.username,
|
||||
user_name: model.user.name,
|
||||
|
|
|
@ -30,7 +30,7 @@ class FileUploader < GitlabUploader
|
|||
#
|
||||
# Returns a String without a trailing slash
|
||||
def self.dynamic_path_segment(model)
|
||||
File.join(CarrierWave.root, base_dir, model.path_with_namespace)
|
||||
File.join(CarrierWave.root, base_dir, model.full_path)
|
||||
end
|
||||
|
||||
attr_accessor :model
|
||||
|
|
|
@ -70,7 +70,7 @@
|
|||
%span.badge
|
||||
= storage_counter(project.statistics.storage_size)
|
||||
%span.pull-right.light
|
||||
%span.monospace= project.path_with_namespace + ".git"
|
||||
%span.monospace= project.full_path + '.git'
|
||||
.panel-footer
|
||||
= paginate @projects, param_name: 'projects_page', theme: 'gitlab'
|
||||
|
||||
|
@ -88,7 +88,7 @@
|
|||
%span.badge
|
||||
= storage_counter(project.statistics.storage_size)
|
||||
%span.pull-right.light
|
||||
%span.monospace= project.path_with_namespace + ".git"
|
||||
%span.monospace= project.full_path + '.git'
|
||||
|
||||
.col-md-6
|
||||
- if can?(current_user, :admin_group_member, @group)
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
- page_title "UI Development Kit", "Help"
|
||||
- lorem = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed fermentum nisi sapien, non consequat lectus aliquam ultrices. Suspendisse sodales est euismod nunc condimentum, a consectetur diam ornare."
|
||||
- content_for :page_specific_javascripts do
|
||||
= webpack_bundle_tag('ui_development_kit')
|
||||
|
||||
.gitlab-ui-dev-kit
|
||||
%h1 GitLab UI development kit
|
||||
|
@ -407,29 +409,6 @@
|
|||
.dropdown-content
|
||||
.dropdown-loading
|
||||
= icon('spinner spin')
|
||||
:javascript
|
||||
$('#js-project-dropdown').glDropdown({
|
||||
data: function (term, callback) {
|
||||
Api.projects(term, { order_by: 'last_activity_at' }, function (data) {
|
||||
callback(data);
|
||||
});
|
||||
},
|
||||
text: function (project) {
|
||||
return project.name_with_namespace || project.name;
|
||||
},
|
||||
selectable: true,
|
||||
fieldName: "author_id",
|
||||
filterable: true,
|
||||
search: {
|
||||
fields: ['name_with_namespace']
|
||||
},
|
||||
id: function (data) {
|
||||
return data.id;
|
||||
},
|
||||
isSelected: function (data) {
|
||||
return data.id === 2;
|
||||
}
|
||||
})
|
||||
|
||||
.example
|
||||
%div
|
||||
|
|
|
@ -25,7 +25,7 @@
|
|||
%td
|
||||
= provider_project_link(provider, project.import_source)
|
||||
%td
|
||||
= link_to project.path_with_namespace, [project.namespace.becomes(Namespace), project]
|
||||
= link_to project.full_path, [project.namespace.becomes(Namespace), project]
|
||||
%td.job-status
|
||||
- if project.import_status == 'finished'
|
||||
%span
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
job.attr("id", "project_#{@project.id}")
|
||||
target_field = job.find(".import-target")
|
||||
target_field.empty()
|
||||
target_field.append('#{link_to @project.path_with_namespace, project_path(@project)}')
|
||||
target_field.append('#{link_to @project.full_path, project_path(@project)}')
|
||||
$("table.import-jobs tbody").prepend(job)
|
||||
job.addClass("active").find(".import-actions").html("<i class='fa fa-spinner fa-spin'></i> started")
|
||||
- else
|
||||
|
|
|
@ -35,7 +35,7 @@
|
|||
%td
|
||||
= link_to project.import_source, "https://bitbucket.org/#{project.import_source}", target: '_blank', rel: 'noopener noreferrer'
|
||||
%td
|
||||
= link_to project.path_with_namespace, [project.namespace.becomes(Namespace), project]
|
||||
= link_to project.full_path, [project.namespace.becomes(Namespace), project]
|
||||
%td.job-status
|
||||
- if project.import_status == 'finished'
|
||||
%span
|
||||
|
|
|
@ -33,7 +33,7 @@
|
|||
%td
|
||||
= project.import_source
|
||||
%td
|
||||
= link_to project.path_with_namespace, [project.namespace.becomes(Namespace), project]
|
||||
= link_to project.full_path, [project.namespace.becomes(Namespace), project]
|
||||
%td.job-status
|
||||
- if project.import_status == 'finished'
|
||||
%span
|
||||
|
|
|
@ -28,7 +28,7 @@
|
|||
%td
|
||||
= link_to project.import_source, "https://gitlab.com/#{project.import_source}", target: "_blank"
|
||||
%td
|
||||
= link_to project.path_with_namespace, [project.namespace.becomes(Namespace), project]
|
||||
= link_to project.full_path, [project.namespace.becomes(Namespace), project]
|
||||
%td.job-status
|
||||
- if project.import_status == 'finished'
|
||||
%span
|
||||
|
|
|
@ -38,7 +38,7 @@
|
|||
%td
|
||||
= link_to project.import_source, "https://code.google.com/p/#{project.import_source}", target: "_blank", rel: 'noopener noreferrer'
|
||||
%td
|
||||
= link_to project.path_with_namespace, [project.namespace.becomes(Namespace), project]
|
||||
= link_to project.full_path, [project.namespace.becomes(Namespace), project]
|
||||
%td.job-status
|
||||
- if project.import_status == 'finished'
|
||||
%span
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
-# haml-lint:disable InlineJavaScript
|
||||
:javascript
|
||||
var _gaq = _gaq || [];
|
||||
_gaq.push(['_setAccount', '#{extra_config.google_analytics_id}']);
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
- noteable_type = @noteable.class if @noteable.present?
|
||||
|
||||
- if project
|
||||
-# haml-lint:disable InlineJavaScript
|
||||
:javascript
|
||||
gl.GfmAutoComplete = gl.GfmAutoComplete || {};
|
||||
gl.GfmAutoComplete.dataSources = {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
.page-with-sidebar{ class: "#{('page-with-new-sidebar' if defined?(@new_sidebar) && @new_sidebar)} #{page_gutter_class}" }
|
||||
.page-with-sidebar{ class: page_with_sidebar_class }
|
||||
- if show_new_nav?
|
||||
- if defined?(nav) && nav
|
||||
= render "layouts/nav/#{nav}"
|
||||
|
@ -9,7 +9,7 @@
|
|||
= render "layouts/nav/#{nav}"
|
||||
- if content_for?(:sub_nav)
|
||||
= yield :sub_nav
|
||||
.content-wrapper{ class: "#{(layout_nav_class unless show_new_nav?)}" }
|
||||
.content-wrapper{ class: layout_nav_class }
|
||||
- if show_new_nav?
|
||||
.mobile-overlay
|
||||
.alert-wrapper
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
<!-- Piwik -->
|
||||
-# haml-lint:disable InlineJavaScript
|
||||
:javascript
|
||||
var _paq = _paq || [];
|
||||
_paq.push(['trackPageView']);
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
!!! 5
|
||||
%html{ lang: I18n.locale, class: "#{page_class}" }
|
||||
%html{ lang: I18n.locale, class: page_class }
|
||||
= render "layouts/head"
|
||||
%body{ class: @body_class, data: { page: body_data_page, project: "#{@project.path if @project}", group: "#{@group.path if @group}", find_file: find_file_path } }
|
||||
= render "layouts/init_auto_complete" if @gfm_form
|
||||
= render 'peek/bar'
|
||||
- if show_new_nav?
|
||||
= render "layouts/header/new"
|
||||
- else
|
||||
|
@ -10,5 +11,3 @@
|
|||
= render 'layouts/page', sidebar: sidebar, nav: nav
|
||||
|
||||
= yield :scripts_body
|
||||
|
||||
= render 'peek/bar'
|
||||
|
|
|
@ -91,8 +91,8 @@
|
|||
= nav_link(controller: :abuse_reports) do
|
||||
= link_to admin_abuse_reports_path, title: "Abuse Reports" do
|
||||
%span
|
||||
Abuse Reports
|
||||
%span.badge.count= number_with_delimiter(AbuseReport.count(:all))
|
||||
Abuse Reports
|
||||
|
||||
- if akismet_enabled?
|
||||
= nav_link(controller: :spam_logs) do
|
||||
|
|
|
@ -28,9 +28,9 @@
|
|||
= nav_link(path: ['groups#issues', 'labels#index', 'milestones#index']) do
|
||||
= link_to issues_group_path(@group), title: 'Issues' do
|
||||
%span
|
||||
Issues
|
||||
- issues = IssuesFinder.new(current_user, group_id: @group.id, state: 'opened').execute
|
||||
%span.badge.count= number_with_delimiter(issues.count)
|
||||
Issues
|
||||
|
||||
%ul.sidebar-sub-level-items
|
||||
= nav_link(path: 'groups#issues', html_options: { class: 'home' }) do
|
||||
|
@ -51,9 +51,9 @@
|
|||
= nav_link(path: 'groups#merge_requests') do
|
||||
= link_to merge_requests_group_path(@group), title: 'Merge Requests' do
|
||||
%span
|
||||
Merge Requests
|
||||
- merge_requests = MergeRequestsFinder.new(current_user, group_id: @group.id, state: 'opened', non_archived: true).execute
|
||||
%span.badge.count= number_with_delimiter(merge_requests.count)
|
||||
Merge Requests
|
||||
= nav_link(path: 'group_members#index') do
|
||||
= link_to group_group_members_path(@group), title: 'Members' do
|
||||
%span
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
- content_for :project_javascripts do
|
||||
- project = @target_project || @project
|
||||
- if current_user
|
||||
-# haml-lint:disable InlineJavaScript
|
||||
:javascript
|
||||
window.uploads_path = "#{project_uploads_path(project)}";
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
- content_for :page_specific_javascripts do
|
||||
- if @snippet && current_user
|
||||
-# haml-lint:disable InlineJavaScript
|
||||
:javascript
|
||||
window.uploads_path = "#{upload_path('personal_snippet', id: @snippet.id)}";
|
||||
|
||||
|
|
2
app/views/peek/views/_host.html.haml
Normal file
2
app/views/peek/views/_host.html.haml
Normal file
|
@ -0,0 +1,2 @@
|
|||
%span.current-host
|
||||
= truncate(view.hostname)
|
|
@ -1,5 +1,6 @@
|
|||
- page_title "Personal Access Tokens"
|
||||
- @content_class = "limit-container-width" unless fluid_layout
|
||||
|
||||
= render 'profiles/head'
|
||||
|
||||
.row.prepend-top-default
|
||||
|
@ -19,7 +20,7 @@
|
|||
%h5.prepend-top-0
|
||||
Your New Personal Access Token
|
||||
.form-group
|
||||
= text_field_tag 'created-personal-access-token', flash[:personal_access_token], readonly: true, class: "form-control", 'aria-describedby' => "created-personal-access-token-help-block"
|
||||
= text_field_tag 'created-personal-access-token', flash[:personal_access_token], readonly: true, class: "form-control js-select-on-focus", 'aria-describedby' => "created-personal-access-token-help-block"
|
||||
= clipboard_button(text: flash[:personal_access_token], title: "Copy personal access token to clipboard", placement: "left")
|
||||
%span#created-personal-access-token-help-block.help-block.text-danger Make sure you save it - you won't be able to access it again.
|
||||
|
||||
|
@ -28,8 +29,3 @@
|
|||
= render "shared/personal_access_tokens_form", path: profile_personal_access_tokens_path, impersonation: false, token: @personal_access_token, scopes: @scopes
|
||||
|
||||
= render "shared/personal_access_tokens_table", impersonation: false, active_tokens: @active_personal_access_tokens, inactive_tokens: @inactive_personal_access_tokens
|
||||
|
||||
:javascript
|
||||
$("#created-personal-access-token").click(function() {
|
||||
this.select();
|
||||
});
|
||||
|
|
|
@ -7,97 +7,92 @@
|
|||
|
||||
= render 'profiles/head'
|
||||
|
||||
- if inject_u2f_api?
|
||||
- content_for :page_specific_javascripts do
|
||||
- content_for :page_specific_javascripts do
|
||||
- if inject_u2f_api?
|
||||
= page_specific_javascript_bundle_tag('u2f')
|
||||
= page_specific_javascript_bundle_tag('two_factor_auth')
|
||||
|
||||
.row.prepend-top-default
|
||||
.col-lg-4
|
||||
%h4.prepend-top-0
|
||||
Register Two-Factor Authentication App
|
||||
%p
|
||||
Use an app on your mobile device to enable two-factor authentication (2FA).
|
||||
.col-lg-8
|
||||
- if current_user.two_factor_otp_enabled?
|
||||
= icon "check inverse", base: "circle", class: "text-success", text: "You've already enabled two-factor authentication using mobile authenticator applications. You can disable it from your account settings page."
|
||||
- else
|
||||
.js-two-factor-auth{ 'data-two-factor-skippable' => "#{two_factor_skippable?}", 'data-two_factor_skip_url' => skip_profile_two_factor_auth_path }
|
||||
.row.prepend-top-default
|
||||
.col-lg-4
|
||||
%h4.prepend-top-0
|
||||
Register Two-Factor Authentication App
|
||||
%p
|
||||
Download the Google Authenticator application from App Store or Google Play Store and scan this code.
|
||||
More information is available in the #{link_to('documentation', help_page_path('profile/two_factor_authentication'))}.
|
||||
.row.append-bottom-10
|
||||
.col-md-4
|
||||
= raw @qr_code
|
||||
.col-md-8
|
||||
.account-well
|
||||
%p.prepend-top-0.append-bottom-0
|
||||
Can't scan the code?
|
||||
%p.prepend-top-0.append-bottom-0
|
||||
To add the entry manually, provide the following details to the application on your phone.
|
||||
%p.prepend-top-0.append-bottom-0
|
||||
Account:
|
||||
= @account_string
|
||||
%p.prepend-top-0.append-bottom-0
|
||||
Key:
|
||||
= current_user.otp_secret.scan(/.{4}/).join(' ')
|
||||
%p.two-factor-new-manual-content
|
||||
Time based: Yes
|
||||
= form_tag profile_two_factor_auth_path, method: :post do |f|
|
||||
- if @error
|
||||
.alert.alert-danger
|
||||
= @error
|
||||
.form-group
|
||||
= label_tag :pin_code, nil, class: "label-light"
|
||||
= text_field_tag :pin_code, nil, class: "form-control", required: true
|
||||
.prepend-top-default
|
||||
= submit_tag 'Register with two-factor app', class: 'btn btn-success'
|
||||
Use an app on your mobile device to enable two-factor authentication (2FA).
|
||||
.col-lg-8
|
||||
- if current_user.two_factor_otp_enabled?
|
||||
= icon "check inverse", base: "circle", class: "text-success", text: "You've already enabled two-factor authentication using mobile authenticator applications. You can disable it from your account settings page."
|
||||
- else
|
||||
%p
|
||||
Download the Google Authenticator application from App Store or Google Play Store and scan this code.
|
||||
More information is available in the #{link_to('documentation', help_page_path('profile/two_factor_authentication'))}.
|
||||
.row.append-bottom-10
|
||||
.col-md-4
|
||||
= raw @qr_code
|
||||
.col-md-8
|
||||
.account-well
|
||||
%p.prepend-top-0.append-bottom-0
|
||||
Can't scan the code?
|
||||
%p.prepend-top-0.append-bottom-0
|
||||
To add the entry manually, provide the following details to the application on your phone.
|
||||
%p.prepend-top-0.append-bottom-0
|
||||
Account:
|
||||
= @account_string
|
||||
%p.prepend-top-0.append-bottom-0
|
||||
Key:
|
||||
= current_user.otp_secret.scan(/.{4}/).join(' ')
|
||||
%p.two-factor-new-manual-content
|
||||
Time based: Yes
|
||||
= form_tag profile_two_factor_auth_path, method: :post do |f|
|
||||
- if @error
|
||||
.alert.alert-danger
|
||||
= @error
|
||||
.form-group
|
||||
= label_tag :pin_code, nil, class: "label-light"
|
||||
= text_field_tag :pin_code, nil, class: "form-control", required: true
|
||||
.prepend-top-default
|
||||
= submit_tag 'Register with two-factor app', class: 'btn btn-success'
|
||||
|
||||
%hr
|
||||
%hr
|
||||
|
||||
.row.prepend-top-default
|
||||
.row.prepend-top-default
|
||||
.col-lg-4
|
||||
%h4.prepend-top-0
|
||||
Register Universal Two-Factor (U2F) Device
|
||||
%p
|
||||
Use a hardware device to add the second factor of authentication.
|
||||
%p
|
||||
As U2F devices are only supported by a few browsers, we require that you set up a
|
||||
two-factor authentication app before a U2F device. That way you'll always be able to
|
||||
log in - even when you're using an unsupported browser.
|
||||
.col-lg-8
|
||||
- if @u2f_registration.errors.present?
|
||||
= form_errors(@u2f_registration)
|
||||
= render "u2f/register"
|
||||
|
||||
.col-lg-4
|
||||
%h4.prepend-top-0
|
||||
Register Universal Two-Factor (U2F) Device
|
||||
%p
|
||||
Use a hardware device to add the second factor of authentication.
|
||||
%p
|
||||
As U2F devices are only supported by a few browsers, we require that you set up a
|
||||
two-factor authentication app before a U2F device. That way you'll always be able to
|
||||
log in - even when you're using an unsupported browser.
|
||||
.col-lg-8
|
||||
- if @u2f_registration.errors.present?
|
||||
= form_errors(@u2f_registration)
|
||||
= render "u2f/register"
|
||||
%hr
|
||||
|
||||
%hr
|
||||
%h5 U2F Devices (#{@u2f_registrations.length})
|
||||
|
||||
%h5 U2F Devices (#{@u2f_registrations.length})
|
||||
|
||||
- if @u2f_registrations.present?
|
||||
.table-responsive
|
||||
%table.table.table-bordered.u2f-registrations
|
||||
%colgroup
|
||||
%col{ width: "50%" }
|
||||
%col{ width: "30%" }
|
||||
%col{ width: "20%" }
|
||||
%thead
|
||||
%tr
|
||||
%th Name
|
||||
%th Registered On
|
||||
%th
|
||||
%tbody
|
||||
- @u2f_registrations.each do |registration|
|
||||
- if @u2f_registrations.present?
|
||||
.table-responsive
|
||||
%table.table.table-bordered.u2f-registrations
|
||||
%colgroup
|
||||
%col{ width: "50%" }
|
||||
%col{ width: "30%" }
|
||||
%col{ width: "20%" }
|
||||
%thead
|
||||
%tr
|
||||
%td= registration.name.presence || "<no name set>"
|
||||
%td= registration.created_at.to_date.to_s(:medium)
|
||||
%td= link_to "Delete", profile_u2f_registration_path(registration), method: :delete, class: "btn btn-danger pull-right", data: { confirm: "Are you sure you want to delete this device? This action cannot be undone." }
|
||||
%th Name
|
||||
%th Registered On
|
||||
%th
|
||||
%tbody
|
||||
- @u2f_registrations.each do |registration|
|
||||
%tr
|
||||
%td= registration.name.presence || "<no name set>"
|
||||
%td= registration.created_at.to_date.to_s(:medium)
|
||||
%td= link_to "Delete", profile_u2f_registration_path(registration), method: :delete, class: "btn btn-danger pull-right", data: { confirm: "Are you sure you want to delete this device? This action cannot be undone." }
|
||||
|
||||
- else
|
||||
.settings-message.text-center
|
||||
You don't have any U2F devices registered yet.
|
||||
|
||||
|
||||
- if two_factor_skippable?
|
||||
:javascript
|
||||
var button = "<a class='btn btn-xs btn-warning pull-right' data-method='patch' href='#{skip_profile_two_factor_auth_path}'>Configure it later</a>";
|
||||
$(".flash-alert").append(button);
|
||||
- else
|
||||
.settings-message.text-center
|
||||
You don't have any U2F devices registered yet.
|
||||
|
|
|
@ -8,9 +8,3 @@
|
|||
|
||||
.content_list.project-activity{ :"data-href" => activity_project_path(@project) }
|
||||
= spinner
|
||||
|
||||
:javascript
|
||||
var activity = new gl.Activities();
|
||||
$(document).on('page:restore', function (event) {
|
||||
activity.reloadActivities()
|
||||
})
|
||||
|
|
|
@ -20,6 +20,3 @@
|
|||
- unless can?(current_user, :push_code, @project)
|
||||
.inline.prepend-left-10
|
||||
= commit_in_fork_help
|
||||
|
||||
:javascript
|
||||
new NewCommitForm($('.js-create-dir-form'))
|
||||
|
|
|
@ -13,6 +13,3 @@
|
|||
.col-sm-offset-2.col-sm-10
|
||||
= button_tag 'Delete file', class: 'btn btn-remove btn-remove-file'
|
||||
= link_to "Cancel", '#', class: "btn btn-cancel", "data-dismiss" => "modal"
|
||||
|
||||
:javascript
|
||||
new NewCommitForm($('.js-delete-blob-form'))
|
||||
|
|
|
@ -28,8 +28,4 @@
|
|||
.form-actions
|
||||
= button_tag 'Create branch', class: 'btn btn-create', tabindex: 3
|
||||
= link_to 'Cancel', project_branches_path(@project), class: 'btn btn-cancel'
|
||||
|
||||
:javascript
|
||||
var availableRefs = #{@project.repository.ref_names.to_json};
|
||||
|
||||
new NewBranchForm($('.js-create-branch-form'), availableRefs)
|
||||
%script#availableRefs{ type: "application/json" }= @project.repository.ref_names.to_json.html_safe
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
.page-content-header
|
||||
.page-content-header.js-commit-box{ 'data-commit-path' => branches_project_commit_path(@project, @commit.id) }
|
||||
.header-main-content
|
||||
= render partial: 'signature', object: @commit.signature
|
||||
%strong
|
||||
|
@ -79,6 +79,3 @@
|
|||
= render 'shared/mini_pipeline_graph', pipeline: last_pipeline, klass: 'js-commit-pipeline-graph'
|
||||
in
|
||||
= time_interval_in_words last_pipeline.duration
|
||||
|
||||
:javascript
|
||||
$(".commit-info.branches").load("#{branches_project_commit_path(@project, @commit.id)}");
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
- notes = commit.notes
|
||||
- note_count = notes.user.count
|
||||
|
||||
- cache_key = [project.path_with_namespace, commit.id, current_application_settings, note_count, @path.presence, current_controller?(:commits)]
|
||||
- cache_key = [project.full_path, commit.id, current_application_settings, note_count, @path.presence, current_controller?(:commits)]
|
||||
- cache_key.push(commit.status(ref)) if commit.status(ref)
|
||||
|
||||
= cache(cache_key, expires_in: 1.day) do
|
||||
|
|
|
@ -11,34 +11,32 @@
|
|||
= content_for :sub_nav do
|
||||
= render "head"
|
||||
|
||||
%div{ class: container_class }
|
||||
.tree-holder
|
||||
.nav-block
|
||||
.tree-ref-container
|
||||
.tree-ref-holder
|
||||
= render 'shared/ref_switcher', destination: 'commits'
|
||||
.js-project-commits-show{ 'data-commits-limit' => @limit }
|
||||
%div{ class: container_class }
|
||||
.tree-holder
|
||||
.nav-block
|
||||
.tree-ref-container
|
||||
.tree-ref-holder
|
||||
= render 'shared/ref_switcher', destination: 'commits'
|
||||
|
||||
%ul.breadcrumb.repo-breadcrumb
|
||||
= commits_breadcrumbs
|
||||
.tree-controls.hidden-xs.hidden-sm
|
||||
- if @merge_request.present?
|
||||
.control
|
||||
= link_to _("View open merge request"), project_merge_request_path(@project, @merge_request), class: 'btn'
|
||||
- elsif create_mr_button?(@repository.root_ref, @ref)
|
||||
.control
|
||||
= link_to _("Create merge request"), create_mr_path(@repository.root_ref, @ref), class: 'btn btn-success'
|
||||
|
||||
%ul.breadcrumb.repo-breadcrumb
|
||||
= commits_breadcrumbs
|
||||
.tree-controls.hidden-xs.hidden-sm
|
||||
- if @merge_request.present?
|
||||
.control
|
||||
= link_to _("View open merge request"), project_merge_request_path(@project, @merge_request), class: 'btn'
|
||||
- elsif create_mr_button?(@repository.root_ref, @ref)
|
||||
= form_tag(project_commits_path(@project, @id), method: :get, class: 'commits-search-form', data: { 'signatures-path' => namespace_project_signatures_path }) do
|
||||
= search_field_tag :search, params[:search], { placeholder: _('Filter by commit message'), id: 'commits-search', class: 'form-control search-text-input input-short', spellcheck: false }
|
||||
.control
|
||||
= link_to _("Create merge request"), create_mr_path(@repository.root_ref, @ref), class: 'btn btn-success'
|
||||
= link_to project_commits_path(@project, @ref, rss_url_options), title: _("Commits feed"), class: 'btn' do
|
||||
= icon("rss")
|
||||
|
||||
.control
|
||||
= form_tag(project_commits_path(@project, @id), method: :get, class: 'commits-search-form', data: { 'signatures-path' => namespace_project_signatures_path }) do
|
||||
= search_field_tag :search, params[:search], { placeholder: _('Filter by commit message'), id: 'commits-search', class: 'form-control search-text-input input-short', spellcheck: false }
|
||||
.control
|
||||
= link_to project_commits_path(@project, @ref, rss_url_options), title: _("Commits feed"), class: 'btn' do
|
||||
= icon("rss")
|
||||
|
||||
%div{ id: dom_id(@project) }
|
||||
%ol#commits-list.list-unstyled.content_list
|
||||
= render 'commits', project: @project, ref: @ref
|
||||
= spinner
|
||||
|
||||
:javascript
|
||||
CommitsList.init(#{@limit});
|
||||
%div{ id: dom_id(@project) }
|
||||
%ol#commits-list.list-unstyled.content_list
|
||||
= render 'commits', project: @project, ref: @ref
|
||||
= spinner
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
- page_title "Find File", @ref
|
||||
= render "projects/commits/head"
|
||||
|
||||
.file-finder-holder.tree-holder.clearfix
|
||||
.file-finder-holder.tree-holder.clearfix.js-file-finder{ 'data-file-find-url': "#{escape_javascript(project_files_path(@project, @ref, @options.merge(format: :json)))}", 'data-find-tree-url': escape_javascript(project_tree_path(@project, @ref)), 'data-blob-url-template': escape_javascript(project_blob_path(@project, @id || @commit.id)) }
|
||||
.nav-block
|
||||
.tree-ref-holder
|
||||
= render 'shared/ref_switcher', destination: 'find_file', path: @path
|
||||
|
@ -17,11 +17,3 @@
|
|||
%table.table.files-slider{ class: "table_#{@hex_path} tree-table table-striped" }
|
||||
%tbody
|
||||
= spinner nil, true
|
||||
|
||||
:javascript
|
||||
var projectFindFile = new ProjectFindFile($(".file-finder-holder"), {
|
||||
url: "#{escape_javascript(project_files_path(@project, @ref, @options.merge(format: :json)))}",
|
||||
treeUrl: "#{escape_javascript(project_tree_path(@project, @ref))}",
|
||||
blobUrlTemplate: "#{escape_javascript(project_blob_path(@project, @id || @commit.id))}"
|
||||
});
|
||||
new ShortcutsFindFile(projectFindFile);
|
||||
|
|
|
@ -3,8 +3,9 @@
|
|||
- if show_new_nav?
|
||||
- add_to_breadcrumbs("Repository", project_tree_path(@project))
|
||||
- content_for :page_specific_javascripts do
|
||||
= page_specific_javascript_bundle_tag('common_d3')
|
||||
= page_specific_javascript_bundle_tag('graphs')
|
||||
= webpack_bundle_tag('common_d3')
|
||||
= webpack_bundle_tag('graphs')
|
||||
= webpack_bundle_tag('graphs_charts')
|
||||
= render "projects/commits/head"
|
||||
|
||||
.repo-charts{ class: container_class }
|
||||
|
@ -75,55 +76,10 @@
|
|||
Commits per day hour (UTC)
|
||||
%canvas#hour-chart
|
||||
|
||||
:javascript
|
||||
var responsiveChart = function (selector, data) {
|
||||
var options = { "scaleOverlay": true, responsive: true, pointHitDetectionRadius: 2, maintainAspectRatio: false };
|
||||
// get selector by context
|
||||
var ctx = selector.get(0).getContext("2d");
|
||||
// pointing parent container to make chart.js inherit its width
|
||||
var container = $(selector).parent();
|
||||
var generateChart = function() {
|
||||
selector.attr('width', $(container).width());
|
||||
if (window.innerWidth < 768) {
|
||||
// Scale fonts if window width lower than 768px (iPad portrait)
|
||||
options.scaleFontSize = 8
|
||||
}
|
||||
return new Chart(ctx).Bar(data, options);
|
||||
};
|
||||
// enabling auto-resizing
|
||||
$(window).resize(generateChart);
|
||||
return generateChart();
|
||||
};
|
||||
|
||||
var chartData = function (keys, values) {
|
||||
var data = {
|
||||
labels : keys,
|
||||
datasets : [{
|
||||
fillColor : "rgba(220,220,220,0.5)",
|
||||
strokeColor : "rgba(220,220,220,1)",
|
||||
barStrokeWidth: 1,
|
||||
barValueSpacing: 1,
|
||||
barDatasetSpacing: 1,
|
||||
data : values
|
||||
}]
|
||||
};
|
||||
return data;
|
||||
};
|
||||
|
||||
var hourData = chartData(#{@commits_per_time.keys.to_json}, #{@commits_per_time.values.to_json});
|
||||
responsiveChart($('#hour-chart'), hourData);
|
||||
|
||||
var dayData = chartData(#{@commits_per_week_days.keys.to_json}, #{@commits_per_week_days.values.to_json});
|
||||
responsiveChart($('#weekday-chart'), dayData);
|
||||
|
||||
var monthData = chartData(#{@commits_per_month.keys.to_json}, #{@commits_per_month.values.to_json});
|
||||
responsiveChart($('#month-chart'), monthData);
|
||||
|
||||
var data = #{@languages.to_json};
|
||||
var ctx = $("#languages-chart").get(0).getContext("2d");
|
||||
var options = {
|
||||
scaleOverlay: true,
|
||||
responsive: true,
|
||||
maintainAspectRatio: false
|
||||
}
|
||||
var myPieChart = new Chart(ctx).Pie(data, options);
|
||||
%script#projectChartData{ type: "application/json" }
|
||||
- projectChartData = {};
|
||||
- projectChartData['hour'] = { 'keys' => @commits_per_time.keys, 'values' => @commits_per_time.values }
|
||||
- projectChartData['weekDays'] = { 'keys' => @commits_per_week_days.keys, 'values' => @commits_per_week_days.values }
|
||||
- projectChartData['month'] = { 'keys' => @commits_per_month.keys, 'values' => @commits_per_month.values }
|
||||
- projectChartData['languages'] = @languages
|
||||
= projectChartData.to_json.html_safe
|
||||
|
|
|
@ -1,15 +1,16 @@
|
|||
- @no_container = true
|
||||
- page_title "Contributors"
|
||||
- content_for :page_specific_javascripts do
|
||||
= page_specific_javascript_bundle_tag('common_d3')
|
||||
= page_specific_javascript_bundle_tag('graphs')
|
||||
= webpack_bundle_tag('common_d3')
|
||||
= webpack_bundle_tag('graphs')
|
||||
= webpack_bundle_tag('graphs_show')
|
||||
|
||||
- if show_new_nav?
|
||||
- add_to_breadcrumbs("Repository", project_tree_path(@project))
|
||||
|
||||
= render 'projects/commits/head'
|
||||
|
||||
%div{ class: container_class }
|
||||
.js-graphs-show{ class: container_class, 'data-project-graph-path': project_graph_path(@project, current_ref, format: :json) }
|
||||
.sub-header-block
|
||||
.tree-ref-holder
|
||||
= render 'shared/ref_switcher', destination: 'graphs'
|
||||
|
@ -33,24 +34,3 @@
|
|||
#contributors-master
|
||||
#contributors.clearfix
|
||||
%ol.contributors-list.clearfix
|
||||
|
||||
|
||||
|
||||
:javascript
|
||||
$.ajax({
|
||||
type: "GET",
|
||||
url: "#{project_graph_path(@project, current_ref, format: :json)}",
|
||||
dataType: "json",
|
||||
success: function (data) {
|
||||
var graph = new ContributorsStatGraph();
|
||||
graph.init(data);
|
||||
|
||||
$("#brush_change").change(function(){
|
||||
graph.change_date_header();
|
||||
graph.redraw_authors();
|
||||
});
|
||||
|
||||
$(".stat-graph").fadeIn();
|
||||
$(".loading-graph").hide();
|
||||
}
|
||||
});
|
||||
|
|
|
@ -10,5 +10,3 @@
|
|||
- if @project.external_import?
|
||||
%p.monospace git clone --bare #{@project.safe_import_url}
|
||||
%p Please wait while we import the repository for you. Refresh at will.
|
||||
:javascript
|
||||
new ProjectImport();
|
||||
|
|
|
@ -33,7 +33,7 @@
|
|||
Suggestions:
|
||||
%code= 'gitlab'
|
||||
%code= @project.path # Path contains no spaces, but dashes
|
||||
%code= @project.path_with_namespace
|
||||
%code= @project.full_path
|
||||
%p
|
||||
Reserved:
|
||||
= link_to 'https://docs.mattermost.com/help/messaging/executing-commands.html#built-in-commands', target: '__blank' do
|
||||
|
|
|
@ -41,7 +41,7 @@
|
|||
- projects = target_projects(@project)
|
||||
.merge-request-select.dropdown
|
||||
= f.hidden_field :target_project_id
|
||||
= dropdown_toggle f.object.target_project.path_with_namespace, { toggle: "dropdown", field_name: "#{f.object_name}[target_project_id]", disabled: @merge_request.persisted? }, { toggle_class: "js-compare-dropdown js-target-project" }
|
||||
= dropdown_toggle f.object.target_project.full_path, { toggle: "dropdown", field_name: "#{f.object_name}[target_project_id]", disabled: @merge_request.persisted? }, { toggle_class: "js-compare-dropdown js-target-project" }
|
||||
.dropdown-menu.dropdown-menu-selectable.dropdown-target-project
|
||||
= dropdown_title("Select target project")
|
||||
= dropdown_filter("Search projects")
|
||||
|
|
|
@ -2,4 +2,4 @@
|
|||
- projects.each do |project|
|
||||
%li
|
||||
%a{ href: "#", class: "#{('is-active' if selected == project.id)}", data: { id: project.id } }
|
||||
= project.path_with_namespace
|
||||
= project.full_path
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue