Commit c5d4da20 authored by Valery Sizov's avatar Valery Sizov

Merge branch 'master' of gitlab.com:gitlab-org/gitlab-ce into ce_upstream

parents e1069aa5 4b6fd0df
*.erb *.erb
lib/gitlab/sanitizers/svg/whitelist.rb
...@@ -208,10 +208,15 @@ spinach 9 10 ruby21: *spinach-knapsack-ruby21 ...@@ -208,10 +208,15 @@ spinach 9 10 ruby21: *spinach-knapsack-ruby21
- bundle exec $CI_BUILD_NAME - bundle exec $CI_BUILD_NAME
rubocop: *exec rubocop: *exec
rake haml_lint: *exec
rake scss_lint: *exec rake scss_lint: *exec
rake brakeman: *exec rake brakeman: *exec
rake flog: *exec rake flog:
rake flay: *exec <<: *exec
allow_failure: yes
rake flay:
<<: *exec
allow_failure: yes
license_finder: *exec license_finder: *exec
rake downtime_check: *exec rake downtime_check: *exec
......
# Whether to ignore frontmatter at the beginning of HAML documents for
# frameworks such as Jekyll/Middleman
skip_frontmatter: false
exclude:
- 'vendor/**/*'
- 'spec/**/*'
linters:
AltText:
enabled: false
ClassAttributeWithStaticValue:
enabled: false
ClassesBeforeIds:
enabled: false
ConsecutiveComments:
enabled: false
ConsecutiveSilentScripts:
enabled: false
max_consecutive: 2
EmptyObjectReference:
enabled: true
EmptyScript:
enabled: true
FinalNewline:
enabled: false
present: true
HtmlAttributes:
enabled: false
ImplicitDiv:
enabled: false
LeadingCommentSpace:
enabled: false
LineLength:
enabled: false
max: 80
MultilinePipe:
enabled: false
MultilineScript:
enabled: true
ObjectReferenceAttributes:
enabled: true
RuboCop:
enabled: false
# These cops are incredibly noisy when it comes to HAML templates, so we
# ignore them.
ignored_cops:
- Lint/BlockAlignment
- Lint/EndAlignment
- Lint/Void
- Metrics/LineLength
- Style/AlignParameters
- Style/BlockNesting
- Style/ElseAlignment
- Style/FileName
- Style/FinalNewline
- Style/FrozenStringLiteralComment
- Style/IfUnlessModifier
- Style/IndentationWidth
- Style/Next
- Style/TrailingBlankLines
- Style/TrailingWhitespace
- Style/WhileUntilModifier
RubyComments:
enabled: false
SpaceBeforeScript:
enabled: false
SpaceInsideHashAttributes:
enabled: false
style: space
Indentation:
enabled: true
character: space # or tab
TagName:
enabled: true
TrailingWhitespace:
enabled: false
UnnecessaryInterpolation:
enabled: false
UnnecessaryStringOutput:
enabled: false
# This configuration was generated by # This configuration was generated by
# `rubocop --auto-gen-config --exclude-limit 0` # `rubocop --auto-gen-config --exclude-limit 0`
# on 2016-07-13 12:36:08 -0600 using RuboCop version 0.41.2. # on 2016-09-14 15:44:53 -0400 using RuboCop version 0.42.0.
# The point is for the user to remove these configuration records # The point is for the user to remove these configuration records
# one by one as the offenses are removed from the code base. # one by one as the offenses are removed from the code base.
# Note that changes in the inspected code, or installation of new # Note that changes in the inspected code, or installation of new
# versions of RuboCop, may require this file to be generated again. # versions of RuboCop, may require this file to be generated again.
# Offense count: 154 # Offense count: 158
Lint/AmbiguousRegexpLiteral: Lint/AmbiguousRegexpLiteral:
Enabled: false Enabled: false
# Offense count: 43 # Offense count: 41
# Configuration parameters: AllowSafeAssignment. # Configuration parameters: AllowSafeAssignment.
Lint/AssignmentInCondition: Lint/AssignmentInCondition:
Enabled: false Enabled: false
# Offense count: 14 # Offense count: 16
Lint/HandleExceptions: Lint/HandleExceptions:
Enabled: false Enabled: false
...@@ -23,28 +23,28 @@ Lint/HandleExceptions: ...@@ -23,28 +23,28 @@ Lint/HandleExceptions:
Lint/Loop: Lint/Loop:
Enabled: false Enabled: false
# Offense count: 15 # Offense count: 16
Lint/ShadowingOuterLocalVariable: Lint/ShadowingOuterLocalVariable:
Enabled: false Enabled: false
# Offense count: 3 # Offense count: 6
# Cop supports --auto-correct. # Cop supports --auto-correct.
Lint/StringConversionInInterpolation: Lint/StringConversionInInterpolation:
Enabled: false Enabled: false
# Offense count: 44 # Offense count: 49
# Cop supports --auto-correct. # Cop supports --auto-correct.
# Configuration parameters: IgnoreEmptyBlocks, AllowUnusedKeywordArguments. # Configuration parameters: IgnoreEmptyBlocks, AllowUnusedKeywordArguments.
Lint/UnusedBlockArgument: Lint/UnusedBlockArgument:
Enabled: false Enabled: false
# Offense count: 129 # Offense count: 144
# Cop supports --auto-correct. # Cop supports --auto-correct.
# Configuration parameters: AllowUnusedKeywordArguments, IgnoreEmptyMethods. # Configuration parameters: AllowUnusedKeywordArguments, IgnoreEmptyMethods.
Lint/UnusedMethodArgument: Lint/UnusedMethodArgument:
Enabled: false Enabled: false
# Offense count: 12 # Offense count: 9
# Cop supports --auto-correct. # Cop supports --auto-correct.
Performance/PushSplat: Performance/PushSplat:
Enabled: false Enabled: false
...@@ -59,51 +59,51 @@ Performance/RedundantBlockCall: ...@@ -59,51 +59,51 @@ Performance/RedundantBlockCall:
Performance/RedundantMatch: Performance/RedundantMatch:
Enabled: false Enabled: false
# Offense count: 24 # Offense count: 27
# Cop supports --auto-correct. # Cop supports --auto-correct.
# Configuration parameters: MaxKeyValuePairs. # Configuration parameters: MaxKeyValuePairs.
Performance/RedundantMerge: Performance/RedundantMerge:
Enabled: false Enabled: false
# Offense count: 60 # Offense count: 61
Rails/OutputSafety: Rails/OutputSafety:
Enabled: false Enabled: false
# Offense count: 128 # Offense count: 129
# Configuration parameters: EnforcedStyle, SupportedStyles. # Configuration parameters: EnforcedStyle, SupportedStyles.
# SupportedStyles: strict, flexible # SupportedStyles: strict, flexible
Rails/TimeZone: Rails/TimeZone:
Enabled: false Enabled: false
# Offense count: 12 # Offense count: 15
# Cop supports --auto-correct. # Cop supports --auto-correct.
# Configuration parameters: Include. # Configuration parameters: Include.
# Include: app/models/**/*.rb # Include: app/models/**/*.rb
Rails/Validation: Rails/Validation:
Enabled: false Enabled: false
# Offense count: 217 # Offense count: 273
# Cop supports --auto-correct. # Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle, SupportedStyles, IndentationWidth. # Configuration parameters: EnforcedStyle, SupportedStyles, IndentationWidth.
# SupportedStyles: with_first_parameter, with_fixed_indentation # SupportedStyles: with_first_parameter, with_fixed_indentation
Style/AlignParameters: Style/AlignParameters:
Enabled: false Enabled: false
# Offense count: 32 # Offense count: 30
# Cop supports --auto-correct. # Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle, SupportedStyles. # Configuration parameters: EnforcedStyle, SupportedStyles.
# SupportedStyles: always, conditionals # SupportedStyles: always, conditionals
Style/AndOr: Style/AndOr:
Enabled: false Enabled: false
# Offense count: 47 # Offense count: 50
# Cop supports --auto-correct. # Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle, SupportedStyles. # Configuration parameters: EnforcedStyle, SupportedStyles.
# SupportedStyles: percent_q, bare_percent # SupportedStyles: percent_q, bare_percent
Style/BarePercentLiterals: Style/BarePercentLiterals:
Enabled: false Enabled: false
# Offense count: 258 # Offense count: 289
# Cop supports --auto-correct. # Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle, SupportedStyles. # Configuration parameters: EnforcedStyle, SupportedStyles.
# SupportedStyles: braces, no_braces, context_dependent # SupportedStyles: braces, no_braces, context_dependent
...@@ -126,14 +126,14 @@ Style/ColonMethodCall: ...@@ -126,14 +126,14 @@ Style/ColonMethodCall:
Style/CommentAnnotation: Style/CommentAnnotation:
Enabled: false Enabled: false
# Offense count: 34 # Offense count: 33
# Cop supports --auto-correct. # Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle, SupportedStyles, SingleLineConditionsOnly. # Configuration parameters: EnforcedStyle, SupportedStyles, SingleLineConditionsOnly.
# SupportedStyles: assign_to_condition, assign_inside_condition # SupportedStyles: assign_to_condition, assign_inside_condition
Style/ConditionalAssignment: Style/ConditionalAssignment:
Enabled: false Enabled: false
# Offense count: 789 # Offense count: 881
# Cop supports --auto-correct. # Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle, SupportedStyles. # Configuration parameters: EnforcedStyle, SupportedStyles.
# SupportedStyles: leading, trailing # SupportedStyles: leading, trailing
...@@ -144,11 +144,12 @@ Style/DotPosition: ...@@ -144,11 +144,12 @@ Style/DotPosition:
Style/DoubleNegation: Style/DoubleNegation:
Enabled: false Enabled: false
# Offense count: 3 # Offense count: 4
# Cop supports --auto-correct.
Style/EachWithObject: Style/EachWithObject:
Enabled: false Enabled: false
# Offense count: 30 # Offense count: 25
# Cop supports --auto-correct. # Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle, SupportedStyles. # Configuration parameters: EnforcedStyle, SupportedStyles.
# SupportedStyles: empty, nil, both # SupportedStyles: empty, nil, both
...@@ -160,7 +161,7 @@ Style/EmptyElse: ...@@ -160,7 +161,7 @@ Style/EmptyElse:
Style/EmptyLiteral: Style/EmptyLiteral:
Enabled: false Enabled: false
# Offense count: 123 # Offense count: 135
# Cop supports --auto-correct. # Cop supports --auto-correct.
# Configuration parameters: AllowForAlignment, ForceEqualSignAlignment. # Configuration parameters: AllowForAlignment, ForceEqualSignAlignment.
Style/ExtraSpacing: Style/ExtraSpacing:
...@@ -172,16 +173,16 @@ Style/ExtraSpacing: ...@@ -172,16 +173,16 @@ Style/ExtraSpacing:
Style/FormatString: Style/FormatString:
Enabled: false Enabled: false
# Offense count: 48 # Offense count: 51
# Configuration parameters: MinBodyLength. # Configuration parameters: MinBodyLength.
Style/GuardClause: Style/GuardClause:
Enabled: false Enabled: false
# Offense count: 11 # Offense count: 9
Style/IfInsideElse: Style/IfInsideElse:
Enabled: false Enabled: false
# Offense count: 177 # Offense count: 174
# Cop supports --auto-correct. # Cop supports --auto-correct.
# Configuration parameters: MaxLineLength. # Configuration parameters: MaxLineLength.
Style/IfUnlessModifier: Style/IfUnlessModifier:
...@@ -194,7 +195,7 @@ Style/IfUnlessModifier: ...@@ -194,7 +195,7 @@ Style/IfUnlessModifier:
Style/IndentArray: Style/IndentArray:
Enabled: false Enabled: false
# Offense count: 89 # Offense count: 97
# Cop supports --auto-correct. # Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle, SupportedStyles, IndentationWidth. # Configuration parameters: EnforcedStyle, SupportedStyles, IndentationWidth.
# SupportedStyles: special_inside_parentheses, consistent, align_braces # SupportedStyles: special_inside_parentheses, consistent, align_braces
...@@ -208,7 +209,7 @@ Style/IndentHash: ...@@ -208,7 +209,7 @@ Style/IndentHash:
Style/Lambda: Style/Lambda:
Enabled: false Enabled: false
# Offense count: 6 # Offense count: 5
# Cop supports --auto-correct. # Cop supports --auto-correct.
Style/LineEndConcatenation: Style/LineEndConcatenation:
Enabled: false Enabled: false
...@@ -218,17 +219,21 @@ Style/LineEndConcatenation: ...@@ -218,17 +219,21 @@ Style/LineEndConcatenation:
Style/MethodCallParentheses: Style/MethodCallParentheses:
Enabled: false Enabled: false
# Offense count: 62 # Offense count: 8
Style/MethodMissing:
Enabled: false
# Offense count: 85
# Cop supports --auto-correct. # Cop supports --auto-correct.
Style/MutableConstant: Style/MutableConstant:
Enabled: false Enabled: false
# Offense count: 10 # Offense count: 8
# Cop supports --auto-correct. # Cop supports --auto-correct.
Style/NestedParenthesizedCalls: Style/NestedParenthesizedCalls:
Enabled: false Enabled: false
# Offense count: 12 # Offense count: 13
# Cop supports --auto-correct. # Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle, MinBodyLength, SupportedStyles. # Configuration parameters: EnforcedStyle, MinBodyLength, SupportedStyles.
# SupportedStyles: skip_modifier_ifs, always # SupportedStyles: skip_modifier_ifs, always
...@@ -242,12 +247,19 @@ Style/Next: ...@@ -242,12 +247,19 @@ Style/Next:
Style/NumericLiteralPrefix: Style/NumericLiteralPrefix:
Enabled: false Enabled: false
# Offense count: 64
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle, SupportedStyles.
# SupportedStyles: predicate, comparison
Style/NumericPredicate:
Enabled: false
# Offense count: 29 # Offense count: 29
# Cop supports --auto-correct. # Cop supports --auto-correct.
Style/ParallelAssignment: Style/ParallelAssignment:
Enabled: false Enabled: false
# Offense count: 208 # Offense count: 264
# Cop supports --auto-correct. # Cop supports --auto-correct.
# Configuration parameters: PreferredDelimiters. # Configuration parameters: PreferredDelimiters.
Style/PercentLiteralDelimiters: Style/PercentLiteralDelimiters:
...@@ -265,7 +277,7 @@ Style/PercentQLiterals: ...@@ -265,7 +277,7 @@ Style/PercentQLiterals:
Style/PerlBackrefs: Style/PerlBackrefs:
Enabled: false Enabled: false
# Offense count: 32 # Offense count: 35
# Configuration parameters: NamePrefix, NamePrefixBlacklist, NameWhitelist. # Configuration parameters: NamePrefix, NamePrefixBlacklist, NameWhitelist.
# NamePrefix: is_, has_, have_ # NamePrefix: is_, has_, have_
# NamePrefixBlacklist: is_, has_, have_ # NamePrefixBlacklist: is_, has_, have_
...@@ -273,7 +285,7 @@ Style/PerlBackrefs: ...@@ -273,7 +285,7 @@ Style/PerlBackrefs:
Style/PredicateName: Style/PredicateName:
Enabled: false Enabled: false
# Offense count: 28 # Offense count: 27
# Cop supports --auto-correct. # Cop supports --auto-correct.
Style/PreferredHashMethods: Style/PreferredHashMethods:
Enabled: false Enabled: false
...@@ -283,14 +295,14 @@ Style/PreferredHashMethods: ...@@ -283,14 +295,14 @@ Style/PreferredHashMethods:
Style/Proc: Style/Proc:
Enabled: false Enabled: false
# Offense count: 20 # Offense count: 22
# Cop supports --auto-correct. # Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle, SupportedStyles. # Configuration parameters: EnforcedStyle, SupportedStyles.
# SupportedStyles: compact, exploded # SupportedStyles: compact, exploded
Style/RaiseArgs: Style/RaiseArgs:
Enabled: false Enabled: false
# Offense count: 3 # Offense count: 4
# Cop supports --auto-correct. # Cop supports --auto-correct.
Style/RedundantBegin: Style/RedundantBegin:
Enabled: false Enabled: false
...@@ -300,29 +312,29 @@ Style/RedundantBegin: ...@@ -300,29 +312,29 @@ Style/RedundantBegin:
Style/RedundantException: Style/RedundantException:
Enabled: false Enabled: false
# Offense count: 23 # Offense count: 24
# Cop supports --auto-correct. # Cop supports --auto-correct.
Style/RedundantFreeze: Style/RedundantFreeze:
Enabled: false Enabled: false
# Offense count: 377 # Offense count: 408
# Cop supports --auto-correct. # Cop supports --auto-correct.
Style/RedundantSelf: Style/RedundantSelf:
Enabled: false Enabled: false
# Offense count: 94 # Offense count: 93
# Cop supports --auto-correct. # Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle, SupportedStyles, AllowInnerSlashes. # Configuration parameters: EnforcedStyle, SupportedStyles, AllowInnerSlashes.
# SupportedStyles: slashes, percent_r, mixed # SupportedStyles: slashes, percent_r, mixed
Style/RegexpLiteral: Style/RegexpLiteral:
Enabled: false Enabled: false
# Offense count: 17 # Offense count: 18
# Cop supports --auto-correct. # Cop supports --auto-correct.
Style/RescueModifier: Style/RescueModifier:
Enabled: false Enabled: false
# Offense count: 2 # Offense count: 5
# Cop supports --auto-correct. # Cop supports --auto-correct.
Style/SelfAssignment: Style/SelfAssignment:
Enabled: false Enabled: false
...@@ -339,42 +351,42 @@ Style/SingleLineBlockParams: ...@@ -339,42 +351,42 @@ Style/SingleLineBlockParams:
Style/SingleLineMethods: Style/SingleLineMethods:
Enabled: false Enabled: false
# Offense count: 119 # Offense count: 124
# Cop supports --auto-correct. # Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle, SupportedStyles. # Configuration parameters: EnforcedStyle, SupportedStyles.
# SupportedStyles: space, no_space # SupportedStyles: space, no_space
Style/SpaceBeforeBlockBraces: Style/SpaceBeforeBlockBraces:
Enabled: false Enabled: false
# Offense count: 11 # Offense count: 10
# Cop supports --auto-correct. # Cop supports --auto-correct.
# Configuration parameters: AllowForAlignment. # Configuration parameters: AllowForAlignment.
Style/SpaceBeforeFirstArg: Style/SpaceBeforeFirstArg:
Enabled: false Enabled: false
# Offense count: 130 # Offense count: 141
# Cop supports --auto-correct. # Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle, SupportedStyles, EnforcedStyleForEmptyBraces, SpaceBeforeBlockParameters. # Configuration parameters: EnforcedStyle, SupportedStyles, EnforcedStyleForEmptyBraces, SpaceBeforeBlockParameters.
# SupportedStyles: space, no_space # SupportedStyles: space, no_space
Style/SpaceInsideBlockBraces: Style/SpaceInsideBlockBraces:
Enabled: false Enabled: false
# Offense count: 98 # Offense count: 96
# Cop supports --auto-correct. # Cop supports --auto-correct.
Style/SpaceInsideBrackets: Style/SpaceInsideBrackets:
Enabled: false Enabled: false
# Offense count: 60 # Offense count: 62
# Cop supports --auto-correct. # Cop supports --auto-correct.
Style/SpaceInsideParens: Style/SpaceInsideParens:
Enabled: false Enabled: false
# Offense count: 5 # Offense count: 7
# Cop supports --auto-correct. # Cop supports --auto-correct.
Style/SpaceInsidePercentLiteralDelimiters: Style/SpaceInsidePercentLiteralDelimiters:
Enabled: false Enabled: false
# Offense count: 36 # Offense count: 40
# Cop supports --auto-correct. # Cop supports --auto-correct.
# Configuration parameters: SupportedStyles. # Configuration parameters: SupportedStyles.
# SupportedStyles: use_perl_names, use_english_names # SupportedStyles: use_perl_names, use_english_names
...@@ -388,21 +400,28 @@ Style/SpecialGlobalVars: ...@@ -388,21 +400,28 @@ Style/SpecialGlobalVars:
Style/StringLiteralsInInterpolation: Style/StringLiteralsInInterpolation:
Enabled: false Enabled: false
# Offense count: 24 # Offense count: 32
# Cop supports --auto-correct. # Cop supports --auto-correct.
# Configuration parameters: IgnoredMethods. # Configuration parameters: IgnoredMethods.
# IgnoredMethods: respond_to, define_method # IgnoredMethods: respond_to, define_method
Style/SymbolProc: Style/SymbolProc:
Enabled: false Enabled: false
# Offense count: 23 # Offense count: 5
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle, SupportedStyles, AllowSafeAssignment.
# SupportedStyles: require_parentheses, require_no_parentheses
Style/TernaryParentheses:
Enabled: false
# Offense count: 24
# Cop supports --auto-correct. # Cop supports --auto-correct.
# Configuration parameters: EnforcedStyleForMultiline, SupportedStyles. # Configuration parameters: EnforcedStyleForMultiline, SupportedStyles.
# SupportedStyles: comma, consistent_comma, no_comma # SupportedStyles: comma, consistent_comma, no_comma
Style/TrailingCommaInArguments: Style/TrailingCommaInArguments:
Enabled: false Enabled: false
# Offense count: 113 # Offense count: 102
# Cop supports --auto-correct. # Cop supports --auto-correct.
# Configuration parameters: EnforcedStyleForMultiline, SupportedStyles. # Configuration parameters: EnforcedStyleForMultiline, SupportedStyles.
# SupportedStyles: comma, consistent_comma, no_comma # SupportedStyles: comma, consistent_comma, no_comma
...@@ -415,7 +434,7 @@ Style/TrailingCommaInLiteral: ...@@ -415,7 +434,7 @@ Style/TrailingCommaInLiteral:
Style/TrailingUnderscoreVariable: Style/TrailingUnderscoreVariable:
Enabled: false Enabled: false
# Offense count: 90 # Offense count: 76
# Cop supports --auto-correct. # Cop supports --auto-correct.
Style/TrailingWhitespace: Style/TrailingWhitespace:
Enabled: false Enabled: false
...@@ -427,12 +446,12 @@ Style/TrailingWhitespace: ...@@ -427,12 +446,12 @@ Style/TrailingWhitespace:
Style/TrivialAccessors: Style/TrivialAccessors:
Enabled: false Enabled: false
# Offense count: 3 # Offense count: 2
# Cop supports --auto-correct. # Cop supports --auto-correct.
Style/UnlessElse: Style/UnlessElse:
Enabled: false Enabled: false
# Offense count: 13 # Offense count: 14
# Cop supports --auto-correct. # Cop supports --auto-correct.
Style/UnneededInterpolation: Style/UnneededInterpolation:
Enabled: false Enabled: false
......
...@@ -2,22 +2,29 @@ Please view this file on the master branch, on stable branches it's out of date. ...@@ -2,22 +2,29 @@ Please view this file on the master branch, on stable branches it's out of date.
v 8.12.0 (unreleased) v 8.12.0 (unreleased)
- Update the rouge gem to 2.0.6, which adds highlighting support for JSX, Prometheus, and others. !6251 - Update the rouge gem to 2.0.6, which adds highlighting support for JSX, Prometheus, and others. !6251
- Only check :can_resolve permission if the note is resolvable
- Add ability to fork to a specific namespace using API. (ritave) - Add ability to fork to a specific namespace using API. (ritave)
- Cleanup misalignments in Issue list view !6206 - Cleanup misalignments in Issue list view !6206
- Prune events older than 12 months. (ritave) - Prune events older than 12 months. (ritave)
- Prepend blank line to `Closes` message on merge request linked to issue (lukehowell) - Prepend blank line to `Closes` message on merge request linked to issue (lukehowell)
- Filter tags by name !6121 - Filter tags by name !6121
- Update gitlab shell secret file also when it is empty. !3774 (glensc)
- Give project selection dropdowns responsive width, make non-wrapping. - Give project selection dropdowns responsive width, make non-wrapping.
- Make push events have equal vertical spacing. - Make push events have equal vertical spacing.
- Add two-factor recovery endpoint to internal API !5510 - Add two-factor recovery endpoint to internal API !5510
- Pass the "Remember me" value to the U2F authentication form - Pass the "Remember me" value to the U2F authentication form
- Remove vendor prefixes for linear-gradient CSS (ClemMakesApps) - Remove vendor prefixes for linear-gradient CSS (ClemMakesApps)
- Move pushes_since_gc from the database to Redis
- Add font color contrast to external label in admin area (ClemMakesApps) - Add font color contrast to external label in admin area (ClemMakesApps)
- Change logo animation to CSS (ClemMakesApps) - Change logo animation to CSS (ClemMakesApps)
- Instructions for enabling Git packfile bitmaps !6104 - Instructions for enabling Git packfile bitmaps !6104
- Use Search::GlobalService.new in the `GET /projects/search/:query` endpoint
- Fix pagination on user snippets page - Fix pagination on user snippets page
- Fix sorting of issues in API
- Ensure specs on sorting of issues in API are deterministic on MySQL
- Escape search term before passing it to Regexp.new !6241 (winniehell) - Escape search term before passing it to Regexp.new !6241 (winniehell)
- Fix pinned sidebar behavior in smaller viewports !6169 - Fix pinned sidebar behavior in smaller viewports !6169
- Fix file permissions change when updating a file on the Gitlab UI !5979
- Change merge_error column from string to text type - Change merge_error column from string to text type
- Reduce contributions calendar data payload (ClemMakesApps) - Reduce contributions calendar data payload (ClemMakesApps)
- Add `web_url` field to issue, merge request, and snippet API objects (Ben Boeckel) - Add `web_url` field to issue, merge request, and snippet API objects (Ben Boeckel)
...@@ -74,6 +81,7 @@ v 8.12.0 (unreleased) ...@@ -74,6 +81,7 @@ v 8.12.0 (unreleased)
- Remove inconsistent font weight for sidebar's labels (ClemMakesApps) - Remove inconsistent font weight for sidebar's labels (ClemMakesApps)
- Align add button on repository view (ClemMakesApps) - Align add button on repository view (ClemMakesApps)
- Fix contributions calendar month label truncation (ClemMakesApps) - Fix contributions calendar month label truncation (ClemMakesApps)
- Import release note descriptions from GitHub (EspadaV8)
- Added tests for diff notes - Added tests for diff notes
- Add pipeline events to Slack integration !5525 - Add pipeline events to Slack integration !5525
- Add a button to download latest successful artifacts for branches and tags !5142 - Add a button to download latest successful artifacts for branches and tags !5142
...@@ -85,12 +93,14 @@ v 8.12.0 (unreleased) ...@@ -85,12 +93,14 @@ v 8.12.0 (unreleased)
- Fix repo title alignment (ClemMakesApps) - Fix repo title alignment (ClemMakesApps)
- Change update interval of contacted_at - Change update interval of contacted_at
- Fix branch title trailing space on hover (ClemMakesApps) - Fix branch title trailing space on hover (ClemMakesApps)
- Don't include 'Created By' tag line when importing from GitHub if there is a linked GitLab account (EspadaV8)
- Award emoji tooltips containing more than 10 usernames are now truncated !4780 (jlogandavison) - Award emoji tooltips containing more than 10 usernames are now truncated !4780 (jlogandavison)
- Fix duplicate "me" in award emoji tooltip !5218 (jlogandavison) - Fix duplicate "me" in award emoji tooltip !5218 (jlogandavison)
- Order award emoji tooltips in order they were added (EspadaV8) - Order award emoji tooltips in order they were added (EspadaV8)
- Fix spacing and vertical alignment on build status icon on commits page (ClemMakesApps) - Fix spacing and vertical alignment on build status icon on commits page (ClemMakesApps)
- Update merge_requests.md with a simpler way to check out a merge request. !5944 - Update merge_requests.md with a simpler way to check out a merge request. !5944
- Fix button missing type (ClemMakesApps) - Fix button missing type (ClemMakesApps)
- Gitlab::Checks is now instrumented
- Move to project dropdown with infinite scroll for better performance - Move to project dropdown with infinite scroll for better performance
- Fix leaking of submit buttons outside the width of a main container !18731 (originally by @pavelloz) - Fix leaking of submit buttons outside the width of a main container !18731 (originally by @pavelloz)
- Load branches asynchronously in Cherry Pick and Revert dialogs. - Load branches asynchronously in Cherry Pick and Revert dialogs.
...@@ -109,6 +119,8 @@ v 8.12.0 (unreleased) ...@@ -109,6 +119,8 @@ v 8.12.0 (unreleased)
- Avoid conflict with admin labels when importing GitHub labels - Avoid conflict with admin labels when importing GitHub labels
- User can edit closed MR with deleted fork (Katarzyna Kobierska Ula Budziszewska) !5496 - User can edit closed MR with deleted fork (Katarzyna Kobierska Ula Budziszewska) !5496
- Fix repository page ui issues - Fix repository page ui issues
- Avoid protected branches checks when verifying access without branch name
- Add information about user and manual build start to runner as variables !6201 (Sergey Gnuskov)
- Fixed invisible scroll controls on build page on iPhone - Fixed invisible scroll controls on build page on iPhone
- Fix error on raw build trace download for old builds stored in database !4822 - Fix error on raw build trace download for old builds stored in database !4822
- Refactor the triggers page and documentation !6217 - Refactor the triggers page and documentation !6217
...@@ -116,8 +128,24 @@ v 8.12.0 (unreleased) ...@@ -116,8 +128,24 @@ v 8.12.0 (unreleased)
- Use default clone protocol on "check out, review, and merge locally" help page URL - Use default clone protocol on "check out, review, and merge locally" help page URL
- API for Ci Lint !5953 (Katarzyna Kobierska Urszula Budziszewska) - API for Ci Lint !5953 (Katarzyna Kobierska Urszula Budziszewska)
- Allow bulk update merge requests from merge requests index page - Allow bulk update merge requests from merge requests index page
- Add notification_settings API calls !5632 (mahcsig)
v 8.11.6 (unreleased) - Remove duplication between project builds and admin builds view !5680 (Katarzyna Kobierska Ula Budziszewska)
- Fix URLs with anchors in wiki !6300 (houqp)
- Deleting source project with existing fork link will close all related merge requests !6177 (Katarzyna Kobierska Ula Budziszeska)
- Return 204 instead of 404 for /ci/api/v1/builds/register.json if no builds are scheduled for a runner !6225
- Fix Gitlab::Popen.popen thread-safety issue
- Add specs to removing project (Katarzyna Kobierska Ula Budziszewska)
- Clean environment variables when running git hooks
v 8.11.6
- Fix unnecessary horizontal scroll area in pipeline visualizations. !6005
- Make merge conflict file size limit 200 KB, to match the docs. !6052
- Fix an error where we were unable to create a CommitStatus for running state. !6107
- Optimize discussion notes resolving and unresolving. !6141
- Fix GitLab import button. !6167
- Restore SSH Key title auto-population behavior. !6186
- Fix DB schema to match latest migration. !6256
- Exclude some pending or inactivated rows in Member scopes.
v 8.11.5 v 8.11.5
- Optimize branch lookups and force a repository reload for Repository#find_branch. !6087 - Optimize branch lookups and force a repository reload for Repository#find_branch. !6087
...@@ -324,6 +352,13 @@ v 8.11.0 ...@@ -324,6 +352,13 @@ v 8.11.0
- Update gitlab_git gem to 10.4.7 - Update gitlab_git gem to 10.4.7
- Simplify SQL queries of marking a todo as done - Simplify SQL queries of marking a todo as done
v 8.10.9
- Exclude some pending or inactivated rows in Member scopes
v 8.10.8
- Fix information disclosure in issue boards.
- Fix privilege escalation in project import.
v 8.10.7 v 8.10.7
- Upgrade Hamlit to 2.6.1. !5873 - Upgrade Hamlit to 2.6.1. !5873
- Upgrade Doorkeeper to 4.2.0. !5881 - Upgrade Doorkeeper to 4.2.0. !5881
...@@ -553,6 +588,9 @@ v 8.10.0 ...@@ -553,6 +588,9 @@ v 8.10.0
- Fix migration corrupting import data for old version upgrades - Fix migration corrupting import data for old version upgrades
- Show tooltip on GitLab export link in new project page - Show tooltip on GitLab export link in new project page
v 8.9.9
- Exclude some pending or inactivated rows in Member scopes
v 8.9.8 v 8.9.8
- Upgrade Doorkeeper to 4.2.0. !5881 - Upgrade Doorkeeper to 4.2.0. !5881
......
...@@ -91,19 +91,7 @@ This was inspired by [an article by Kent C. Dodds][medium-up-for-grabs]. ...@@ -91,19 +91,7 @@ This was inspired by [an article by Kent C. Dodds][medium-up-for-grabs].
## Implement design & UI elements ## Implement design & UI elements
### Design reference Please see the [UI Guide for building GitLab].
The GitLab design reference can be found in the [gitlab-design] project.
The designs are made using Antetype (`.atype` files). You can use the
[free Antetype viewer (Mac OSX only)] or grab an exported PNG from the design
(the PNG is 1:1).
The current designs can be found in the [`gitlab8.atype` file].
### UI development kit
Implemented UI elements can also be found at https://gitlab.com/help/ui. Please
note that this page isn't comprehensive at this time.
## Issue tracker ## Issue tracker
...@@ -489,7 +477,5 @@ available at [http://contributor-covenant.org/version/1/1/0/](http://contributor ...@@ -489,7 +477,5 @@ available at [http://contributor-covenant.org/version/1/1/0/](http://contributor
[doc-styleguide]: doc/development/doc_styleguide.md "Documentation styleguide" [doc-styleguide]: doc/development/doc_styleguide.md "Documentation styleguide"
[scss-styleguide]: doc/development/scss_styleguide.md "SCSS styleguide" [scss-styleguide]: doc/development/scss_styleguide.md "SCSS styleguide"
[newlines-styleguide]: doc/development/newlines_styleguide.md "Newlines styleguide" [newlines-styleguide]: doc/development/newlines_styleguide.md "Newlines styleguide"
[gitlab-design]: https://gitlab.com/gitlab-org/gitlab-design [UI Guide for building GitLab]: https://gitlab.com/gitlab-org/gitlab-ce/blob/master/doc/development/ui_guide.md
[free Antetype viewer (Mac OSX only)]: https://itunes.apple.com/us/app/antetype-viewer/id824152298?mt=12
[`gitlab8.atype` file]: https://gitlab.com/gitlab-org/gitlab-design/tree/master/current/
[license-finder-doc]: doc/development/licensing.md [license-finder-doc]: doc/development/licensing.md
...@@ -26,7 +26,7 @@ gem 'omniauth-auth0', '~> 1.4.1' ...@@ -26,7 +26,7 @@ gem 'omniauth-auth0', '~> 1.4.1'
gem 'omniauth-azure-oauth2', '~> 0.0.6' gem 'omniauth-azure-oauth2', '~> 0.0.6'
gem 'omniauth-bitbucket', '~> 0.0.2' gem 'omniauth-bitbucket', '~> 0.0.2'
gem 'omniauth-cas3', '~> 1.1.2' gem 'omniauth-cas3', '~> 1.1.2'
gem 'omniauth-facebook', '~> 3.0.0' gem 'omniauth-facebook', '~> 4.0.0'
gem 'omniauth-github', '~> 1.1.1' gem 'omniauth-github', '~> 1.1.1'
gem 'omniauth-gitlab', '~> 1.0.0' gem 'omniauth-gitlab', '~> 1.0.0'
gem 'omniauth-google-oauth2', '~> 0.4.1' gem 'omniauth-google-oauth2', '~> 0.4.1'
...@@ -57,7 +57,7 @@ gem 'browser', '~> 2.2' ...@@ -57,7 +57,7 @@ gem 'browser', '~> 2.2'
# Extracting information from a git repository # Extracting information from a git repository
# Provide access to Gitlab::Git library # Provide access to Gitlab::Git library
gem 'gitlab_git', '~> 10.6.3' gem 'gitlab_git', '~> 10.6.6'
# LDAP Auth # LDAP Auth
# GitLab fork with several improvements to original library. For full list of changes # GitLab fork with several improvements to original library. For full list of changes
...@@ -306,9 +306,10 @@ group :development, :test do ...@@ -306,9 +306,10 @@ group :development, :test do
gem 'spring-commands-spinach', '~> 1.1.0' gem 'spring-commands-spinach', '~> 1.1.0'
gem 'spring-commands-teaspoon', '~> 0.0.2' gem 'spring-commands-teaspoon', '~> 0.0.2'
gem 'rubocop', '~> 0.41.2', require: false gem 'rubocop', '~> 0.42.0', require: false
gem 'rubocop-rspec', '~> 1.5.0', require: false gem 'rubocop-rspec', '~> 1.5.0', require: false
gem 'scss_lint', '~> 0.47.0', require: false gem 'scss_lint', '~> 0.47.0', require: false
gem 'haml_lint', '~> 0.18.2', require: false
gem 'simplecov', '0.12.0', require: false gem 'simplecov', '0.12.0', require: false
gem 'flog', '~> 4.3.2', require: false gem 'flog', '~> 4.3.2', require: false
gem 'flay', '~> 2.6.1', require: false gem 'flay', '~> 2.6.1', require: false
......
...@@ -301,7 +301,7 @@ GEM ...@@ -301,7 +301,7 @@ GEM
mime-types (>= 1.16, < 3) mime-types (>= 1.16, < 3)
posix-spawn (~> 0.3) posix-spawn (~> 0.3)
gitlab-license (1.0.0) gitlab-license (1.0.0)
gitlab_git (10.6.3) gitlab_git (10.6.6)
activesupport (~> 4.0) activesupport (~> 4.0)
charlock_holmes (~> 0.7.3) charlock_holmes (~> 0.7.3)
github-linguist (~> 4.7.0) github-linguist (~> 4.7.0)
...@@ -346,11 +346,18 @@ GEM ...@@ -346,11 +346,18 @@ GEM
multi_json (>= 1.3.2) multi_json (>= 1.3.2)
gssapi (1.2.0) gssapi (1.2.0)
ffi (>= 1.0.1) ffi (>= 1.0.1)
haml (4.0.7)
tilt
haml_lint (0.18.2)
haml (~> 4.0)
rake (>= 10, < 12)
rubocop (>= 0.36.0)
sysexits (~> 1.1)
hamlit (2.6.1) hamlit (2.6.1)
temple (~> 0.7.6) temple (~> 0.7.6)
thor thor
tilt tilt
hashie (3.4.3) hashie (3.4.4)
health_check (2.1.0) health_check (2.1.0)
rails (>= 4.0) rails (>= 4.0)
hipchat (1.5.2) hipchat (1.5.2)
...@@ -418,7 +425,7 @@ GEM ...@@ -418,7 +425,7 @@ GEM
mime-types (>= 1.16, < 4) mime-types (>= 1.16, < 4)
mail_room (0.8.0) mail_room (0.8.0)
method_source (0.8.2) method_source (0.8.2)
mime-types (2.99.2) mime-types (2.99.3)
mimemagic (0.3.0) mimemagic (0.3.0)
mini_portile2 (2.1.0) mini_portile2 (2.1.0)
minitest (5.7.0) minitest (5.7.0)
...@@ -461,7 +468,7 @@ GEM ...@@ -461,7 +468,7 @@ GEM
addressable (~> 2.3) addressable (~> 2.3)
nokogiri (~> 1.6.6) nokogiri (~> 1.6.6)
omniauth (~> 1.2) omniauth (~> 1.2)
omniauth-facebook (3.0.0) omniauth-facebook (4.0.0)
omniauth-oauth2 (~> 1.2) omniauth-oauth2 (~> 1.2)
omniauth-github (1.1.2) omniauth-github (1.1.2)
omniauth (~> 1.0) omniauth (~> 1.0)
...@@ -636,7 +643,7 @@ GEM ...@@ -636,7 +643,7 @@ GEM
rspec-retry (0.4.5) rspec-retry (0.4.5)
rspec-core rspec-core
rspec-support (3.5.0) rspec-support (3.5.0)
rubocop (0.41.2) rubocop (0.42.0)
parser (>= 2.3.1.1, < 3.0) parser (>= 2.3.1.1, < 3.0)
powerpack (~> 0.1) powerpack (~> 0.1)
rainbow (>= 1.99.1, < 3.0) rainbow (>= 1.99.1, < 3.0)
...@@ -747,6 +754,7 @@ GEM ...@@ -747,6 +754,7 @@ GEM
stringex (2.5.2) stringex (2.5.2)
sys-filesystem (1.1.6) sys-filesystem (1.1.6)
ffi ffi
sysexits (1.2.0)
systemu (2.6.5) systemu (2.6.5)
task_list (1.0.2) task_list (1.0.2)
html-pipeline html-pipeline
...@@ -778,7 +786,7 @@ GEM ...@@ -778,7 +786,7 @@ GEM
unf (0.1.4) unf (0.1.4)
unf_ext unf_ext
unf_ext (0.0.7.2) unf_ext (0.0.7.2)
unicode-display_width (1.1.0) unicode-display_width (1.1.1)
unicorn (4.9.0) unicorn (4.9.0)
kgio (~> 2.6) kgio (~> 2.6)
rack rack
...@@ -889,7 +897,7 @@ DEPENDENCIES ...@@ -889,7 +897,7 @@ DEPENDENCIES
gitlab-elasticsearch-git (~> 1.0.1) gitlab-elasticsearch-git (~> 1.0.1)
gitlab-flowdock-git-hook (~> 1.0.1) gitlab-flowdock-git-hook (~> 1.0.1)
gitlab-license (~> 1.0) gitlab-license (~> 1.0)
gitlab_git (~> 10.6.3) gitlab_git (~> 10.6.6)
gitlab_meta (= 7.0) gitlab_meta (= 7.0)
gitlab_omniauth-ldap (~> 1.2.1) gitlab_omniauth-ldap (~> 1.2.1)
gollum-lib (~> 4.2) gollum-lib (~> 4.2)
...@@ -898,6 +906,7 @@ DEPENDENCIES ...@@ -898,6 +906,7 @@ DEPENDENCIES
grape (~> 0.15.0) grape (~> 0.15.0)
grape-entity (~> 0.4.2) grape-entity (~> 0.4.2)
gssapi gssapi
haml_lint (~> 0.18.2)
hamlit (~> 2.6.1) hamlit (~> 2.6.1)
health_check (~> 2.1.0) health_check (~> 2.1.0)
hipchat (~> 1.5.0) hipchat (~> 1.5.0)
...@@ -933,7 +942,7 @@ DEPENDENCIES ...@@ -933,7 +942,7 @@ DEPENDENCIES
omniauth-azure-oauth2 (~> 0.0.6) omniauth-azure-oauth2 (~> 0.0.6)
omniauth-bitbucket (~> 0.0.2) omniauth-bitbucket (~> 0.0.2)
omniauth-cas3 (~> 1.1.2) omniauth-cas3 (~> 1.1.2)
omniauth-facebook (~> 3.0.0) omniauth-facebook (~> 4.0.0)
omniauth-github (~> 1.1.1) omniauth-github (~> 1.1.1)
omniauth-gitlab (~> 1.0.0) omniauth-gitlab (~> 1.0.0)
omniauth-google-oauth2 (~> 0.4.1) omniauth-google-oauth2 (~> 0.4.1)
...@@ -968,7 +977,7 @@ DEPENDENCIES ...@@ -968,7 +977,7 @@ DEPENDENCIES
rqrcode-rails3 (~> 0.1.7) rqrcode-rails3 (~> 0.1.7)
rspec-rails (~> 3.5.0) rspec-rails (~> 3.5.0)
rspec-retry (~> 0.4.5) rspec-retry (~> 0.4.5)
rubocop (~> 0.41.2) rubocop (~> 0.42.0)
rubocop-rspec (~> 1.5.0) rubocop-rspec (~> 1.5.0)
ruby-fogbugz (~> 0.2.1) ruby-fogbugz (~> 0.2.1)
ruby-prof (~> 0.15.9) ruby-prof (~> 0.15.9)
......
...@@ -79,10 +79,6 @@ ...@@ -79,10 +79,6 @@
padding-left: 15px !important; padding-left: 15px !important;
} }
.issue-info, .merge-request-info {
display: none;
}
.nav-links, .nav-links { .nav-links, .nav-links {
li a { li a {
font-size: 14px; font-size: 14px;
......
...@@ -206,7 +206,7 @@ ...@@ -206,7 +206,7 @@
padding-top: 0; padding-top: 0;
.block { .block {
width: $sidebar_collapsed_width - 1px; width: $sidebar_collapsed_width - 2px;
margin-left: -19px; margin-left: -19px;
padding: 15px 0 0; padding: 15px 0 0;
border-bottom: none; border-bottom: none;
......
...@@ -37,6 +37,15 @@ form.edit-issue { ...@@ -37,6 +37,15 @@ form.edit-issue {
margin: 0; margin: 0;
} }
ul.related-merge-requests > li {
display: -ms-flexbox;
display: -webkit-flex;
display: flex;
.merge-request-id {
flex-shrink: 0;
}
}
.merge-requests-title, .related-branches-title { .merge-requests-title, .related-branches-title {
font-size: 16px; font-size: 16px;
font-weight: 600; font-weight: 600;
......
...@@ -334,6 +334,10 @@ a.deploy-project-label { ...@@ -334,6 +334,10 @@ a.deploy-project-label {
a { a {
color: $gl-dark-link-color; color: $gl-dark-link-color;
} }
.dropdown-menu {
width: 240px;
}
} }
.last-push-widget { .last-push-widget {
......
...@@ -7,8 +7,7 @@ module CreatesCommit ...@@ -7,8 +7,7 @@ module CreatesCommit
commit_params = @commit_params.merge( commit_params = @commit_params.merge(
source_project: @project, source_project: @project,
source_branch: @ref, source_branch: @ref,
target_branch: @target_branch, target_branch: @target_branch
previous_path: @previous_path
) )
result = service.new(@tree_edit_project, current_user, commit_params).execute result = service.new(@tree_edit_project, current_user, commit_params).execute
......
...@@ -38,12 +38,7 @@ class Projects::BlobController < Projects::ApplicationController ...@@ -38,12 +38,7 @@ class Projects::BlobController < Projects::ApplicationController
end end
def update def update
if params[:file_path].present? @path = params[:file_path] if params[:file_path].present?
@previous_path = @path
@path = params[:file_path]
@commit_params[:file_path] = @path
end
after_edit_path = after_edit_path =
if from_merge_request && @target_branch == @ref if from_merge_request && @target_branch == @ref
diffs_namespace_project_merge_request_path(from_merge_request.target_project.namespace, from_merge_request.target_project, from_merge_request) + diffs_namespace_project_merge_request_path(from_merge_request.target_project.namespace, from_merge_request.target_project, from_merge_request) +
...@@ -143,6 +138,8 @@ class Projects::BlobController < Projects::ApplicationController ...@@ -143,6 +138,8 @@ class Projects::BlobController < Projects::ApplicationController
params[:file_name] = params[:file].original_filename params[:file_name] = params[:file].original_filename
end end
File.join(@path, params[:file_name]) File.join(@path, params[:file_name])
elsif params[:file_path].present?
params[:file_path]
else else
@path @path
end end
...@@ -155,6 +152,7 @@ class Projects::BlobController < Projects::ApplicationController ...@@ -155,6 +152,7 @@ class Projects::BlobController < Projects::ApplicationController
@commit_params = { @commit_params = {
file_path: @file_path, file_path: @file_path,
commit_message: params[:commit_message], commit_message: params[:commit_message],
previous_path: @path,
file_content: params[:content], file_content: params[:content],
file_content_encoding: params[:encoding], file_content_encoding: params[:encoding],
last_commit_sha: params[:last_commit_sha] last_commit_sha: params[:last_commit_sha]
......
...@@ -468,17 +468,11 @@ class Projects::MergeRequestsController < Projects::ApplicationController ...@@ -468,17 +468,11 @@ class Projects::MergeRequestsController < Projects::ApplicationController
end end
def validates_merge_request def validates_merge_request
# If source project was removed (Ex. mr from fork to origin)
return invalid_mr unless @merge_request.source_project
# Show git not found page # Show git not found page
# if there is no saved commits between source & target branch # if there is no saved commits between source & target branch
if @merge_request.commits.blank? if @merge_request.commits.blank?
# and if target branch doesn't exist # and if target branch doesn't exist
return invalid_mr unless @merge_request.target_branch_exists? return invalid_mr unless @merge_request.target_branch_exists?
# or if source branch doesn't exist
return invalid_mr unless @merge_request.source_branch_exists?
end end
end end
......
...@@ -22,6 +22,18 @@ class Blob < SimpleDelegator ...@@ -22,6 +22,18 @@ class Blob < SimpleDelegator
new(blob) new(blob)
end end
# Returns the data of the blob.
#
# If the blob is a text based blob the content is converted to UTF-8 and any
# invalid byte sequences are replaced.
def data
if binary?
super
else
@data ||= super.encode(Encoding::UTF_8, invalid: :replace, undef: :replace)
end
end
def no_highlighting? def no_highlighting?
size && size > 1.megabyte size && size > 1.megabyte
end end
......
...@@ -148,6 +148,7 @@ module Ci ...@@ -148,6 +148,7 @@ module Ci
variables += runner.predefined_variables if runner variables += runner.predefined_variables if runner
variables += project.container_registry_variables variables += project.container_registry_variables
variables += yaml_variables variables += yaml_variables
variables += user_variables
variables += project.secret_variables variables += project.secret_variables
variables += trigger_request.user_variables if trigger_request variables += trigger_request.user_variables if trigger_request
variables variables
...@@ -435,6 +436,15 @@ module Ci ...@@ -435,6 +436,15 @@ module Ci
read_attribute(:yaml_variables) || build_attributes_from_config[:yaml_variables] || [] read_attribute(:yaml_variables) || build_attributes_from_config[:yaml_variables] || []
end end
def user_variables
return [] if user.blank?
[
{ key: 'GITLAB_USER_ID', value: user.id.to_s, public: true },
{ key: 'GITLAB_USER_EMAIL', value: user.email, public: true }
]
end
private private
def update_artifacts_size def update_artifacts_size
...@@ -470,6 +480,7 @@ module Ci ...@@ -470,6 +480,7 @@ module Ci
] ]
variables << { key: 'CI_BUILD_TAG', value: ref, public: true } if tag? variables << { key: 'CI_BUILD_TAG', value: ref, public: true } if tag?
variables << { key: 'CI_BUILD_TRIGGERED', value: 'true', public: true } if trigger_request variables << { key: 'CI_BUILD_TRIGGERED', value: 'true', public: true } if trigger_request
variables << { key: 'CI_BUILD_MANUAL', value: 'true', public: true } if manual?
variables variables
end end
......
...@@ -69,17 +69,15 @@ class CommitStatus < ActiveRecord::Base ...@@ -69,17 +69,15 @@ class CommitStatus < ActiveRecord::Base
commit_status.update_attributes finished_at: Time.now commit_status.update_attributes finished_at: Time.now
end end
# We use around_transition to process pipeline on next stages as soon as possible, before the `after_*` is executed
around_transition any => [:success, :failed, :canceled] do |commit_status, block|
block.call
commit_status.pipeline.try(:process!)
end
after_transition do |commit_status, transition| after_transition do |commit_status, transition|
commit_status.pipeline.try(:build_updated) unless transition.loopback? commit_status.pipeline.try(:build_updated) unless transition.loopback?
end end
after_transition any => [:success, :failed, :canceled] do |commit_status|
commit_status.pipeline.try(:process!)
true
end
after_transition [:created, :pending, :running] => :success do |commit_status| after_transition [:created, :pending, :running] => :success do |commit_status|
MergeRequests::MergeWhenBuildSucceedsService.new(commit_status.pipeline.project, nil).trigger(commit_status) MergeRequests::MergeWhenBuildSucceedsService.new(commit_status.pipeline.project, nil).trigger(commit_status)
end end
......
...@@ -8,8 +8,9 @@ module HasStatus ...@@ -8,8 +8,9 @@ module HasStatus
class_methods do class_methods do
def status_sql def status_sql
scope = all.relevant scope = all
builds = scope.select('count(*)').to_sql builds = scope.select('count(*)').to_sql
created = scope.created.select('count(*)').to_sql
success = scope.success.select('count(*)').to_sql success = scope.success.select('count(*)').to_sql
ignored = scope.ignored.select('count(*)').to_sql if scope.respond_to?(:ignored) ignored = scope.ignored.select('count(*)').to_sql if scope.respond_to?(:ignored)
ignored ||= '0' ignored ||= '0'
...@@ -19,12 +20,12 @@ module HasStatus ...@@ -19,12 +20,12 @@ module HasStatus
skipped = scope.skipped.select('count(*)').to_sql skipped = scope.skipped.select('count(*)').to_sql
deduce_status = "(CASE deduce_status = "(CASE
WHEN (#{builds})=0 THEN NULL WHEN (#{builds})=(#{created}) THEN NULL
WHEN (#{builds})=(#{skipped}) THEN 'skipped' WHEN (#{builds})=(#{skipped}) THEN 'skipped'
WHEN (#{builds})=(#{success})+(#{ignored})+(#{skipped}) THEN 'success' WHEN (#{builds})=(#{success})+(#{ignored})+(#{skipped}) THEN 'success'
WHEN (#{builds})=(#{pending})+(#{skipped}) THEN 'pending' WHEN (#{builds})=(#{created})+(#{pending})+(#{skipped}) THEN 'pending'
WHEN (#{builds})=(#{canceled})+(#{success})+(#{ignored})+(#{skipped}) THEN 'canceled' WHEN (#{builds})=(#{canceled})+(#{success})+(#{ignored})+(#{skipped}) THEN 'canceled'
WHEN (#{running})+(#{pending})>0 THEN 'running' WHEN (#{running})+(#{pending})+(#{created})>0 THEN 'running'
ELSE 'failed' ELSE 'failed'
END)" END)"
......
...@@ -29,17 +29,34 @@ class Member < ActiveRecord::Base ...@@ -29,17 +29,34 @@ class Member < ActiveRecord::Base
allow_nil: true allow_nil: true
} }
# This scope encapsulates (most of) the conditions a row in the member table
# must satisfy if it is a valid permission. Of particular note:
#
# * Access requests must be excluded
# * Blocked users must be excluded
# * Invitations take effect immediately
# * expires_at is not implemented. A background worker purges expired rows
scope :active, -> do
is_external_invite = arel_table[:user_id].eq(nil).and(arel_table[:invite_token].not_eq(nil))
user_is_active = User.arel_table[:state].eq(:active)
includes(:user).references(:users)
.where(is_external_invite.or(user_is_active))
.where(requested_at: nil)
end
scope :invite, -> { where.not(invite_token: nil) } scope :invite, -> { where.not(invite_token: nil) }
scope :non_invite, -> { where(invite_token: nil) } scope :non_invite, -> { where(invite_token: nil) }
scope :request, -> { where.not(requested_at: nil) } scope :request, -> { where.not(requested_at: nil) }
scope :has_access, -> { where('access_level > 0') }
scope :has_access, -> { active.where('access_level > 0') }
scope :guests, -> { where(access_level: GUEST) }
scope :reporters, -> { where(access_level: REPORTER) } scope :guests, -> { active.where(access_level: GUEST) }
scope :developers, -> { where(access_level: DEVELOPER) } scope :reporters, -> { active.where(access_level: REPORTER) }
scope :masters, -> { where(access_level: MASTER) } scope :developers, -> { active.where(access_level: DEVELOPER) }
scope :owners, -> { where(access_level: OWNER) } scope :masters, -> { active.where(access_level: MASTER) }
scope :owners_and_masters, -> { where(access_level: [OWNER, MASTER]) } scope :owners, -> { active.where(access_level: OWNER) }
scope :owners_and_masters, -> { active.where(access_level: [OWNER, MASTER]) }
before_validation :generate_invite_token, on: :create, if: -> (member) { member.invite_email.present? } before_validation :generate_invite_token, on: :create, if: -> (member) { member.invite_email.present? }
......
...@@ -321,6 +321,10 @@ class MergeRequest < ActiveRecord::Base ...@@ -321,6 +321,10 @@ class MergeRequest < ActiveRecord::Base
closed? && forked_source_project_missing? closed? && forked_source_project_missing?
end end
def closed_without_source_project?
closed? && !source_project
end
def forked_source_project_missing? def forked_source_project_missing?
return false unless for_fork? return false unless for_fork?
return true unless source_project return true unless source_project
...@@ -344,6 +348,12 @@ class MergeRequest < ActiveRecord::Base ...@@ -344,6 +348,12 @@ class MergeRequest < ActiveRecord::Base
end end
end end
def reopenable?
return false if closed_without_fork? || closed_without_source_project? || merged?
closed?
end
def ensure_merge_request_diff def ensure_merge_request_diff
merge_request_diff || create_merge_request_diff merge_request_diff || create_merge_request_diff
end end
......
...@@ -52,7 +52,7 @@ class Project < ActiveRecord::Base ...@@ -52,7 +52,7 @@ class Project < ActiveRecord::Base
# Relations # Relations
belongs_to :creator, foreign_key: 'creator_id', class_name: 'User' belongs_to :creator, foreign_key: 'creator_id', class_name: 'User'
belongs_to :group, -> { where(type: Group) }, foreign_key: 'namespace_id' belongs_to :group, -> { where(type: 'Group') }, foreign_key: 'namespace_id'
belongs_to :namespace belongs_to :namespace
belongs_to :mirror_user, foreign_key: 'mirror_user_id', class_name: 'User' belongs_to :mirror_user, foreign_key: 'mirror_user_id', class_name: 'User'
...@@ -1526,8 +1526,24 @@ class Project < ActiveRecord::Base ...@@ -1526,8 +1526,24 @@ class Project < ActiveRecord::Base
self.repository_read_only = true self.repository_read_only = true
end end
def pushes_since_gc
Gitlab::Redis.with { |redis| redis.get(pushes_since_gc_redis_key).to_i }
end
def increment_pushes_since_gc
Gitlab::Redis.with { |redis| redis.incr(pushes_since_gc_redis_key) }
end
def reset_pushes_since_gc
Gitlab::Redis.with { |redis| redis.del(pushes_since_gc_redis_key) }
end
private private
def pushes_since_gc_redis_key
"projects/#{id}/pushes_since_gc"
end
# Prevents the creation of project_feature record for every project # Prevents the creation of project_feature record for every project
def setup_project_feature def setup_project_feature
build_project_feature unless project_feature build_project_feature unless project_feature
......
...@@ -897,7 +897,7 @@ class Repository ...@@ -897,7 +897,7 @@ class Repository
update: true update: true
} }
if previous_path if previous_path && previous_path != path
options[:file][:previous_path] = previous_path options[:file][:previous_path] = previous_path
Gitlab::Git::Blob.rename(raw_repository, options) Gitlab::Git::Blob.rename(raw_repository, options)
else else
......
...@@ -31,13 +31,13 @@ module Ci ...@@ -31,13 +31,13 @@ module Ci
current_status = status_for_prior_stages(index) current_status = status_for_prior_stages(index)
created_builds_in_stage(index).select do |build| created_builds_in_stage(index).select do |build|
if HasStatus::COMPLETED_STATUSES.include?(current_status)
process_build(build, current_status) process_build(build, current_status)
end end
end end
end
def process_build(build, current_status) def process_build(build, current_status)
return false unless HasStatus::COMPLETED_STATUSES.include?(current_status)
if valid_statuses_for_when(build.when).include?(current_status) if valid_statuses_for_when(build.when).include?(current_status)
build.enqueue build.enqueue
true true
......
...@@ -24,6 +24,8 @@ module Projects ...@@ -24,6 +24,8 @@ module Projects
# Git data (e.g. a list of branch names). # Git data (e.g. a list of branch names).
flush_caches(project, wiki_path) flush_caches(project, wiki_path)
Projects::UnlinkForkService.new(project, current_user).execute
Project.transaction do Project.transaction do
project.destroy! project.destroy!
trash_repositories! trash_repositories!
......
...@@ -30,10 +30,8 @@ module Projects ...@@ -30,10 +30,8 @@ module Projects
end end
def increment! def increment!
if Gitlab::ExclusiveLease.new("project_housekeeping:increment!:#{@project.id}", timeout: 60).try_obtain
Gitlab::Metrics.measure(:increment_pushes_since_gc) do Gitlab::Metrics.measure(:increment_pushes_since_gc) do
update_pushes_since_gc(@project.pushes_since_gc + 1) @project.increment_pushes_since_gc
end
end end
end end
...@@ -43,12 +41,8 @@ module Projects ...@@ -43,12 +41,8 @@ module Projects
GitGarbageCollectWorker.perform_async(@project.id) GitGarbageCollectWorker.perform_async(@project.id)
ensure ensure
Gitlab::Metrics.measure(:reset_pushes_since_gc) do Gitlab::Metrics.measure(:reset_pushes_since_gc) do
update_pushes_since_gc(0) @project.reset_pushes_since_gc
end
end end
def update_pushes_since_gc(new_value)
@project.update_column(:pushes_since_gc, new_value)
end end
def try_obtain_lease def try_obtain_lease
......
- project = build.project
%tr.build.commit
%td.status
= ci_status_with_icon(build.status)
%td
.branch-commit
- if can?(current_user, :read_build, build.project)
= link_to namespace_project_build_url(build.project.namespace, build.project, build) do
%span.build-link ##{build.id}
- else
%span.build-link ##{build.id}
- if build.ref
.icon-container
= build.tag? ? icon('tag') : icon('code-fork')
= link_to build.ref, namespace_project_commits_path(build.project.namespace, build.project, build.ref), class: "monospace branch-name"
- else
.light none
.icon-container
= custom_icon("icon_commit")
= link_to build.short_sha, namespace_project_commit_path(build.project.namespace, build.project, build.sha), class: "monospace commit-id"
- if build.stuck?
%i.fa.fa-warning.text-warning
.label-container
- if build.tags.any?
- build.tags.each do |tag|
%span.label.label-primary
= tag
- if build.try(:trigger_request)
%span.label.label-info triggered
- if build.try(:allow_failure)
%span.label.label-danger allowed to fail
%td
- if project
= link_to project.name_with_namespace, admin_namespace_project_path(project.namespace, project)
%td
- if build.try(:runner)
= runner_link(build.runner)
- else
.light none
%td
#{build.stage} / #{build.name}
%td
- if build.duration
%p.duration
= custom_icon("icon_timer")
= duration_in_numbers(build.duration)
- if build.finished_at
%p.finished-at
= icon("calendar")
%span #{time_ago_with_tooltip(build.finished_at)}
- if defined?(coverage) && coverage
%td.coverage
- if build.try(:coverage)
#{build.coverage}%
%td
.pull-right
- if can?(current_user, :read_build, project) && build.artifacts?
= link_to download_namespace_project_build_artifacts_path(build.project.namespace, build.project, build), title: 'Download artifacts', class: 'btn btn-build' do
%i.fa.fa-download
- if can?(current_user, :update_build, build.project)
- if build.active?
= link_to cancel_namespace_project_build_path(build.project.namespace, build.project, build, return_to: request.original_url), method: :post, title: 'Cancel', class: 'btn btn-build' do
%i.fa.fa-remove.cred
- elsif defined?(allow_retry) && allow_retry && build.retryable?
= link_to retry_namespace_project_build_path(build.project.namespace, build.project, build, return_to: request.original_url), method: :post, title: 'Retry', class: 'btn btn-build' do
%i.fa.fa-refresh
...@@ -4,26 +4,8 @@ ...@@ -4,26 +4,8 @@
%div{ class: container_class } %div{ class: container_class }
.top-area .top-area
%ul.nav-links - build_path_proc = ->(scope) { admin_builds_path(scope: scope) }
%li{class: ('active' if @scope.nil?)} = render "shared/builds/tabs", build_path_proc: build_path_proc, all_builds: @all_builds, scope: @scope
= link_to admin_builds_path do
All
%span.badge.js-totalbuilds-count= @all_builds.count(:id)
%li{class: ('active' if @scope == 'pending')}
= link_to admin_builds_path(scope: :pending) do
Pending
%span.badge= number_with_delimiter(@all_builds.pending.count(:id))
%li{class: ('active' if @scope == 'running')}
= link_to admin_builds_path(scope: :running) do
Running
%span.badge= number_with_delimiter(@all_builds.running.count(:id))
%li{class: ('active' if @scope == 'finished')}
= link_to admin_builds_path(scope: :finished) do
Finished
%span.badge= number_with_delimiter(@all_builds.finished.count(:id))
.nav-controls .nav-controls
- if @all_builds.running_or_pending.any? - if @all_builds.running_or_pending.any?
...@@ -33,23 +15,4 @@ ...@@ -33,23 +15,4 @@
#{(@scope || 'all').capitalize} builds #{(@scope || 'all').capitalize} builds
%ul.content-list.builds-content-list %ul.content-list.builds-content-list
- if @builds.blank? = render "projects/builds/table", builds: @builds, admin: true
%li
.nothing-here-block No builds to show
- else
.table-holder
%table.table.builds
%thead
%tr
%th Status
%th Commit
%th Project
%th Runner
%th Name
%th
%th
- @builds.each do |build|
= render "admin/builds/build", build: build
= paginate @builds, theme: 'gitlab'
- page_title "SSH Keys" - page_title "SSH Keys"
= render 'profiles/head'
.row.prepend-top-default .row.prepend-top-default
.col-lg-3.profile-settings-sidebar .col-lg-3.profile-settings-sidebar
......
- admin = local_assigns.fetch(:admin, false)
- if builds.blank?
%li
.nothing-here-block No builds to show
- else
.table-holder
%table.table.builds
%thead
%tr
%th Status
%th Commit
- if admin
%th Project
%th Runner
%th Stage
%th Name
%th
%th Coverage
%th
= render partial: "projects/ci/builds/build", collection: builds, as: :build, locals: { commit_sha: true, ref: true, stage: true, allow_retry: true, coverage: admin || project.build_coverage_enabled?, admin: admin }
= paginate builds, theme: 'gitlab'
...@@ -4,30 +4,8 @@ ...@@ -4,30 +4,8 @@
%div{ class: container_class } %div{ class: container_class }
.top-area .top-area
%ul.nav-links - build_path_proc = ->(scope) { project_builds_path(@project, scope: scope) }
%li{class: ('active' if @scope.nil?)} = render "shared/builds/tabs", build_path_proc: build_path_proc, all_builds: @all_builds, scope: @scope
= link_to project_builds_path(@project) do
All
%span.badge.js-totalbuilds-count
= number_with_delimiter(@all_builds.count(:id))
%li{class: ('active' if @scope == 'pending')}
= link_to project_builds_path(@project, scope: :pending) do
Pending
%span.badge
= number_with_delimiter(@all_builds.pending.count(:id))
%li{class: ('active' if @scope == 'running')}
= link_to project_builds_path(@project, scope: :running) do
Running
%span.badge
= number_with_delimiter(@all_builds.running.count(:id))
%li{class: ('active' if @scope == 'finished')}
= link_to project_builds_path(@project, scope: :finished) do
Finished
%span.badge
= number_with_delimiter(@all_builds.finished.count(:id))
.nav-controls .nav-controls
- if can?(current_user, :update_build, @project) - if can?(current_user, :update_build, @project)
...@@ -42,23 +20,4 @@ ...@@ -42,23 +20,4 @@
%span CI Lint %span CI Lint
%ul.content-list.builds-content-list %ul.content-list.builds-content-list
- if @builds.blank? = render "table", builds: @builds, project: @project
%li
.nothing-here-block No builds to show
- else
.table-holder
%table.table.builds
%thead
%tr
%th Status
%th Commit
%th Stage
%th Name
%th
- if @project.build_coverage_enabled?
%th Coverage
%th
= render @builds, commit_sha: true, ref: true, stage: true, allow_retry: true, coverage: @project.build_coverage_enabled?
= paginate @builds, theme: 'gitlab'
- admin = local_assigns.fetch(:admin, false)
- ref = local_assigns.fetch(:ref, nil)
- commit_sha = local_assigns.fetch(:commit_sha, nil)
- retried = local_assigns.fetch(:retried, false)
- stage = local_assigns.fetch(:stage, false)
- coverage = local_assigns.fetch(:coverage, false)
- allow_retry = local_assigns.fetch(:allow_retry, false)
%tr.build.commit %tr.build.commit
%td.status %td.status
- if can?(current_user, :read_build, build) - if can?(current_user, :read_build, build)
...@@ -9,11 +17,11 @@ ...@@ -9,11 +17,11 @@
.branch-commit .branch-commit
- if can?(current_user, :read_build, build) - if can?(current_user, :read_build, build)
= link_to namespace_project_build_url(build.project.namespace, build.project, build) do = link_to namespace_project_build_url(build.project.namespace, build.project, build) do
%span ##{build.id} %span.build-link ##{build.id}
- else - else
%span ##{build.id} %span.build-link ##{build.id}
- if defined?(ref) && ref - if ref
- if build.ref - if build.ref
.icon-container .icon-container
= build.tag? ? icon('tag') : icon('code-fork') = build.tag? ? icon('tag') : icon('code-fork')
...@@ -23,12 +31,12 @@ ...@@ -23,12 +31,12 @@
.icon-container .icon-container
= custom_icon("icon_commit") = custom_icon("icon_commit")
- if defined?(commit_sha) && commit_sha - if commit_sha
= link_to build.short_sha, namespace_project_commit_path(build.project.namespace, build.project, build.sha), class: "commit-id monospace" = link_to build.short_sha, namespace_project_commit_path(build.project.namespace, build.project, build.sha), class: "commit-id monospace"
- if build.stuck? - if build.stuck?
= icon('warning', class: 'text-warning has-tooltip', title: 'Build is stuck. Check runners.') = icon('warning', class: 'text-warning has-tooltip', title: 'Build is stuck. Check runners.')
- if defined?(retried) && retried - if retried
= icon('warning', class: 'text-warning has-tooltip', title: 'Build was retried.') = icon('warning', class: 'text-warning has-tooltip', title: 'Build was retried.')
.label-container .label-container
...@@ -40,19 +48,24 @@ ...@@ -40,19 +48,24 @@
%span.label.label-info triggered %span.label.label-info triggered
- if build.try(:allow_failure) - if build.try(:allow_failure)
%span.label.label-danger allowed to fail %span.label.label-danger allowed to fail
- if defined?(retried) && retried - if retried
%span.label.label-warning retried %span.label.label-warning retried
- if build.manual? - if build.manual?
%span.label.label-info manual %span.label.label-info manual
- if defined?(runner) && runner - if admin
%td
- if build.project
= link_to build.project.name_with_namespace, admin_namespace_project_path(build.project.namespace, build.project)
- if admin
%td %td
- if build.try(:runner) - if build.try(:runner)
= runner_link(build.runner) = runner_link(build.runner)
- else - else
.light none .light none
- if defined?(stage) && stage - if stage
%td %td
= build.stage = build.stage
...@@ -64,13 +77,14 @@ ...@@ -64,13 +77,14 @@
%p.duration %p.duration
= custom_icon("icon_timer") = custom_icon("icon_timer")
= duration_in_numbers(build.duration) = duration_in_numbers(build.duration)
- if build.finished_at - if build.finished_at
%p.finished-at %p.finished-at
= icon("calendar") = icon("calendar")
%span #{time_ago_with_tooltip(build.finished_at)} %span #{time_ago_with_tooltip(build.finished_at)}
- if defined?(coverage) && coverage
%td.coverage %td.coverage
- if coverage
- if build.try(:coverage) - if build.try(:coverage)
#{build.coverage}% #{build.coverage}%
...@@ -83,10 +97,10 @@ ...@@ -83,10 +97,10 @@
- if build.active? - if build.active?
= link_to cancel_namespace_project_build_path(build.project.namespace, build.project, build, return_to: request.original_url), method: :post, title: 'Cancel', class: 'btn btn-build' do = link_to cancel_namespace_project_build_path(build.project.namespace, build.project, build, return_to: request.original_url), method: :post, title: 'Cancel', class: 'btn btn-build' do
= icon('remove', class: 'cred') = icon('remove', class: 'cred')
- elsif defined?(allow_retry) && allow_retry - elsif allow_retry
- if build.retryable? - if build.retryable?
= link_to retry_namespace_project_build_path(build.project.namespace, build.project, build, return_to: request.original_url), method: :post, title: 'Retry', class: 'btn btn-build' do = link_to retry_namespace_project_build_path(build.project.namespace, build.project, build, return_to: request.original_url), method: :post, title: 'Retry', class: 'btn btn-build' do
= icon('repeat') = icon('repeat')
- elsif build.playable? - elsif build.playable? && !admin
= link_to play_namespace_project_build_path(build.project.namespace, build.project, build, return_to: request.original_url), method: :post, title: 'Play', class: 'btn btn-build' do = link_to play_namespace_project_build_path(build.project.namespace, build.project, build, return_to: request.original_url), method: :post, title: 'Play', class: 'btn btn-build' do
= custom_icon('icon_play') = custom_icon('icon_play')
- if @merge_requests.any? - if @merge_requests.any?
%h2.merge-requests-title %h2.merge-requests-title
= pluralize(@merge_requests.count, 'Related Merge Request') = pluralize(@merge_requests.count, 'Related Merge Request')
%ul.unstyled-list %ul.unstyled-list.related-merge-requests
- has_any_ci = @merge_requests.any?(&:pipeline) - has_any_ci = @merge_requests.any?(&:pipeline)
- @merge_requests.each do |merge_request| - @merge_requests.each do |merge_request|
%li %li
......
- if @related_branches.any? - if @related_branches.any?
%h2.related-branches-title %h2.related-branches-title
= pluralize(@related_branches.count, 'Related Branch') = pluralize(@related_branches.count, 'Related Branch')
%ul.unstyled-list %ul.unstyled-list.related-merge-requests
- @related_branches.each do |branch| - @related_branches.each do |branch|
%li %li
- target = @project.repository.find_branch(branch).target - target = @project.repository.find_branch(branch).target
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
- if can?(current_user, :update_merge_request, @merge_request) - if can?(current_user, :update_merge_request, @merge_request)
- if @merge_request.open? - if @merge_request.open?
= link_to 'Close merge request', merge_request_path(@merge_request, merge_request: {state_event: :close }), method: :put, class: "btn btn-nr btn-comment btn-close close-mr-link js-note-target-close", title: "Close merge request", data: {original_text: "Close merge request", alternative_text: "Comment & close merge request"} = link_to 'Close merge request', merge_request_path(@merge_request, merge_request: {state_event: :close }), method: :put, class: "btn btn-nr btn-comment btn-close close-mr-link js-note-target-close", title: "Close merge request", data: {original_text: "Close merge request", alternative_text: "Comment & close merge request"}
- if @merge_request.closed? - if @merge_request.reopenable?
= link_to 'Reopen merge request', merge_request_path(@merge_request, merge_request: {state_event: :reopen }), method: :put, class: "btn btn-nr btn-comment btn-reopen reopen-mr-link js-note-target-reopen", title: "Reopen merge request", data: {original_text: "Reopen merge request", alternative_text: "Comment & reopen merge request"} = link_to 'Reopen merge request', merge_request_path(@merge_request, merge_request: {state_event: :reopen }), method: :put, class: "btn btn-nr btn-comment btn-reopen reopen-mr-link js-note-target-reopen", title: "Reopen merge request", data: {original_text: "Reopen merge request", alternative_text: "Comment & reopen merge request"}
%comment-and-resolve-btn{ "inline-template" => true, ":discussion-id" => "" } %comment-and-resolve-btn{ "inline-template" => true, ":discussion-id" => "" }
%button.btn.btn-nr.btn-default.append-right-10.js-comment-resolve-button{ "v-if" => "showButton", type: "submit", data: { namespace_path: "#{@merge_request.project.namespace.path}", project_path: "#{@merge_request.project.path}" } } %button.btn.btn-nr.btn-default.append-right-10.js-comment-resolve-button{ "v-if" => "showButton", type: "submit", data: { namespace_path: "#{@merge_request.project.namespace.path}", project_path: "#{@merge_request.project.path}" } }
......
...@@ -29,6 +29,7 @@ ...@@ -29,6 +29,7 @@
%ul.dropdown-menu.dropdown-menu-align-right %ul.dropdown-menu.dropdown-menu-align-right
%li= link_to "Email Patches", merge_request_path(@merge_request, format: :patch) %li= link_to "Email Patches", merge_request_path(@merge_request, format: :patch)
%li= link_to "Plain Diff", merge_request_path(@merge_request, format: :diff) %li= link_to "Plain Diff", merge_request_path(@merge_request, format: :diff)
- unless @merge_request.closed_without_fork?
.normal .normal
%span Request to merge %span Request to merge
%span.label-branch= source_branch_with_namespace(@merge_request) %span.label-branch= source_branch_with_namespace(@merge_request)
...@@ -38,6 +39,7 @@ ...@@ -38,6 +39,7 @@
- if @merge_request.open? && @merge_request.diverged_from_target_branch? - if @merge_request.open? && @merge_request.diverged_from_target_branch?
%span (#{pluralize(@merge_request.diverged_commits_count, 'commit')} behind) %span (#{pluralize(@merge_request.diverged_commits_count, 'commit')} behind)
- unless @merge_request.closed_without_source_project?
= render "projects/merge_requests/show/how_to_merge" = render "projects/merge_requests/show/how_to_merge"
= render "projects/merge_requests/widget/show.html.haml" = render "projects/merge_requests/widget/show.html.haml"
...@@ -53,6 +55,7 @@ ...@@ -53,6 +55,7 @@
= link_to namespace_project_merge_request_path(@project.namespace, @project, @merge_request), data: { target: 'div#notes', action: 'notes', toggle: 'tab' } do = link_to namespace_project_merge_request_path(@project.namespace, @project, @merge_request), data: { target: 'div#notes', action: 'notes', toggle: 'tab' } do
Discussion Discussion
%span.badge= @merge_request.mr_and_commit_notes.user.count %span.badge= @merge_request.mr_and_commit_notes.user.count
- unless @merge_request.closed_without_source_project?
%li.commits-tab %li.commits-tab
= link_to commits_namespace_project_merge_request_path(@project.namespace, @project, @merge_request), data: { target: 'div#commits', action: 'commits', toggle: 'tab' } do = link_to commits_namespace_project_merge_request_path(@project.namespace, @project, @merge_request), data: { target: 'div#commits', action: 'commits', toggle: 'tab' } do
Commits Commits
......
- return unless note.author - return unless note.author
- return if note.cross_reference_not_visible_for?(current_user) - return if note.cross_reference_not_visible_for?(current_user)
- can_resolve = can?(current_user, :resolve_note, note)
- note_editable = note_editable?(note) - note_editable = note_editable?(note)
%li.timeline-entry{ id: dom_id(note), class: ["note", "note-row-#{note.id}", ('system-note' if note.system)], data: {author_id: note.author.id, editable: note_editable} } %li.timeline-entry{ id: dom_id(note), class: ["note", "note-row-#{note.id}", ('system-note' if note.system)], data: {author_id: note.author.id, editable: note_editable} }
...@@ -24,6 +23,8 @@ ...@@ -24,6 +23,8 @@
%span.note-role.hidden-xs= access %span.note-role.hidden-xs= access
- if note.resolvable? - if note.resolvable?
- can_resolve = can?(current_user, :resolve_note, note)
%resolve-btn{ ":namespace-path" => "'#{note.project.namespace.path}'", %resolve-btn{ ":namespace-path" => "'#{note.project.namespace.path}'",
":project-path" => "'#{note.project.path}'", ":project-path" => "'#{note.project.path}'",
":discussion-id" => "'#{note.discussion_id}'", ":discussion-id" => "'#{note.discussion_id}'",
......
%ul.nav-links
%li{ class: ('active' if scope.nil?) }
= link_to build_path_proc.call(nil) do
All
%span.badge.js-totalbuilds-count
= number_with_delimiter(all_builds.count(:id))
%li{ class: ('active' if scope == 'pending') }
= link_to build_path_proc.call('pending') do
Pending
%span.badge
= number_with_delimiter(all_builds.pending.count(:id))
%li{ class: ('active' if scope == 'running') }
= link_to build_path_proc.call('running') do
Running
%span.badge
= number_with_delimiter(all_builds.running.count(:id))
%li{ class: ('active' if scope == 'finished') }
= link_to build_path_proc.call('finished') do
Finished
%span.badge
= number_with_delimiter(all_builds.finished.count(:id))
...@@ -68,7 +68,8 @@ if Gitlab::Metrics.enabled? ...@@ -68,7 +68,8 @@ if Gitlab::Metrics.enabled?
['app', 'mailers', 'emails'] => ['app', 'mailers'], ['app', 'mailers', 'emails'] => ['app', 'mailers'],
['app', 'services', '**'] => ['app', 'services'], ['app', 'services', '**'] => ['app', 'services'],
['lib', 'gitlab', 'diff'] => ['lib'], ['lib', 'gitlab', 'diff'] => ['lib'],
['lib', 'gitlab', 'email', 'message'] => ['lib'] ['lib', 'gitlab', 'email', 'message'] => ['lib'],
['lib', 'gitlab', 'checks'] => ['lib']
} }
paths_to_instrument.each do |(path, prefix)| paths_to_instrument.each do |(path, prefix)|
......
...@@ -13,9 +13,5 @@ Mime::Type.register "video/mp4", :mp4, [], [:m4v, :mov] ...@@ -13,9 +13,5 @@ Mime::Type.register "video/mp4", :mp4, [], [:m4v, :mov]
Mime::Type.register "video/webm", :webm Mime::Type.register "video/webm", :webm
Mime::Type.register "video/ogg", :ogv Mime::Type.register "video/ogg", :ogv
middlewares = Gitlab::Application.config.middleware Mime::Type.unregister :json
middlewares.swap(ActionDispatch::ParamsParser, ActionDispatch::ParamsParser, { Mime::Type.register 'application/json', :json, %w(application/vnd.git-lfs+json application/json)
Mime::Type.lookup('application/vnd.git-lfs+json') => lambda do |body|
ActiveSupport::JSON.decode(body)
end
})
...@@ -8,14 +8,28 @@ class MergeRequestDiffRemoveUniq < ActiveRecord::Migration ...@@ -8,14 +8,28 @@ class MergeRequestDiffRemoveUniq < ActiveRecord::Migration
DOWNTIME = false DOWNTIME = false
def up def up
constraint_name = 'merge_request_diffs_merge_request_id_key'
transaction do
if index_exists?(:merge_request_diffs, :merge_request_id) if index_exists?(:merge_request_diffs, :merge_request_id)
remove_index :merge_request_diffs, :merge_request_id remove_index(:merge_request_diffs, :merge_request_id)
end
# In some bizarre cases PostgreSQL might have a separate unique constraint
# that we'll need to drop.
if constraint_exists?(constraint_name) && Gitlab::Database.postgresql?
execute("ALTER TABLE merge_request_diffs DROP CONSTRAINT IF EXISTS #{constraint_name};")
end
end end
end end
def down def down
unless index_exists?(:merge_request_diffs, :merge_request_id) unless index_exists?(:merge_request_diffs, :merge_request_id)
add_concurrent_index :merge_request_diffs, :merge_request_id, unique: true add_concurrent_index(:merge_request_diffs, :merge_request_id, unique: true)
end
end end
def constraint_exists?(name)
indexes(:merge_request_diffs).map(&:name).include?(name)
end end
end end
# See http://doc.gitlab.com/ce/development/migration_style_guide.html
# for more information on how to write migrations for GitLab.
class RemoveProjectsPushesSinceGc < ActiveRecord::Migration
include Gitlab::Database::MigrationHelpers
DOWNTIME = true
DOWNTIME_REASON = 'This migration removes an existing column'
disable_ddl_transaction!
def up
remove_column :projects, :pushes_since_gc
end
def down
add_column_with_default! :projects, :pushes_since_gc, :integer, default: 0
end
end
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
# #
# It's strongly recommended that you check this file into your version control system. # It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema.define(version: 20160906143504) do ActiveRecord::Schema.define(version: 20160913162434) do
# These are extensions that must be enabled in order to support this database # These are extensions that must be enabled in order to support this database
enable_extension "plpgsql" enable_extension "plpgsql"
...@@ -945,7 +945,6 @@ ActiveRecord::Schema.define(version: 20160906143504) do ...@@ -945,7 +945,6 @@ ActiveRecord::Schema.define(version: 20160906143504) do
t.boolean "mirror_trigger_builds", default: false, null: false t.boolean "mirror_trigger_builds", default: false, null: false
t.boolean "pending_delete", default: false t.boolean "pending_delete", default: false
t.boolean "public_builds", default: true, null: false t.boolean "public_builds", default: true, null: false
t.integer "pushes_since_gc", default: 0
t.boolean "last_repository_check_failed" t.boolean "last_repository_check_failed"
t.datetime "last_repository_check_at" t.datetime "last_repository_check_at"
t.boolean "container_registry_enabled" t.boolean "container_registry_enabled"
......
...@@ -406,7 +406,8 @@ To configure the storage driver in Omnibus: ...@@ -406,7 +406,8 @@ To configure the storage driver in Omnibus:
's3' => { 's3' => {
'accesskey' => 's3-access-key', 'accesskey' => 's3-access-key',
'secretkey' => 's3-secret-key-for-access-key', 'secretkey' => 's3-secret-key-for-access-key',
'bucket' => 'your-s3-bucket' 'bucket' => 'your-s3-bucket',
'region' => 'your-s3-region'
} }
} }
``` ```
...@@ -428,6 +429,7 @@ storage: ...@@ -428,6 +429,7 @@ storage:
accesskey: 'AKIAKIAKI' accesskey: 'AKIAKIAKI'
secretkey: 'secret123' secretkey: 'secret123'
bucket: 'gitlab-registry-bucket-AKIAKIAKI' bucket: 'gitlab-registry-bucket-AKIAKIAKI'
region: 'your-s3-region'
cache: cache:
blobdescriptor: inmemory blobdescriptor: inmemory
delete: delete:
......
...@@ -28,6 +28,7 @@ following locations: ...@@ -28,6 +28,7 @@ following locations:
- [Namespaces](namespaces.md) - [Namespaces](namespaces.md)
- [Notes](notes.md) (comments) - [Notes](notes.md) (comments)
- [Open source license templates](licenses.md) - [Open source license templates](licenses.md)
- [Notification settings](notification_settings.md)
- [Pipelines](pipelines.md) - [Pipelines](pipelines.md)
- [Projects](projects.md) including setting Webhooks - [Projects](projects.md) including setting Webhooks
- [Project Access Requests](access_requests.md) - [Project Access Requests](access_requests.md)
......
...@@ -38,6 +38,15 @@ POST /ci/api/v1/builds/register ...@@ -38,6 +38,15 @@ POST /ci/api/v1/builds/register
curl --request POST "https://gitlab.example.com/ci/api/v1/builds/register" --form "token=t0k3n" curl --request POST "https://gitlab.example.com/ci/api/v1/builds/register" --form "token=t0k3n"
``` ```
**Responses:**
| Status | Data |Description |
|--------|------|---------------------------------------------------------------------------|
| `201` | yes | When a build is scheduled for a runner |
| `204` | no | When no builds are scheduled for a runner (for GitLab Runner >= `v1.3.0`) |
| `403` | no | When invalid token is used or no token is sent |
| `404` | no | When no builds are scheduled for a runner (for GitLab Runner < `v1.3.0`) **or** when the runner is set to `paused` in GitLab runner's configuration page |
### Update details of an existing build ### Update details of an existing build
``` ```
......
# Notification settings
>**Note:** This feature was [introduced][ce-5632] in GitLab 8.12.
**Valid notification levels**
The notification levels are defined in the `NotificationSetting::level` model enumeration. Currently, these levels are recognized:
```
disabled
participating
watch
global
mention
custom
```
If the `custom` level is used, specific email events can be controlled. Notification email events are defined in the `NotificationSetting::EMAIL_EVENTS` model variable. Currently, these events are recognized:
```
new_note
new_issue
reopen_issue
close_issue
reassign_issue
new_merge_request
reopen_merge_request
close_merge_request
reassign_merge_request
merge_merge_request
```
## Global notification settings
Get current notification settings and email address.
```
GET /notification_settings
```
```bash
curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v3/notification_settings
```
Example response:
```json
{
"level": "participating",
"notification_email": "admin@example.com"
}
```
## Update global notification settings
Update current notification settings and email address.
```
PUT /notification_settings
```
```bash
curl --request PUT --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v3/notification_settings?level=watch
```
| Attribute | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `level` | string | no | The global notification level |
| `notification_email` | string | no | The email address to send notifications |
| `new_note` | boolean | no | Enable/disable this notification |
| `new_issue` | boolean | no | Enable/disable this notification |
| `reopen_issue` | boolean | no | Enable/disable this notification |
| `close_issue` | boolean | no | Enable/disable this notification |
| `reassign_issue` | boolean | no | Enable/disable this notification |
| `new_merge_request` | boolean | no | Enable/disable this notification |
| `reopen_merge_request` | boolean | no | Enable/disable this notification |
| `close_merge_request` | boolean | no | Enable/disable this notification |
| `reassign_merge_request` | boolean | no | Enable/disable this notification |
| `merge_merge_request` | boolean | no | Enable/disable this notification |
Example response:
```json
{
"level": "watch",
"notification_email": "admin@example.com"
}
```
## Group / project level notification settings
Get current group or project notification settings.
```
GET /groups/:id/notification_settings
GET /projects/:id/notification_settings
```
```bash
curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v3/groups/5/notification_settings
curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v3/projects/8/notification_settings
```
| Attribute | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `id` | integer/string | yes | The group/project ID or path |
Example response:
```json
{
"level": "global"
}
```
## Update group/project level notification settings
Update current group/project notification settings.
```
PUT /groups/:id/notification_settings
PUT /projects/:id/notification_settings
```
```bash
curl --request PUT --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v3/groups/5/notification_settings?level=watch
curl --request PUT --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v3/projects/8/notification_settings?level=custom&new_note=true
```
| Attribute | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `id` | integer/string | yes | The group/project ID or path |
| `level` | string | no | The global notification level |
| `new_note` | boolean | no | Enable/disable this notification |
| `new_issue` | boolean | no | Enable/disable this notification |
| `reopen_issue` | boolean | no | Enable/disable this notification |
| `close_issue` | boolean | no | Enable/disable this notification |
| `reassign_issue` | boolean | no | Enable/disable this notification |
| `new_merge_request` | boolean | no | Enable/disable this notification |
| `reopen_merge_request` | boolean | no | Enable/disable this notification |
| `close_merge_request` | boolean | no | Enable/disable this notification |
| `reassign_merge_request` | boolean | no | Enable/disable this notification |
| `merge_merge_request` | boolean | no | Enable/disable this notification |
Example responses:
```json
{
"level": "watch"
}
{
"level": "custom",
"events": {
"new_note": true,
"new_issue": false,
"reopen_issue": false,
"close_issue": false,
"reassign_issue": false,
"new_merge_request": false,
"reopen_merge_request": false,
"close_merge_request": false,
"reassign_merge_request": false,
"merge_merge_request": false
}
}
```
[ce-5632]: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/5632
...@@ -105,7 +105,8 @@ What is important is that each job is run independently from each other. ...@@ -105,7 +105,8 @@ What is important is that each job is run independently from each other.
If you want to check whether your `.gitlab-ci.yml` file is valid, there is a If you want to check whether your `.gitlab-ci.yml` file is valid, there is a
Lint tool under the page `/ci/lint` of your GitLab instance. You can also find Lint tool under the page `/ci/lint` of your GitLab instance. You can also find
the link under **Settings > CI settings** in your project. a "CI Lint" button to go to this page under **Pipelines > Pipelines** and
**Pipelines > Builds** in your project.
For more information and a complete `.gitlab-ci.yml` syntax, please read For more information and a complete `.gitlab-ci.yml` syntax, please read
[the documentation on .gitlab-ci.yml](../yaml/README.md). [the documentation on .gitlab-ci.yml](../yaml/README.md).
......
...@@ -34,6 +34,7 @@ The `API_TOKEN` will take the Secure Variable value: `SECURE`. ...@@ -34,6 +34,7 @@ The `API_TOKEN` will take the Secure Variable value: `SECURE`.
| **CI_BUILD_REF_NAME** | all | all | The branch or tag name for which project is built | | **CI_BUILD_REF_NAME** | all | all | The branch or tag name for which project is built |
| **CI_BUILD_REPO** | all | all | The URL to clone the Git repository | | **CI_BUILD_REPO** | all | all | The URL to clone the Git repository |
| **CI_BUILD_TRIGGERED** | all | 0.5 | The flag to indicate that build was [triggered] | | **CI_BUILD_TRIGGERED** | all | 0.5 | The flag to indicate that build was [triggered] |
| **CI_BUILD_MANUAL** | 8.12 | all | The flag to indicate that build was manually started |
| **CI_BUILD_TOKEN** | all | 1.2 | Token used for authenticating with the GitLab Container Registry | | **CI_BUILD_TOKEN** | all | 1.2 | Token used for authenticating with the GitLab Container Registry |
| **CI_PIPELINE_ID** | 8.10 | 0.5 | The unique id of the current pipeline that GitLab CI uses internally | | **CI_PIPELINE_ID** | 8.10 | 0.5 | The unique id of the current pipeline that GitLab CI uses internally |
| **CI_PROJECT_ID** | all | all | The unique id of the current project that GitLab CI uses internally | | **CI_PROJECT_ID** | all | all | The unique id of the current project that GitLab CI uses internally |
...@@ -47,6 +48,8 @@ The `API_TOKEN` will take the Secure Variable value: `SECURE`. ...@@ -47,6 +48,8 @@ The `API_TOKEN` will take the Secure Variable value: `SECURE`.
| **CI_RUNNER_ID** | 8.10 | 0.5 | The unique id of runner being used | | **CI_RUNNER_ID** | 8.10 | 0.5 | The unique id of runner being used |
| **CI_RUNNER_DESCRIPTION** | 8.10 | 0.5 | The description of the runner as saved in GitLab | | **CI_RUNNER_DESCRIPTION** | 8.10 | 0.5 | The description of the runner as saved in GitLab |
| **CI_RUNNER_TAGS** | 8.10 | 0.5 | The defined runner tags | | **CI_RUNNER_TAGS** | 8.10 | 0.5 | The defined runner tags |
| **GITLAB_USER_ID** | 8.12 | all | The id of the user who started the build |
| **GITLAB_USER_EMAIL** | 8.12 | all | The email of the user who started the build |
**Some of the variables are only available when using runner with at least defined version.** **Some of the variables are only available when using runner with at least defined version.**
...@@ -60,6 +63,7 @@ export CI_BUILD_REPO="https://gitab-ci-token:abcde-1234ABCD5678ef@gitlab.com/git ...@@ -60,6 +63,7 @@ export CI_BUILD_REPO="https://gitab-ci-token:abcde-1234ABCD5678ef@gitlab.com/git
export CI_BUILD_TAG="1.0.0" export CI_BUILD_TAG="1.0.0"
export CI_BUILD_NAME="spec:other" export CI_BUILD_NAME="spec:other"
export CI_BUILD_STAGE="test" export CI_BUILD_STAGE="test"
export CI_BUILD_MANUAL="true"
export CI_BUILD_TRIGGERED="true" export CI_BUILD_TRIGGERED="true"
export CI_BUILD_TOKEN="abcde-1234ABCD5678ef" export CI_BUILD_TOKEN="abcde-1234ABCD5678ef"
export CI_PIPELINE_ID="1000" export CI_PIPELINE_ID="1000"
...@@ -78,6 +82,8 @@ export CI_SERVER="yes" ...@@ -78,6 +82,8 @@ export CI_SERVER="yes"
export CI_SERVER_NAME="GitLab" export CI_SERVER_NAME="GitLab"
export CI_SERVER_REVISION="70606bf" export CI_SERVER_REVISION="70606bf"
export CI_SERVER_VERSION="8.9.0" export CI_SERVER_VERSION="8.9.0"
export GITLAB_USER_ID="42"
export GITLAB_USER_EMAIL="alexzander@sporer.com"
``` ```
### YAML-defined variables ### YAML-defined variables
......
...@@ -137,3 +137,18 @@ end ...@@ -137,3 +137,18 @@ end
``` ```
Here the final value of `sleep_real_time` will be `3`, _not_ `1`. Here the final value of `sleep_real_time` will be `3`, _not_ `1`.
## Tracking Custom Events
Besides instrumenting code GitLab Performance Monitoring also supports tracking
of custom events. This is primarily intended to be used for tracking business
metrics such as the number of Git pushes, repository imports, and so on.
To track a custom event simply call `Gitlab::Metrics.add_event` passing it an
event name and a custom set of (optional) tags. For example:
```ruby
Gitlab::Metrics.add_event(:user_login, email: current_user.email)
```
Event names should be verbs such as `push_repository` and `remove_branch`.
...@@ -70,7 +70,7 @@ sudo -u git -H git checkout 8-12-stable-ee ...@@ -70,7 +70,7 @@ sudo -u git -H git checkout 8-12-stable-ee
```bash ```bash
cd /home/git/gitlab-shell cd /home/git/gitlab-shell
sudo -u git -H git fetch --all --tags sudo -u git -H git fetch --all --tags
sudo -u git -H git checkout v3.4.0 sudo -u git -H git checkout v3.5.0
``` ```
### 6. Update gitlab-workhorse ### 6. Update gitlab-workhorse
......
...@@ -66,7 +66,7 @@ The following table depicts the various user permission levels in a project. ...@@ -66,7 +66,7 @@ The following table depicts the various user permission levels in a project.
| Remove protected branches [^2] | | | | | | | Remove protected branches [^2] | | | | | |
| Remove pages | | | | | ✓ | | Remove pages | | | | | ✓ |
[^1]: If **Allow guest to access builds** is enabled in CI settings [^1]: If **Public pipelines** is enabled in **Project Settings > CI/CD Pipelines**
[^2]: Not allowed for Guest, Reporter, Developer, Master, or Owner [^2]: Not allowed for Guest, Reporter, Developer, Master, or Owner
## Group ## Group
......
...@@ -102,6 +102,9 @@ A merge request contains all the history from a repository, plus the additional ...@@ -102,6 +102,9 @@ A merge request contains all the history from a repository, plus the additional
commits added to the branch associated with the merge request. Here's a few commits added to the branch associated with the merge request. Here's a few
tricks to checkout a merge request locally. tricks to checkout a merge request locally.
Please note that you can checkout a merge request locally even if the source
project is a fork (even a private fork) of the target project.
#### Checkout locally by adding a git alias #### Checkout locally by adding a git alias
Add the following alias to your `~/.gitconfig`: Add the following alias to your `~/.gitconfig`:
......
...@@ -15,6 +15,7 @@ At its current state, GitHub importer can import: ...@@ -15,6 +15,7 @@ At its current state, GitHub importer can import:
- the wiki pages (introduced in GitLab 8.4) - the wiki pages (introduced in GitLab 8.4)
- the milestones (introduced in GitLab 8.7) - the milestones (introduced in GitLab 8.7)
- the labels (introduced in GitLab 8.7) - the labels (introduced in GitLab 8.7)
- the release note descriptions (introduced in GitLab 8.12)
With GitLab 8.7+, references to pull requests and issues are preserved. With GitLab 8.7+, references to pull requests and issues are preserved.
......
...@@ -55,6 +55,7 @@ module API ...@@ -55,6 +55,7 @@ module API
mount ::API::Milestones mount ::API::Milestones
mount ::API::Namespaces mount ::API::Namespaces
mount ::API::Notes mount ::API::Notes
mount ::API::NotificationSettings
mount ::API::Pipelines mount ::API::Pipelines
mount ::API::ProjectHooks mount ::API::ProjectHooks
mount ::API::ProjectGitHook # TODO: Should be removed after 8.11 is released mount ::API::ProjectGitHook # TODO: Should be removed after 8.11 is released
......
...@@ -37,7 +37,7 @@ module API ...@@ -37,7 +37,7 @@ module API
# id (required) - The ID of a project # id (required) - The ID of a project
# sha (required) - The commit hash # sha (required) - The commit hash
# ref (optional) - The ref # ref (optional) - The ref
# state (required) - The state of the status. Can be: pending, running, success, error or failure # state (required) - The state of the status. Can be: pending, running, success, failed or canceled
# target_url (optional) - The target URL to associate with this status # target_url (optional) - The target URL to associate with this status
# description (optional) - A short description of the status # description (optional) - A short description of the status
# name or context (optional) - A string label to differentiate this status from the status of other systems. Default: "default" # name or context (optional) - A string label to differentiate this status from the status of other systems. Default: "default"
...@@ -46,7 +46,7 @@ module API ...@@ -46,7 +46,7 @@ module API
post ':id/statuses/:sha' do post ':id/statuses/:sha' do
authorize! :create_commit_status, user_project authorize! :create_commit_status, user_project
required_attributes! [:state] required_attributes! [:state]
attrs = attributes_for_keys [:ref, :target_url, :description, :context, :name] attrs = attributes_for_keys [:target_url, :description]
commit = @project.commit(params[:sha]) commit = @project.commit(params[:sha])
not_found! 'Commit' unless commit not_found! 'Commit' unless commit
...@@ -58,36 +58,38 @@ module API ...@@ -58,36 +58,38 @@ module API
# the first found branch on that commit # the first found branch on that commit
ref = params[:ref] ref = params[:ref]
unless ref ref ||= @project.repository.branch_names_contains(commit.sha).first
branches = @project.repository.branch_names_contains(commit.sha) not_found! 'References for commit' unless ref
not_found! 'References for commit' if branches.none?
ref = branches.first name = params[:name] || params[:context] || 'default'
end
pipeline = @project.ensure_pipeline(ref, commit.sha, current_user) pipeline = @project.ensure_pipeline(ref, commit.sha, current_user)
name = params[:name] || params[:context] status = GenericCommitStatus.running_or_pending.find_or_initialize_by(
status = GenericCommitStatus.running_or_pending.find_by(pipeline: pipeline, name: name, ref: params[:ref]) project: @project, pipeline: pipeline,
status ||= GenericCommitStatus.new(project: @project, pipeline: pipeline, user: current_user) user: current_user, name: name, ref: ref)
status.update(attrs) status.attributes = attrs
begin
case params[:state].to_s case params[:state].to_s
when 'pending'
status.enqueue!
when 'running' when 'running'
status.run status.enqueue
status.run!
when 'success' when 'success'
status.success status.success!
when 'failed' when 'failed'
status.drop status.drop!
when 'canceled' when 'canceled'
status.cancel status.cancel!
else else
status.status = params[:state].to_s render_api_error!('invalid state', 400)
end end
if status.save
present status, with: Entities::CommitStatus present status, with: Entities::CommitStatus
else rescue StateMachines::InvalidTransition => e
render_validation_error!(status) render_api_error!(e.message, 400)
end end
end end
end end
......
...@@ -407,7 +407,7 @@ module API ...@@ -407,7 +407,7 @@ module API
expose :access_level expose :access_level
expose :notification_level do |member, options| expose :notification_level do |member, options|
if member.notification_setting if member.notification_setting
NotificationSetting.levels[member.notification_setting.level] ::NotificationSetting.levels[member.notification_setting.level]
end end
end end
end end
...@@ -418,6 +418,21 @@ module API ...@@ -418,6 +418,21 @@ module API
class GroupAccess < MemberAccess class GroupAccess < MemberAccess
end end
class NotificationSetting < Grape::Entity
expose :level
expose :events, if: ->(notification_setting, _) { notification_setting.custom? } do
::NotificationSetting::EMAIL_EVENTS.each do |event|
expose event
end
end
end
class GlobalNotificationSetting < NotificationSetting
expose :notification_email do |notification_setting, options|
notification_setting.user.notification_email
end
end
class ProjectService < Grape::Entity class ProjectService < Grape::Entity
expose :id, :title, :created_at, :updated_at, :active expose :id, :title, :created_at, :updated_at, :active
expose :push_events, :issues_events, :merge_requests_events expose :push_events, :issues_events, :merge_requests_events
......
...@@ -280,6 +280,10 @@ module API ...@@ -280,6 +280,10 @@ module API
render_api_error!('304 Not Modified', 304) render_api_error!('304 Not Modified', 304)
end end
def no_content!
render_api_error!('204 No Content', 204)
end
def render_validation_error!(model) def render_validation_error!(model)
if model.errors.any? if model.errors.any?
render_api_error!(model.errors.messages || '400 Bad Request', 400) render_api_error!(model.errors.messages || '400 Bad Request', 400)
......
...@@ -41,7 +41,8 @@ module API ...@@ -41,7 +41,8 @@ module API
issues = current_user.issues.inc_notes_with_associations issues = current_user.issues.inc_notes_with_associations
issues = filter_issues_state(issues, params[:state]) unless params[:state].nil? issues = filter_issues_state(issues, params[:state]) unless params[:state].nil?
issues = filter_issues_labels(issues, params[:labels]) unless params[:labels].nil? issues = filter_issues_labels(issues, params[:labels]) unless params[:labels].nil?
issues.reorder(issuable_order_by => issuable_sort) issues = issues.reorder(issuable_order_by => issuable_sort)
present paginate(issues), with: Entities::Issue, current_user: current_user present paginate(issues), with: Entities::Issue, current_user: current_user
end end
end end
...@@ -73,7 +74,11 @@ module API ...@@ -73,7 +74,11 @@ module API
params[:group_id] = group.id params[:group_id] = group.id
params[:milestone_title] = params.delete(:milestone) params[:milestone_title] = params.delete(:milestone)
params[:label_name] = params.delete(:labels) params[:label_name] = params.delete(:labels)
params[:sort] = "#{params.delete(:order_by)}_#{params.delete(:sort)}" if params[:order_by] && params[:sort]
if params[:order_by] || params[:sort]
# The Sortable concern takes 'created_desc', not 'created_at_desc' (for example)
params[:sort] = "#{issuable_order_by.sub('_at', '')}_#{issuable_sort}"
end
issues = IssuesFinder.new(current_user, params).execute issues = IssuesFinder.new(current_user, params).execute
...@@ -113,7 +118,8 @@ module API ...@@ -113,7 +118,8 @@ module API
issues = filter_issues_milestone(issues, params[:milestone]) issues = filter_issues_milestone(issues, params[:milestone])
end end
issues.reorder(issuable_order_by => issuable_sort) issues = issues.reorder(issuable_order_by => issuable_sort)
present paginate(issues), with: Entities::Issue, current_user: current_user present paginate(issues), with: Entities::Issue, current_user: current_user
end end
......
module API
# notification_settings API
class NotificationSettings < Grape::API
before { authenticate! }
helpers ::API::Helpers::MembersHelpers
resource :notification_settings do
desc 'Get global notification level settings and email, defaults to Participate' do
detail 'This feature was introduced in GitLab 8.12'
success Entities::GlobalNotificationSetting
end
get do
notification_setting = current_user.global_notification_setting
present notification_setting, with: Entities::GlobalNotificationSetting
end
desc 'Update global notification level settings and email, defaults to Participate' do
detail 'This feature was introduced in GitLab 8.12'
success Entities::GlobalNotificationSetting
end
params do
optional :level, type: String, desc: 'The global notification level'
optional :notification_email, type: String, desc: 'The email address to send notifications'
NotificationSetting::EMAIL_EVENTS.each do |event|
optional event, type: Boolean, desc: 'Enable/disable this notification'
end
end
put do
notification_setting = current_user.global_notification_setting
begin
notification_setting.transaction do
new_notification_email = params.delete(:notification_email)
declared_params = declared(params, include_missing: false).to_h
current_user.update(notification_email: new_notification_email) if new_notification_email
notification_setting.update(declared_params)
end
rescue ArgumentError => e # catch level enum error
render_api_error! e.to_s, 400
end
render_validation_error! current_user
render_validation_error! notification_setting
present notification_setting, with: Entities::GlobalNotificationSetting
end
end
%w[group project].each do |source_type|
resource source_type.pluralize do
desc "Get #{source_type} level notification level settings, defaults to Global" do
detail 'This feature was introduced in GitLab 8.12'
success Entities::NotificationSetting
end
params do
requires :id, type: String, desc: 'The group ID or project ID or project NAMESPACE/PROJECT_NAME'
end
get ":id/notification_settings" do
source = find_source(source_type, params[:id])
notification_setting = current_user.notification_settings_for(source)
present notification_setting, with: Entities::NotificationSetting
end
desc "Update #{source_type} level notification level settings, defaults to Global" do
detail 'This feature was introduced in GitLab 8.12'
success Entities::NotificationSetting
end
params do
requires :id, type: String, desc: 'The group ID or project ID or project NAMESPACE/PROJECT_NAME'
optional :level, type: String, desc: "The #{source_type} notification level"
NotificationSetting::EMAIL_EVENTS.each do |event|
optional event, type: Boolean, desc: 'Enable/disable this notification'
end
end
put ":id/notification_settings" do
source = find_source(source_type, params.delete(:id))
notification_setting = current_user.notification_settings_for(source)
begin
declared_params = declared(params, include_missing: false).to_h
notification_setting.update(declared_params)
rescue ArgumentError => e # catch level enum error
render_api_error! e.to_s, 400
end
render_validation_error! notification_setting
present notification_setting, with: Entities::NotificationSetting
end
end
end
end
end
...@@ -434,18 +434,9 @@ module API ...@@ -434,18 +434,9 @@ module API
# Example Request: # Example Request:
# GET /projects/search/:query # GET /projects/search/:query
get "/search/:query" do get "/search/:query" do
ids = current_user.authorized_projects.map(&:id) search_service = Search::GlobalService.new(current_user, search: params[:query]).execute
visibility_levels = [ Gitlab::VisibilityLevel::INTERNAL, Gitlab::VisibilityLevel::PUBLIC ] projects = search_service.objects('projects', params[:page])
projects = Project.where("(id in (?) OR visibility_level in (?)) AND (name LIKE (?))", ids, visibility_levels, "%#{params[:query]}%") projects = projects.reorder(project_order_by => project_sort)
sort = params[:sort] == 'desc' ? 'desc' : 'asc'
projects = case params["order_by"]
when 'id' then projects.order("id #{sort}")
when 'name' then projects.order("name #{sort}")
when 'created_at' then projects.order("created_at #{sort}")
when 'last_activity_at' then projects.order("last_activity_at #{sort}")
else projects
end
present paginate(projects), with: Entities::Project present paginate(projects), with: Entities::Project
end end
......
...@@ -31,6 +31,7 @@ module Banzai ...@@ -31,6 +31,7 @@ module Banzai
def apply_relative_link_rules! def apply_relative_link_rules!
if @uri.relative? && @uri.path.present? if @uri.relative? && @uri.path.present?
link = ::File.join(@wiki_base_path, @uri.path) link = ::File.join(@wiki_base_path, @uri.path)
link = "#{link}##{@uri.fragment}" if @uri.fragment
@uri = Addressable::URI.parse(link) @uri = Addressable::URI.parse(link)
end end
end end
......
...@@ -27,7 +27,7 @@ module Ci ...@@ -27,7 +27,7 @@ module Ci
else else
Gitlab::Metrics.add_event(:build_not_found) Gitlab::Metrics.add_event(:build_not_found)
not_found! build_not_found!
end end
end end
......
...@@ -32,6 +32,14 @@ module Ci ...@@ -32,6 +32,14 @@ module Ci
end end
end end
def build_not_found!
if headers['User-Agent'].match(/gitlab-ci-multi-runner \d+\.\d+\.\d+(~beta\.\d+\.g[0-9a-f]+)? /)
no_content!
else
not_found!
end
end
def current_runner def current_runner
@runner ||= Runner.find_by_token(params[:token].to_s) @runner ||= Runner.find_by_token(params[:token].to_s)
end end
......
...@@ -256,7 +256,7 @@ module Gitlab ...@@ -256,7 +256,7 @@ module Gitlab
# Create (if necessary) and link the secret token file # Create (if necessary) and link the secret token file
def generate_and_link_secret_token def generate_and_link_secret_token
secret_file = Gitlab.config.gitlab_shell.secret_file secret_file = Gitlab.config.gitlab_shell.secret_file
unless File.exist? secret_file unless File.size?(secret_file)
# Generate a new token of 16 random hexadecimal characters and store it in secret_file. # Generate a new token of 16 random hexadecimal characters and store it in secret_file.
token = SecureRandom.hex(16) token = SecureRandom.hex(16)
File.write(secret_file, token) File.write(secret_file, token)
......
...@@ -24,6 +24,7 @@ module Gitlab ...@@ -24,6 +24,7 @@ module Gitlab
protected protected
def protected_branch_checks def protected_branch_checks
return unless @branch_name
return unless project.protected_branch?(@branch_name) return unless project.protected_branch?(@branch_name)
if forced_push? && user_access.cannot_do_action?(:force_push_code_to_protected_branches) if forced_push? && user_access.cannot_do_action?(:force_push_code_to_protected_branches)
......
...@@ -17,6 +17,7 @@ module Gitlab ...@@ -17,6 +17,7 @@ module Gitlab
def trigger(gl_id, oldrev, newrev, ref) def trigger(gl_id, oldrev, newrev, ref)
return [true, nil] unless exists? return [true, nil] unless exists?
Bundler.with_clean_env do
case name case name
when "pre-receive", "post-receive" when "pre-receive", "post-receive"
call_receive_hook(gl_id, oldrev, newrev, ref) call_receive_hook(gl_id, oldrev, newrev, ref)
...@@ -24,6 +25,7 @@ module Gitlab ...@@ -24,6 +25,7 @@ module Gitlab
call_update_hook(gl_id, oldrev, newrev, ref) call_update_hook(gl_id, oldrev, newrev, ref)
end end
end end
end
private private
......
...@@ -20,6 +20,11 @@ module Gitlab ...@@ -20,6 +20,11 @@ module Gitlab
find_by("identities.extern_uid = ? AND identities.provider = 'github'", github_id.to_s). find_by("identities.extern_uid = ? AND identities.provider = 'github'", github_id.to_s).
try(:id) try(:id)
end end
def gitlab_author_id
return @gitlab_author_id if defined?(@gitlab_author_id)
@gitlab_author_id = gitlab_user_id(raw_data.user.id)
end
end end
end end
end end
...@@ -21,7 +21,7 @@ module Gitlab ...@@ -21,7 +21,7 @@ module Gitlab
end end
def author_id def author_id
gitlab_user_id(raw_data.user.id) || project.creator_id gitlab_author_id || project.creator_id
end end
def body def body
...@@ -52,8 +52,12 @@ module Gitlab ...@@ -52,8 +52,12 @@ module Gitlab
end end
def note def note
if gitlab_author_id
body
else
formatter.author_line(author) + body formatter.author_line(author) + body
end end
end
def type def type
'LegacyDiffNote' if on_diff? 'LegacyDiffNote' if on_diff?
......
...@@ -24,6 +24,7 @@ module Gitlab ...@@ -24,6 +24,7 @@ module Gitlab
import_issues import_issues
import_pull_requests import_pull_requests
import_wiki import_wiki
import_releases
handle_errors handle_errors
true true
...@@ -177,6 +178,18 @@ module Gitlab ...@@ -177,6 +178,18 @@ module Gitlab
errors << { type: :wiki, errors: e.message } errors << { type: :wiki, errors: e.message }
end end
end end
def import_releases
releases = client.releases(repo, per_page: 100)
releases.each do |raw|
begin
gh_release = ReleaseFormatter.new(project, raw)
gh_release.create! if gh_release.valid?
rescue => e
errors << { type: :release, url: Gitlab::UrlSanitizer.sanitize(raw.url), errors: e.message }
end
end
end
end end
end end
end end
...@@ -49,7 +49,7 @@ module Gitlab ...@@ -49,7 +49,7 @@ module Gitlab
end end
def author_id def author_id
gitlab_user_id(raw_data.user.id) || project.creator_id gitlab_author_id || project.creator_id
end end
def body def body
...@@ -57,7 +57,11 @@ module Gitlab ...@@ -57,7 +57,11 @@ module Gitlab
end end
def description def description
@formatter.author_line(author) + body if gitlab_author_id
body
else
formatter.author_line(author) + body
end
end end
def milestone def milestone
......
...@@ -77,7 +77,7 @@ module Gitlab ...@@ -77,7 +77,7 @@ module Gitlab
end end
def author_id def author_id
gitlab_user_id(raw_data.user.id) || project.creator_id gitlab_author_id || project.creator_id
end end
def body def body
...@@ -85,8 +85,12 @@ module Gitlab ...@@ -85,8 +85,12 @@ module Gitlab
end end
def description def description
if gitlab_author_id
body
else
formatter.author_line(author) + body formatter.author_line(author) + body
end end
end
def milestone def milestone
if raw_data.milestone.present? if raw_data.milestone.present?
......
module Gitlab
module GithubImport
class ReleaseFormatter < BaseFormatter
def attributes
{
project: project,
tag: raw_data.tag_name,
description: raw_data.body,
created_at: raw_data.created_at,
updated_at: raw_data.created_at
}
end
def klass
Release
end
def valid?
!raw_data.draft
end
end
end
end
...@@ -18,19 +18,18 @@ module Gitlab ...@@ -18,19 +18,18 @@ module Gitlab
FileUtils.mkdir_p(path) FileUtils.mkdir_p(path)
end end
@cmd_output = "" cmd_output = ""
@cmd_status = 0 cmd_status = 0
Open3.popen3(vars, *cmd, options) do |stdin, stdout, stderr, wait_thr| Open3.popen3(vars, *cmd, options) do |stdin, stdout, stderr, wait_thr|
yield(stdin) if block_given? yield(stdin) if block_given?
stdin.close stdin.close
@cmd_output << stdout.read cmd_output << stdout.read
@cmd_output << stderr.read cmd_output << stderr.read
@cmd_status = wait_thr.value.exitstatus cmd_status = wait_thr.value.exitstatus
end end
[@cmd_output, @cmd_status] [cmd_output, cmd_status]
end end
end end
end end
...@@ -102,7 +102,7 @@ module Gitlab ...@@ -102,7 +102,7 @@ module Gitlab
def secret def secret
@secret ||= begin @secret ||= begin
bytes = Base64.strict_decode64(File.read(secret_path)) bytes = Base64.strict_decode64(File.read(secret_path).chomp)
raise "#{secret_path} does not contain #{SECRET_LENGTH} bytes" if bytes.length != SECRET_LENGTH raise "#{secret_path} does not contain #{SECRET_LENGTH} bytes" if bytes.length != SECRET_LENGTH
bytes bytes
end end
......
unless Rails.env.production?
require 'haml_lint/rake_task'
HamlLint::RakeTask.new
end
...@@ -181,6 +181,25 @@ describe ProjectsController do ...@@ -181,6 +181,25 @@ describe ProjectsController do
expect(response).to have_http_status(302) expect(response).to have_http_status(302)
expect(response).to redirect_to(dashboard_projects_path) expect(response).to redirect_to(dashboard_projects_path)
end end
context "when the project is forked" do
let(:project) { create(:project) }
let(:fork_project) { create(:project, forked_from_project: project) }
let(:merge_request) do
create(:merge_request,
source_project: fork_project,
target_project: project)
end
it "closes all related merge requests" do
project.merge_requests << merge_request
sign_in(admin)
delete :destroy, namespace_id: fork_project.namespace.path, id: fork_project.path
expect(merge_request.reload.state).to eq('closed')
end
end
end end
describe "POST #toggle_star" do describe "POST #toggle_star" do
......
...@@ -30,5 +30,9 @@ FactoryGirl.define do ...@@ -30,5 +30,9 @@ FactoryGirl.define do
trait :shared do trait :shared do
is_shared true is_shared true
end end
trait :inactive do
active false
end
end end
end end
FactoryGirl.define do FactoryGirl.define do
sequence :issue_created_at do |n|
4.hours.ago + ( 2 * n ).seconds
end
factory :issue do factory :issue do
title title
author author
......
require 'rails_helper'
describe 'Profile > SSH Keys', feature: true do
let(:user) { create(:user) }
before do
login_as(user)
visit profile_keys_path
end
describe 'User adds an SSH key' do
it 'auto-populates the title', js: true do
fill_in('Key', with: attributes_for(:key).fetch(:key))
expect(find_field('Title').value).to eq 'dummy@gitlab.com'
end
end
end
...@@ -57,7 +57,7 @@ feature 'Project', feature: true do ...@@ -57,7 +57,7 @@ feature 'Project', feature: true do
describe 'removal', js: true do describe 'removal', js: true do
let(:user) { create(:user) } let(:user) { create(:user) }
let(:project) { create(:project, namespace: user.namespace) } let(:project) { create(:project, namespace: user.namespace, name: 'project1') }
before do before do
login_with(user) login_with(user)
...@@ -65,8 +65,12 @@ feature 'Project', feature: true do ...@@ -65,8 +65,12 @@ feature 'Project', feature: true do
visit edit_namespace_project_path(project.namespace, project) visit edit_namespace_project_path(project.namespace, project)
end end
it 'removes project' do it 'removes a project' do
expect { remove_with_confirm('Remove project', project.path) }.to change {Project.count}.by(-1) expect { remove_with_confirm('Remove project', project.path) }.to change {Project.count}.by(-1)
expect(page).to have_content "Project 'project1' will be deleted."
expect(Project.all.count).to be_zero
expect(project.issues).to be_empty
expect(project.merge_requests).to be_empty
end end
end end
......
...@@ -127,6 +127,13 @@ describe Banzai::Pipeline::WikiPipeline do ...@@ -127,6 +127,13 @@ describe Banzai::Pipeline::WikiPipeline do
expect(output).to include("href=\"#{relative_url_root}/wiki_link_ns/wiki_link_project/wikis/nested/twice/page.md\"") expect(output).to include("href=\"#{relative_url_root}/wiki_link_ns/wiki_link_project/wikis/nested/twice/page.md\"")
end end
it 'rewrites links with anchor' do
markdown = '[Link to Header](start-page#title)'
output = described_class.to_html(markdown, project: project, project_wiki: project_wiki, page_slug: page.slug)
expect(output).to include("href=\"#{relative_url_root}/wiki_link_ns/wiki_link_project/wikis/start-page#title\"")
end
end end
describe "when creating root links" do describe "when creating root links" do
......
...@@ -73,6 +73,12 @@ describe Gitlab::GithubImport::CommentFormatter, lib: true do ...@@ -73,6 +73,12 @@ describe Gitlab::GithubImport::CommentFormatter, lib: true do
gl_user = create(:omniauth_user, extern_uid: octocat.id, provider: 'github') gl_user = create(:omniauth_user, extern_uid: octocat.id, provider: 'github')
expect(comment.attributes.fetch(:author_id)).to eq gl_user.id expect(comment.attributes.fetch(:author_id)).to eq gl_user.id
end end
it 'returns note without created at tag line' do
create(:omniauth_user, extern_uid: octocat.id, provider: 'github')
expect(comment.attributes.fetch(:note)).to eq("I'm having a problem with this.")
end
end end
end end
end end
...@@ -98,6 +98,30 @@ describe Gitlab::GithubImport::Importer, lib: true do ...@@ -98,6 +98,30 @@ describe Gitlab::GithubImport::Importer, lib: true do
) )
end end
let(:release1) do
double(
tag_name: 'v1.0.0',
name: 'First release',
body: 'Release v1.0.0',
draft: false,
created_at: created_at,
updated_at: updated_at,
url: 'https://api.github.com/repos/octocat/Hello-World/releases/1'
)
end
let(:release2) do
double(
tag_name: 'v2.0.0',
name: 'Second release',
body: nil,
draft: false,
created_at: created_at,
updated_at: updated_at,
url: 'https://api.github.com/repos/octocat/Hello-World/releases/2'
)
end
before do before do
allow(project).to receive(:import_data).and_return(double.as_null_object) allow(project).to receive(:import_data).and_return(double.as_null_object)
allow_any_instance_of(Octokit::Client).to receive(:rate_limit!).and_raise(Octokit::NotFound) allow_any_instance_of(Octokit::Client).to receive(:rate_limit!).and_raise(Octokit::NotFound)
...@@ -106,6 +130,7 @@ describe Gitlab::GithubImport::Importer, lib: true do ...@@ -106,6 +130,7 @@ describe Gitlab::GithubImport::Importer, lib: true do
allow_any_instance_of(Octokit::Client).to receive(:issues).and_return([issue1, issue2]) allow_any_instance_of(Octokit::Client).to receive(:issues).and_return([issue1, issue2])
allow_any_instance_of(Octokit::Client).to receive(:pull_requests).and_return([pull_request, pull_request]) allow_any_instance_of(Octokit::Client).to receive(:pull_requests).and_return([pull_request, pull_request])
allow_any_instance_of(Octokit::Client).to receive(:last_response).and_return(double(rels: { next: nil })) allow_any_instance_of(Octokit::Client).to receive(:last_response).and_return(double(rels: { next: nil }))
allow_any_instance_of(Octokit::Client).to receive(:releases).and_return([release1, release2])
allow_any_instance_of(Gitlab::Shell).to receive(:import_repository).and_raise(Gitlab::Shell::Error) allow_any_instance_of(Gitlab::Shell).to receive(:import_repository).and_raise(Gitlab::Shell::Error)
end end
...@@ -127,7 +152,8 @@ describe Gitlab::GithubImport::Importer, lib: true do ...@@ -127,7 +152,8 @@ describe Gitlab::GithubImport::Importer, lib: true do
{ type: :issue, url: "https://api.github.com/repos/octocat/Hello-World/issues/1348", errors: "Validation failed: Title can't be blank, Title is too short (minimum is 0 characters)" }, { type: :issue, url: "https://api.github.com/repos/octocat/Hello-World/issues/1348", errors: "Validation failed: Title can't be blank, Title is too short (minimum is 0 characters)" },
{ type: :pull_request, url: "https://api.github.com/repos/octocat/Hello-World/pulls/1347", errors: "Invalid Repository. Use user/repo format." }, { type: :pull_request, url: "https://api.github.com/repos/octocat/Hello-World/pulls/1347", errors: "Invalid Repository. Use user/repo format." },
{ type: :pull_request, url: "https://api.github.com/repos/octocat/Hello-World/pulls/1347", errors: "Validation failed: Validate branches Cannot Create: This merge request already exists: [\"New feature\"]" }, { type: :pull_request, url: "https://api.github.com/repos/octocat/Hello-World/pulls/1347", errors: "Validation failed: Validate branches Cannot Create: This merge request already exists: [\"New feature\"]" },
{ type: :wiki, errors: "Gitlab::Shell::Error" } { type: :wiki, errors: "Gitlab::Shell::Error" },
{ type: :release, url: 'https://api.github.com/repos/octocat/Hello-World/releases/2', errors: "Validation failed: Description can't be blank" }
] ]
} }
......
...@@ -109,6 +109,12 @@ describe Gitlab::GithubImport::IssueFormatter, lib: true do ...@@ -109,6 +109,12 @@ describe Gitlab::GithubImport::IssueFormatter, lib: true do
expect(issue.attributes.fetch(:author_id)).to eq gl_user.id expect(issue.attributes.fetch(:author_id)).to eq gl_user.id
end end
it 'returns description without created at tag line' do
create(:omniauth_user, extern_uid: octocat.id, provider: 'github')
expect(issue.attributes.fetch(:description)).to eq("I'm having a problem with this.")
end
end end
end end
......
...@@ -140,6 +140,12 @@ describe Gitlab::GithubImport::PullRequestFormatter, lib: true do ...@@ -140,6 +140,12 @@ describe Gitlab::GithubImport::PullRequestFormatter, lib: true do
expect(pull_request.attributes.fetch(:author_id)).to eq gl_user.id expect(pull_request.attributes.fetch(:author_id)).to eq gl_user.id
end end
it 'returns description without created at tag line' do
create(:omniauth_user, extern_uid: octocat.id, provider: 'github')
expect(pull_request.attributes.fetch(:description)).to eq('Please pull these awesome changes')
end
end end
context 'when it has a milestone' do context 'when it has a milestone' do
......
require 'spec_helper'
describe Gitlab::GithubImport::ReleaseFormatter, lib: true do
let!(:project) { create(:project, namespace: create(:namespace, path: 'octocat')) }
let(:octocat) { double(id: 123456, login: 'octocat') }
let(:created_at) { DateTime.strptime('2011-01-26T19:01:12Z') }
let(:base_data) do
{
tag_name: 'v1.0.0',
name: 'First release',
draft: false,
created_at: created_at,
published_at: created_at,
body: 'Release v1.0.0'
}
end
subject(:release) { described_class.new(project, raw_data) }
describe '#attributes' do
let(:raw_data) { double(base_data) }
it 'returns formatted attributes' do
expected = {
project: project,
tag: 'v1.0.0',
description: 'Release v1.0.0',
created_at: created_at,
updated_at: created_at
}
expect(release.attributes).to eq(expected)
end
end
describe '#valid' do
context 'when release is not a draft' do
let(:raw_data) { double(base_data) }
it 'returns true' do
expect(release.valid?).to eq true
end
end
context 'when release is draft' do
let(:raw_data) { double(base_data.merge(draft: true)) }
it 'returns false' do
expect(release.valid?).to eq false
end
end
end
end
...@@ -30,6 +30,11 @@ describe Gitlab::Workhorse, lib: true do ...@@ -30,6 +30,11 @@ describe Gitlab::Workhorse, lib: true do
expect(subject.encoding).to eq(Encoding::ASCII_8BIT) expect(subject.encoding).to eq(Encoding::ASCII_8BIT)
end end
it 'accepts a trailing newline' do
open(described_class.secret_path, 'a') { |f| f.write "\n" }
expect(subject.length).to eq(32)
end
it 'raises an exception if the secret file cannot be read' do it 'raises an exception if the secret file cannot be read' do
File.delete(described_class.secret_path) File.delete(described_class.secret_path)
expect { subject }.to raise_exception(Errno::ENOENT) expect { subject }.to raise_exception(Errno::ENOENT)
......
# encoding: utf-8
require 'rails_helper' require 'rails_helper'
describe Blob do describe Blob do
...@@ -7,6 +8,25 @@ describe Blob do ...@@ -7,6 +8,25 @@ describe Blob do
end end
end end
describe '#data' do
context 'using a binary blob' do
it 'returns the data as-is' do
data = "\n\xFF\xB9\xC3"
blob = described_class.new(double(binary?: true, data: data))
expect(blob.data).to eq(data)
end
end
context 'using a text blob' do
it 'converts the data to UTF-8' do
blob = described_class.new(double(binary?: false, data: "\n\xFF\xB9\xC3"))
expect(blob.data).to eq("\n���")
end
end
end
describe '#svg?' do describe '#svg?' do
it 'is falsey when not text' do it 'is falsey when not text' do
git_blob = double(text?: false) git_blob = double(text?: false)
......
...@@ -231,6 +231,34 @@ describe Ci::Build, models: true do ...@@ -231,6 +231,34 @@ describe Ci::Build, models: true do
it { is_expected.to eq(predefined_variables) } it { is_expected.to eq(predefined_variables) }
end end
context 'when build has user' do
let(:user) { create(:user, username: 'starter') }
let(:user_variables) do
[
{ key: 'GITLAB_USER_ID', value: user.id.to_s, public: true },
{ key: 'GITLAB_USER_EMAIL', value: user.email, public: true }
]
end
before do
build.update_attributes(user: user)
end
it { user_variables.each { |v| is_expected.to include(v) } }
end
context 'when build started manually' do
before do
build.update_attributes(when: :manual)
end
let(:manual_variable) do
{ key: 'CI_BUILD_MANUAL', value: 'true', public: true }
end
it { is_expected.to include(manual_variable) }
end
context 'when build is for tag' do context 'when build is for tag' do
let(:tag_variable) do let(:tag_variable) do
{ key: 'CI_BUILD_TAG', value: 'master', public: true } { key: 'CI_BUILD_TAG', value: 'master', public: true }
......
...@@ -373,8 +373,8 @@ describe Ci::Pipeline, models: true do ...@@ -373,8 +373,8 @@ describe Ci::Pipeline, models: true do
end end
describe '#execute_hooks' do describe '#execute_hooks' do
let!(:build_a) { create_build('a') } let!(:build_a) { create_build('a', 0) }
let!(:build_b) { create_build('b') } let!(:build_b) { create_build('b', 1) }
let!(:hook) do let!(:hook) do
create(:project_hook, project: project, pipeline_events: enabled) create(:project_hook, project: project, pipeline_events: enabled)
...@@ -398,7 +398,7 @@ describe Ci::Pipeline, models: true do ...@@ -398,7 +398,7 @@ describe Ci::Pipeline, models: true do
build_b.enqueue build_b.enqueue
end end
it 'receive a pending event once' do it 'receives a pending event once' do
expect(WebMock).to have_requested_pipeline_hook('pending').once expect(WebMock).to have_requested_pipeline_hook('pending').once
end end
end end
...@@ -411,7 +411,7 @@ describe Ci::Pipeline, models: true do ...@@ -411,7 +411,7 @@ describe Ci::Pipeline, models: true do
build_b.run build_b.run
end end
it 'receive a running event once' do it 'receives a running event once' do
expect(WebMock).to have_requested_pipeline_hook('running').once expect(WebMock).to have_requested_pipeline_hook('running').once
end end
end end
...@@ -422,11 +422,21 @@ describe Ci::Pipeline, models: true do ...@@ -422,11 +422,21 @@ describe Ci::Pipeline, models: true do
build_b.success build_b.success
end end
it 'receive a success event once' do it 'receives a success event once' do
expect(WebMock).to have_requested_pipeline_hook('success').once expect(WebMock).to have_requested_pipeline_hook('success').once
end end
end end
context 'when stage one failed' do
before do
build_a.drop
end
it 'receives a failed event once' do
expect(WebMock).to have_requested_pipeline_hook('failed').once
end
end
def have_requested_pipeline_hook(status) def have_requested_pipeline_hook(status)
have_requested(:post, hook.url).with do |req| have_requested(:post, hook.url).with do |req|
json_body = JSON.parse(req.body) json_body = JSON.parse(req.body)
...@@ -450,8 +460,12 @@ describe Ci::Pipeline, models: true do ...@@ -450,8 +460,12 @@ describe Ci::Pipeline, models: true do
end end
end end
def create_build(name) def create_build(name, stage_idx)
create(:ci_build, :created, pipeline: pipeline, name: name) create(:ci_build,
:created,
pipeline: pipeline,
name: name,
stage_idx: stage_idx)
end end
end end
end end
...@@ -40,7 +40,7 @@ describe CommitStatus, models: true do ...@@ -40,7 +40,7 @@ describe CommitStatus, models: true do
it { is_expected.to be_falsey } it { is_expected.to be_falsey }
end end
%w(running success failed).each do |status| %w[running success failed].each do |status|
context "if commit status is #{status}" do context "if commit status is #{status}" do
before { commit_status.status = status } before { commit_status.status = status }
...@@ -48,7 +48,7 @@ describe CommitStatus, models: true do ...@@ -48,7 +48,7 @@ describe CommitStatus, models: true do
end end
end end
%w(pending canceled).each do |status| %w[pending canceled].each do |status|
context "if commit status is #{status}" do context "if commit status is #{status}" do
before { commit_status.status = status } before { commit_status.status = status }
...@@ -60,7 +60,7 @@ describe CommitStatus, models: true do ...@@ -60,7 +60,7 @@ describe CommitStatus, models: true do
describe '#active?' do describe '#active?' do
subject { commit_status.active? } subject { commit_status.active? }
%w(pending running).each do |state| %w[pending running].each do |state|
context "if commit_status.status is #{state}" do context "if commit_status.status is #{state}" do
before { commit_status.status = state } before { commit_status.status = state }
...@@ -68,7 +68,7 @@ describe CommitStatus, models: true do ...@@ -68,7 +68,7 @@ describe CommitStatus, models: true do
end end
end end
%w(success failed canceled).each do |state| %w[success failed canceled].each do |state|
context "if commit_status.status is #{state}" do context "if commit_status.status is #{state}" do
before { commit_status.status = state } before { commit_status.status = state }
...@@ -80,7 +80,7 @@ describe CommitStatus, models: true do ...@@ -80,7 +80,7 @@ describe CommitStatus, models: true do
describe '#complete?' do describe '#complete?' do
subject { commit_status.complete? } subject { commit_status.complete? }
%w(success failed canceled).each do |state| %w[success failed canceled].each do |state|
context "if commit_status.status is #{state}" do context "if commit_status.status is #{state}" do
before { commit_status.status = state } before { commit_status.status = state }
...@@ -88,7 +88,7 @@ describe CommitStatus, models: true do ...@@ -88,7 +88,7 @@ describe CommitStatus, models: true do
end end
end end
%w(pending running).each do |state| %w[pending running].each do |state|
context "if commit_status.status is #{state}" do context "if commit_status.status is #{state}" do
before { commit_status.status = state } before { commit_status.status = state }
...@@ -187,7 +187,7 @@ describe CommitStatus, models: true do ...@@ -187,7 +187,7 @@ describe CommitStatus, models: true do
subject { CommitStatus.where(pipeline: pipeline).stages } subject { CommitStatus.where(pipeline: pipeline).stages }
it 'returns ordered list of stages' do it 'returns ordered list of stages' do
is_expected.to eq(%w(build test deploy)) is_expected.to eq(%w[build test deploy])
end end
end end
......
...@@ -57,7 +57,7 @@ describe Member, models: true do ...@@ -57,7 +57,7 @@ describe Member, models: true do
describe 'Scopes & finders' do describe 'Scopes & finders' do
before do before do
project = create(:project) project = create(:empty_project)
group = create(:group) group = create(:group)
@owner_user = create(:user).tap { |u| group.add_owner(u) } @owner_user = create(:user).tap { |u| group.add_owner(u) }
@owner = group.members.find_by(user_id: @owner_user.id) @owner = group.members.find_by(user_id: @owner_user.id)
...@@ -65,6 +65,15 @@ describe Member, models: true do ...@@ -65,6 +65,15 @@ describe Member, models: true do
@master_user = create(:user).tap { |u| project.team << [u, :master] } @master_user = create(:user).tap { |u| project.team << [u, :master] }
@master = project.members.find_by(user_id: @master_user.id) @master = project.members.find_by(user_id: @master_user.id)
@blocked_user = create(:user).tap do |u|
project.team << [u, :master]
project.team << [u, :developer]
u.block!
end
@blocked_master = project.members.find_by(user_id: @blocked_user.id, access_level: Gitlab::Access::MASTER)
@blocked_developer = project.members.find_by(user_id: @blocked_user.id, access_level: Gitlab::Access::DEVELOPER)
Member.add_user( Member.add_user(
project.members, project.members,
'toto1@example.com', 'toto1@example.com',
...@@ -73,7 +82,7 @@ describe Member, models: true do ...@@ -73,7 +82,7 @@ describe Member, models: true do
) )
@invited_member = project.members.invite.find_by_invite_email('toto1@example.com') @invited_member = project.members.invite.find_by_invite_email('toto1@example.com')
accepted_invite_user = build(:user) accepted_invite_user = build(:user, state: :active)
Member.add_user( Member.add_user(
project.members, project.members,
'toto2@example.com', 'toto2@example.com',
...@@ -91,7 +100,7 @@ describe Member, models: true do ...@@ -91,7 +100,7 @@ describe Member, models: true do
describe '.access_for_user_ids' do describe '.access_for_user_ids' do
it 'returns the right access levels' do it 'returns the right access levels' do
users = [@owner_user.id, @master_user.id] users = [@owner_user.id, @master_user.id, @blocked_user.id]
expected = { expected = {
@owner_user.id => Gitlab::Access::OWNER, @owner_user.id => Gitlab::Access::OWNER,
@master_user.id => Gitlab::Access::MASTER @master_user.id => Gitlab::Access::MASTER
...@@ -125,6 +134,19 @@ describe Member, models: true do ...@@ -125,6 +134,19 @@ describe Member, models: true do
it { expect(described_class.request).not_to include @accepted_request_member } it { expect(described_class.request).not_to include @accepted_request_member }
end end
describe '.developers' do
subject { described_class.developers.to_a }
it { is_expected.not_to include @owner }
it { is_expected.not_to include @master }
it { is_expected.to include @invited_member }
it { is_expected.to include @accepted_invite_member }
it { is_expected.not_to include @requested_member }
it { is_expected.to include @accepted_request_member }
it { is_expected.not_to include @blocked_master }
it { is_expected.not_to include @blocked_developer }
end
describe '.owners_and_masters' do describe '.owners_and_masters' do
it { expect(described_class.owners_and_masters).to include @owner } it { expect(described_class.owners_and_masters).to include @owner }
it { expect(described_class.owners_and_masters).to include @master } it { expect(described_class.owners_and_masters).to include @master }
...@@ -132,6 +154,20 @@ describe Member, models: true do ...@@ -132,6 +154,20 @@ describe Member, models: true do
it { expect(described_class.owners_and_masters).not_to include @accepted_invite_member } it { expect(described_class.owners_and_masters).not_to include @accepted_invite_member }
it { expect(described_class.owners_and_masters).not_to include @requested_member } it { expect(described_class.owners_and_masters).not_to include @requested_member }
it { expect(described_class.owners_and_masters).not_to include @accepted_request_member } it { expect(described_class.owners_and_masters).not_to include @accepted_request_member }
it { expect(described_class.owners_and_masters).not_to include @blocked_master }
end
describe '.has_access' do
subject { described_class.has_access.to_a }
it { is_expected.to include @owner }
it { is_expected.to include @master }
it { is_expected.to include @invited_member }
it { is_expected.to include @accepted_invite_member }
it { is_expected.not_to include @requested_member }
it { is_expected.to include @accepted_request_member }
it { is_expected.not_to include @blocked_master }
it { is_expected.not_to include @blocked_developer }
end end
end end
......
...@@ -1338,4 +1338,81 @@ describe MergeRequest, models: true do ...@@ -1338,4 +1338,81 @@ describe MergeRequest, models: true do
end end
end end
end end
describe '#closed_without_source_project?' do
let(:project) { create(:project) }
let(:user) { create(:user) }
let(:fork_project) { create(:project, forked_from_project: project, namespace: user.namespace) }
let(:destroy_service) { Projects::DestroyService.new(fork_project, user) }
context 'when the merge request is closed' do
let(:closed_merge_request) do
create(:closed_merge_request,
source_project: fork_project,
target_project: project)
end
it 'returns false if the source project exists' do
expect(closed_merge_request.closed_without_source_project?).to be_falsey
end
it 'returns true if the source project does not exist' do
destroy_service.execute
closed_merge_request.reload
expect(closed_merge_request.closed_without_source_project?).to be_truthy
end
end
context 'when the merge request is open' do
it 'returns false' do
expect(subject.closed_without_source_project?).to be_falsey
end
end
end
describe '#reopenable?' do
context 'when the merge request is closed' do
it 'returns true' do
subject.close
expect(subject.reopenable?).to be_truthy
end
context 'forked project' do
let(:project) { create(:project) }
let(:user) { create(:user) }
let(:fork_project) { create(:project, forked_from_project: project, namespace: user.namespace) }
let(:merge_request) do
create(:closed_merge_request,
source_project: fork_project,
target_project: project)
end
it 'returns false if unforked' do
Projects::UnlinkForkService.new(fork_project, user).execute
expect(merge_request.reload.reopenable?).to be_falsey
end
it 'returns false if the source project is deleted' do
Projects::DestroyService.new(fork_project, user).execute
expect(merge_request.reload.reopenable?).to be_falsey
end
it 'returns false if the merge request is merged' do
merge_request.update_attributes(state: 'merged')
expect(merge_request.reload.reopenable?).to be_falsey
end
end
end
context 'when the merge request is opened' do
it 'returns false' do
expect(subject.reopenable?).to be_falsey
end
end
end
end end
...@@ -6,6 +6,7 @@ describe Project, models: true do ...@@ -6,6 +6,7 @@ describe Project, models: true do
it { is_expected.to belong_to(:namespace) } it { is_expected.to belong_to(:namespace) }
it { is_expected.to belong_to(:creator).class_name('User') } it { is_expected.to belong_to(:creator).class_name('User') }
it { is_expected.to have_many(:users) } it { is_expected.to have_many(:users) }
it { is_expected.to have_many(:services) }
it { is_expected.to have_many(:events).dependent(:destroy) } it { is_expected.to have_many(:events).dependent(:destroy) }
it { is_expected.to have_many(:merge_requests).dependent(:destroy) } it { is_expected.to have_many(:merge_requests).dependent(:destroy) }
it { is_expected.to have_many(:issues).dependent(:destroy) } it { is_expected.to have_many(:issues).dependent(:destroy) }
...@@ -24,6 +25,30 @@ describe Project, models: true do ...@@ -24,6 +25,30 @@ describe Project, models: true do
it { is_expected.to have_one(:pushover_service).dependent(:destroy) } it { is_expected.to have_one(:pushover_service).dependent(:destroy) }
it { is_expected.to have_one(:asana_service).dependent(:destroy) } it { is_expected.to have_one(:asana_service).dependent(:destroy) }
it { is_expected.to have_one(:board).dependent(:destroy) } it { is_expected.to have_one(:board).dependent(:destroy) }
it { is_expected.to have_one(:campfire_service).dependent(:destroy) }
it { is_expected.to have_one(:drone_ci_service).dependent(:destroy) }
it { is_expected.to have_one(:emails_on_push_service).dependent(:destroy) }
it { is_expected.to have_one(:builds_email_service).dependent(:destroy) }
it { is_expected.to have_one(:emails_on_push_service).dependent(:destroy) }
it { is_expected.to have_one(:irker_service).dependent(:destroy) }
it { is_expected.to have_one(:pivotaltracker_service).dependent(:destroy) }
it { is_expected.to have_one(:hipchat_service).dependent(:destroy) }
it { is_expected.to have_one(:flowdock_service).dependent(:destroy) }
it { is_expected.to have_one(:assembla_service).dependent(:destroy) }
it { is_expected.to have_one(:gemnasium_service).dependent(:destroy) }
it { is_expected.to have_one(:buildkite_service).dependent(:destroy) }
it { is_expected.to have_one(:bamboo_service).dependent(:destroy) }
it { is_expected.to have_one(:teamcity_service).dependent(:destroy) }
it { is_expected.to have_one(:jira_service).dependent(:destroy) }
it { is_expected.to have_one(:redmine_service).dependent(:destroy) }
it { is_expected.to have_one(:custom_issue_tracker_service).dependent(:destroy) }
it { is_expected.to have_one(:bugzilla_service).dependent(:destroy) }
it { is_expected.to have_one(:gitlab_issue_tracker_service).dependent(:destroy) }
it { is_expected.to have_one(:external_wiki_service).dependent(:destroy) }
it { is_expected.to have_one(:project_feature).dependent(:destroy) }
it { is_expected.to have_one(:import_data).class_name('ProjectImportData').dependent(:destroy) }
it { is_expected.to have_one(:last_event).class_name('Event') }
it { is_expected.to have_one(:forked_from_project).through(:forked_project_link) }
it { is_expected.to have_many(:commit_statuses) } it { is_expected.to have_many(:commit_statuses) }
it { is_expected.to have_many(:pipelines) } it { is_expected.to have_many(:pipelines) }
it { is_expected.to have_many(:builds) } it { is_expected.to have_many(:builds) }
...@@ -32,10 +57,17 @@ describe Project, models: true do ...@@ -32,10 +57,17 @@ describe Project, models: true do
it { is_expected.to have_many(:variables) } it { is_expected.to have_many(:variables) }
it { is_expected.to have_many(:triggers) } it { is_expected.to have_many(:triggers) }
it { is_expected.to have_many(:pages_domains) } it { is_expected.to have_many(:pages_domains) }
it { is_expected.to have_many(:path_locks).dependent(:destroy) }
it { is_expected.to have_many(:labels).dependent(:destroy) }
it { is_expected.to have_many(:users_star_projects).dependent(:destroy) }
it { is_expected.to have_many(:environments).dependent(:destroy) } it { is_expected.to have_many(:environments).dependent(:destroy) }
it { is_expected.to have_many(:deployments).dependent(:destroy) } it { is_expected.to have_many(:deployments).dependent(:destroy) }
it { is_expected.to have_many(:todos).dependent(:destroy) } it { is_expected.to have_many(:todos).dependent(:destroy) }
it { is_expected.to have_many(:path_locks).dependent(:destroy) } it { is_expected.to have_many(:releases).dependent(:destroy) }
it { is_expected.to have_many(:lfs_objects_projects).dependent(:destroy) }
it { is_expected.to have_many(:project_group_links).dependent(:destroy) }
it { is_expected.to have_many(:notification_settings).dependent(:destroy) }
it { is_expected.to have_many(:forks).through(:forked_project_links) }
describe '#members & #requesters' do describe '#members & #requesters' do
let(:project) { create(:project) } let(:project) { create(:project) }
...@@ -187,7 +219,7 @@ describe Project, models: true do ...@@ -187,7 +219,7 @@ describe Project, models: true do
expect(project.runners_token).not_to eq('') expect(project.runners_token).not_to eq('')
end end
it 'does not set an random toke if one provided' do it 'does not set an random token if one provided' do
project = FactoryGirl.create :empty_project, runners_token: 'my-token' project = FactoryGirl.create :empty_project, runners_token: 'my-token'
expect(project.runners_token).to eq('my-token') expect(project.runners_token).to eq('my-token')
end end
...@@ -1709,4 +1741,56 @@ describe Project, models: true do ...@@ -1709,4 +1741,56 @@ describe Project, models: true do
project.change_head(project.default_branch) project.change_head(project.default_branch)
end end
end end
describe '#pushes_since_gc' do
let(:project) { create(:project) }
after do
project.reset_pushes_since_gc
end
context 'without any pushes' do
it 'returns 0' do
expect(project.pushes_since_gc).to eq(0)
end
end
context 'with a number of pushes' do
it 'returns the number of pushes' do
3.times { project.increment_pushes_since_gc }
expect(project.pushes_since_gc).to eq(3)
end
end
end
describe '#increment_pushes_since_gc' do
let(:project) { create(:project) }
after do
project.reset_pushes_since_gc
end
it 'increments the number of pushes since the last GC' do
3.times { project.increment_pushes_since_gc }
expect(project.pushes_since_gc).to eq(3)
end
end
describe '#reset_pushes_since_gc' do
let(:project) { create(:project) }
after do
project.reset_pushes_since_gc
end
it 'resets the number of pushes since the last GC' do
3.times { project.increment_pushes_since_gc }
project.reset_pushes_since_gc
expect(project.pushes_since_gc).to eq(0)
end
end
end end
...@@ -117,19 +117,38 @@ describe API::CommitStatuses, api: true do ...@@ -117,19 +117,38 @@ describe API::CommitStatuses, api: true do
let(:post_url) { "/projects/#{project.id}/statuses/#{sha}" } let(:post_url) { "/projects/#{project.id}/statuses/#{sha}" }
context 'developer user' do context 'developer user' do
context 'only required parameters' do %w[pending running success failed canceled].each do |status|
before { post api(post_url, developer), state: 'success' } context "for #{status}" do
context 'uses only required parameters' do
it 'creates commit status' do it 'creates commit status' do
post api(post_url, developer), state: status
expect(response).to have_http_status(201) expect(response).to have_http_status(201)
expect(json_response['sha']).to eq(commit.id) expect(json_response['sha']).to eq(commit.id)
expect(json_response['status']).to eq('success') expect(json_response['status']).to eq(status)
expect(json_response['name']).to eq('default') expect(json_response['name']).to eq('default')
expect(json_response['ref']).to be_nil expect(json_response['ref']).not_to be_empty
expect(json_response['target_url']).to be_nil expect(json_response['target_url']).to be_nil
expect(json_response['description']).to be_nil expect(json_response['description']).to be_nil
end end
end end
end
end
context 'transitions status from pending' do
before do
post api(post_url, developer), state: 'pending'
end
%w[running success failed canceled].each do |status|
it "to #{status}" do
expect { post api(post_url, developer), state: status }.not_to change { CommitStatus.count }
expect(response).to have_http_status(201)
expect(json_response['status']).to eq(status)
end
end
end
context 'with all optional parameters' do context 'with all optional parameters' do
before do before do
......
...@@ -17,21 +17,27 @@ describe API::API, api: true do ...@@ -17,21 +17,27 @@ describe API::API, api: true do
assignee: user, assignee: user,
project: project, project: project,
state: :closed, state: :closed,
milestone: milestone milestone: milestone,
created_at: generate(:issue_created_at),
updated_at: 3.hours.ago
end end
let!(:confidential_issue) do let!(:confidential_issue) do
create :issue, create :issue,
:confidential, :confidential,
project: project, project: project,
author: author, author: author,
assignee: assignee assignee: assignee,
created_at: generate(:issue_created_at),
updated_at: 2.hours.ago
end end
let!(:issue) do let!(:issue) do
create :issue, create :issue,
author: user, author: user,
assignee: user, assignee: user,
project: project, project: project,
milestone: milestone milestone: milestone,
created_at: generate(:issue_created_at),
updated_at: 1.hour.ago
end end
let!(:label) do let!(:label) do
create(:label, title: 'label', color: '#FFAABB', project: project) create(:label, title: 'label', color: '#FFAABB', project: project)
...@@ -135,6 +141,42 @@ describe API::API, api: true do ...@@ -135,6 +141,42 @@ describe API::API, api: true do
expect(json_response).to be_an Array expect(json_response).to be_an Array
expect(json_response.length).to eq(0) expect(json_response.length).to eq(0)
end end
it 'sorts by created_at descending by default' do
get api('/issues', user)
response_dates = json_response.map { |issue| issue['created_at'] }
expect(response).to have_http_status(200)
expect(json_response).to be_an Array
expect(response_dates).to eq(response_dates.sort.reverse)
end
it 'sorts ascending when requested' do
get api('/issues?sort=asc', user)
response_dates = json_response.map { |issue| issue['created_at'] }
expect(response).to have_http_status(200)
expect(json_response).to be_an Array
expect(response_dates).to eq(response_dates.sort)
end
it 'sorts by updated_at descending when requested' do
get api('/issues?order_by=updated_at', user)
response_dates = json_response.map { |issue| issue['updated_at'] }
expect(response).to have_http_status(200)
expect(json_response).to be_an Array
expect(response_dates).to eq(response_dates.sort.reverse)
end
it 'sorts by updated_at ascending when requested' do
get api('/issues?order_by=updated_at&sort=asc', user)
response_dates = json_response.map { |issue| issue['updated_at'] }
expect(response).to have_http_status(200)
expect(json_response).to be_an Array
expect(response_dates).to eq(response_dates.sort)
end
end end
end end
...@@ -147,21 +189,24 @@ describe API::API, api: true do ...@@ -147,21 +189,24 @@ describe API::API, api: true do
assignee: user, assignee: user,
project: group_project, project: group_project,
state: :closed, state: :closed,
milestone: group_milestone milestone: group_milestone,
updated_at: 3.hours.ago
end end
let!(:group_confidential_issue) do let!(:group_confidential_issue) do
create :issue, create :issue,
:confidential, :confidential,
project: group_project, project: group_project,
author: author, author: author,
assignee: assignee assignee: assignee,
updated_at: 2.hours.ago
end end
let!(:group_issue) do let!(:group_issue) do
create :issue, create :issue,
author: user, author: user,
assignee: user, assignee: user,
project: group_project, project: group_project,
milestone: group_milestone milestone: group_milestone,
updated_at: 1.hour.ago
end end
let!(:group_label) do let!(:group_label) do
create(:label, title: 'group_lbl', color: '#FFAABB', project: group_project) create(:label, title: 'group_lbl', color: '#FFAABB', project: group_project)
...@@ -278,6 +323,42 @@ describe API::API, api: true do ...@@ -278,6 +323,42 @@ describe API::API, api: true do
expect(json_response.length).to eq(1) expect(json_response.length).to eq(1)
expect(json_response.first['id']).to eq(group_closed_issue.id) expect(json_response.first['id']).to eq(group_closed_issue.id)
end end
it 'sorts by created_at descending by default' do
get api(base_url, user)
response_dates = json_response.map { |issue| issue['created_at'] }
expect(response).to have_http_status(200)
expect(json_response).to be_an Array
expect(response_dates).to eq(response_dates.sort.reverse)
end
it 'sorts ascending when requested' do
get api("#{base_url}?sort=asc", user)
response_dates = json_response.map { |issue| issue['created_at'] }
expect(response).to have_http_status(200)
expect(json_response).to be_an Array
expect(response_dates).to eq(response_dates.sort)
end
it 'sorts by updated_at descending when requested' do
get api("#{base_url}?order_by=updated_at", user)
response_dates = json_response.map { |issue| issue['updated_at'] }
expect(response).to have_http_status(200)
expect(json_response).to be_an Array
expect(response_dates).to eq(response_dates.sort.reverse)
end
it 'sorts by updated_at ascending when requested' do
get api("#{base_url}?order_by=updated_at&sort=asc", user)
response_dates = json_response.map { |issue| issue['updated_at'] }
expect(response).to have_http_status(200)
expect(json_response).to be_an Array
expect(response_dates).to eq(response_dates.sort)
end
end end
describe "GET /projects/:id/issues" do describe "GET /projects/:id/issues" do
...@@ -386,6 +467,42 @@ describe API::API, api: true do ...@@ -386,6 +467,42 @@ describe API::API, api: true do
expect(json_response.length).to eq(1) expect(json_response.length).to eq(1)
expect(json_response.first['id']).to eq(closed_issue.id) expect(json_response.first['id']).to eq(closed_issue.id)
end end
it 'sorts by created_at descending by default' do
get api("#{base_url}/issues", user)
response_dates = json_response.map { |issue| issue['created_at'] }
expect(response).to have_http_status(200)
expect(json_response).to be_an Array
expect(response_dates).to eq(response_dates.sort.reverse)
end
it 'sorts ascending when requested' do
get api("#{base_url}/issues?sort=asc", user)
response_dates = json_response.map { |issue| issue['created_at'] }
expect(response).to have_http_status(200)
expect(json_response).to be_an Array
expect(response_dates).to eq(response_dates.sort)
end
it 'sorts by updated_at descending when requested' do
get api("#{base_url}/issues?order_by=updated_at", user)
response_dates = json_response.map { |issue| issue['updated_at'] }
expect(response).to have_http_status(200)
expect(json_response).to be_an Array
expect(response_dates).to eq(response_dates.sort.reverse)
end
it 'sorts by updated_at ascending when requested' do
get api("#{base_url}/issues?order_by=updated_at&sort=asc", user)
response_dates = json_response.map { |issue| issue['updated_at'] }
expect(response).to have_http_status(200)
expect(json_response).to be_an Array
expect(response_dates).to eq(response_dates.sort)
end
end end
describe "GET /projects/:id/issues/:issue_id" do describe "GET /projects/:id/issues/:issue_id" do
......
require 'spec_helper'
describe API::API, api: true do
include ApiHelpers
let(:user) { create(:user) }
let!(:group) { create(:group) }
let!(:project) { create(:project, :public, creator_id: user.id, namespace: group) }
describe "GET /notification_settings" do
it "returns global notification settings for the current user" do
get api("/notification_settings", user)
expect(response).to have_http_status(200)
expect(json_response).to be_a Hash
expect(json_response['notification_email']).to eq(user.notification_email)
expect(json_response['level']).to eq(user.global_notification_setting.level)
end
end
describe "PUT /notification_settings" do
let(:email) { create(:email, user: user) }
it "updates global notification settings for the current user" do
put api("/notification_settings", user), { level: 'watch', notification_email: email.email }
expect(response).to have_http_status(200)
expect(json_response['notification_email']).to eq(email.email)
expect(user.reload.notification_email).to eq(email.email)
expect(json_response['level']).to eq(user.reload.global_notification_setting.level)
end
end
describe "PUT /notification_settings" do
it "fails on non-user email address" do
put api("/notification_settings", user), { notification_email: 'invalid@example.com' }
expect(response).to have_http_status(400)
end
end
describe "GET /groups/:id/notification_settings" do
it "returns group level notification settings for the current user" do
get api("/groups/#{group.id}/notification_settings", user)
expect(response).to have_http_status(200)
expect(json_response).to be_a Hash
expect(json_response['level']).to eq(user.notification_settings_for(group).level)
end
end
describe "PUT /groups/:id/notification_settings" do
it "updates group level notification settings for the current user" do
put api("/groups/#{group.id}/notification_settings", user), { level: 'watch' }
expect(response).to have_http_status(200)
expect(json_response['level']).to eq(user.reload.notification_settings_for(group).level)
end
end
describe "GET /projects/:id/notification_settings" do
it "returns project level notification settings for the current user" do
get api("/projects/#{project.id}/notification_settings", user)
expect(response).to have_http_status(200)
expect(json_response).to be_a Hash
expect(json_response['level']).to eq(user.notification_settings_for(project).level)
end
end
describe "PUT /projects/:id/notification_settings" do
it "updates project level notification settings for the current user" do
put api("/projects/#{project.id}/notification_settings", user), { level: 'custom', new_note: true }
expect(response).to have_http_status(200)
expect(json_response['level']).to eq(user.reload.notification_settings_for(project).level)
expect(json_response['events']['new_note']).to eq(true)
expect(json_response['events']['new_issue']).to eq(false)
end
end
describe "PUT /projects/:id/notification_settings" do
it "fails on invalid level" do
put api("/projects/#{project.id}/notification_settings", user), { level: 'invalid' }
expect(response).to have_http_status(400)
end
end
end
...@@ -15,6 +15,25 @@ describe Ci::API::API do ...@@ -15,6 +15,25 @@ describe Ci::API::API do
describe "POST /builds/register" do describe "POST /builds/register" do
let!(:build) { create(:ci_build, pipeline: pipeline, name: 'spinach', stage: 'test', stage_idx: 0) } let!(:build) { create(:ci_build, pipeline: pipeline, name: 'spinach', stage: 'test', stage_idx: 0) }
let(:user_agent) { 'gitlab-ci-multi-runner 1.5.2 (1-5-stable; go1.6.3; linux/amd64)' }
shared_examples 'no builds available' do
context 'when runner sends version in User-Agent' do
context 'for stable version' do
it { expect(response).to have_http_status(204) }
end
context 'for beta version' do
let(:user_agent) { 'gitlab-ci-multi-runner 1.6.0~beta.167.g2b2bacc (1-5-stable; go1.6.3; linux/amd64)' }
it { expect(response).to have_http_status(204) }
end
end
context "when runner doesn't send version in User-Agent" do
let(:user_agent) { 'Go-http-client/1.1' }
it { expect(response).to have_http_status(404) }
end
end
it "starts a build" do it "starts a build" do
register_builds info: { platform: :darwin } register_builds info: { platform: :darwin }
...@@ -33,36 +52,30 @@ describe Ci::API::API do ...@@ -33,36 +52,30 @@ describe Ci::API::API do
context 'when builds are finished' do context 'when builds are finished' do
before do before do
build.success build.success
end
it "returns 404 error if no builds for specific runner" do
register_builds register_builds
expect(response).to have_http_status(404)
end end
it_behaves_like 'no builds available'
end end
context 'for other project with builds' do context 'for other project with builds' do
before do before do
build.success build.success
create(:ci_build, :pending) create(:ci_build, :pending)
end
it "returns 404 error if no builds for shared runner" do
register_builds register_builds
expect(response).to have_http_status(404)
end end
it_behaves_like 'no builds available'
end end
context 'for shared runner' do context 'for shared runner' do
let(:shared_runner) { create(:ci_runner, token: "SharedRunner") } let(:shared_runner) { create(:ci_runner, token: "SharedRunner") }
it "should return 404 error if no builds for shared runner" do before do
register_builds shared_runner.token register_builds shared_runner.token
expect(response).to have_http_status(404)
end end
it_behaves_like 'no builds available'
end end
context 'for triggered build' do context 'for triggered build' do
...@@ -136,18 +149,27 @@ describe Ci::API::API do ...@@ -136,18 +149,27 @@ describe Ci::API::API do
end end
context 'when runner is not allowed to pick untagged builds' do context 'when runner is not allowed to pick untagged builds' do
before { runner.update_column(:run_untagged, false) } before do
runner.update_column(:run_untagged, false)
it 'does not pick build' do
register_builds register_builds
end
expect(response).to have_http_status 404 it_behaves_like 'no builds available'
end end
end end
context 'when runner is paused' do
let(:inactive_runner) { create(:ci_runner, :inactive, token: "InactiveRunner") }
before do
register_builds inactive_runner.token
end
it { expect(response).to have_http_status 404 }
end end
def register_builds(token = runner.token, **params) def register_builds(token = runner.token, **params)
post ci_api("/builds/register"), params.merge(token: token) post ci_api("/builds/register"), params.merge(token: token), { 'User-Agent' => user_agent }
end end
end end
......
...@@ -4,12 +4,11 @@ describe Projects::HousekeepingService do ...@@ -4,12 +4,11 @@ describe Projects::HousekeepingService do
subject { Projects::HousekeepingService.new(project) } subject { Projects::HousekeepingService.new(project) }
let(:project) { create :project } let(:project) { create :project }
describe 'execute' do after do
before do project.reset_pushes_since_gc
project.pushes_since_gc = 3
project.save!
end end
describe '#execute' do
it 'enqueues a sidekiq job' do it 'enqueues a sidekiq job' do
expect(subject).to receive(:try_obtain_lease).and_return(true) expect(subject).to receive(:try_obtain_lease).and_return(true)
expect(GitGarbageCollectWorker).to receive(:perform_async).with(project.id) expect(GitGarbageCollectWorker).to receive(:perform_async).with(project.id)
...@@ -32,12 +31,12 @@ describe Projects::HousekeepingService do ...@@ -32,12 +31,12 @@ describe Projects::HousekeepingService do
it 'does not reset pushes_since_gc' do it 'does not reset pushes_since_gc' do
expect do expect do
expect { subject.execute }.to raise_error(Projects::HousekeepingService::LeaseTaken) expect { subject.execute }.to raise_error(Projects::HousekeepingService::LeaseTaken)
end.not_to change { project.pushes_since_gc }.from(3) end.not_to change { project.pushes_since_gc }
end end
end end
end end
describe 'needed?' do describe '#needed?' do
it 'when the count is low enough' do it 'when the count is low enough' do
expect(subject.needed?).to eq(false) expect(subject.needed?).to eq(false)
end end
...@@ -48,25 +47,11 @@ describe Projects::HousekeepingService do ...@@ -48,25 +47,11 @@ describe Projects::HousekeepingService do
end end
end end
describe 'increment!' do describe '#increment!' do
let(:lease_key) { "project_housekeeping:increment!:#{project.id}" }
it 'increments the pushes_since_gc counter' do it 'increments the pushes_since_gc counter' do
lease = double(:lease, try_obtain: true)
expect(Gitlab::ExclusiveLease).to receive(:new).with(lease_key, anything).and_return(lease)
expect do expect do
subject.increment! subject.increment!
end.to change { project.pushes_since_gc }.from(0).to(1) end.to change { project.pushes_since_gc }.from(0).to(1)
end end
it 'does not increment when no lease can be obtained' do
lease = double(:lease, try_obtain: false)
expect(Gitlab::ExclusiveLease).to receive(:new).with(lease_key, anything).and_return(lease)
expect do
subject.increment!
end.not_to change { project.pushes_since_gc }
end
end end
end end
...@@ -3,5 +3,4 @@ build/ ...@@ -3,5 +3,4 @@ build/
nbbuild/ nbbuild/
dist/ dist/
nbdist/ nbdist/
nbactions.xml
.nb-gradle/ .nb-gradle/
...@@ -9,6 +9,7 @@ gtags.files ...@@ -9,6 +9,7 @@ gtags.files
GTAGS GTAGS
GRTAGS GRTAGS
GPATH GPATH
GSYMS
cscope.files cscope.files
cscope.out cscope.out
cscope.in.out cscope.in.out
......
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
# Icon must end with two \r # Icon must end with two \r
Icon Icon
# Thumbnails # Thumbnails
._* ._*
......
...@@ -17,3 +17,4 @@ cabal.sandbox.config ...@@ -17,3 +17,4 @@ cabal.sandbox.config
*.eventlog *.eventlog
.stack-work/ .stack-work/
cabal.project.local cabal.project.local
.HTF/
...@@ -52,6 +52,7 @@ ...@@ -52,6 +52,7 @@
/administrator/language/en-GB/en-GB.plg_content_contact.sys.ini /administrator/language/en-GB/en-GB.plg_content_contact.sys.ini
/administrator/language/en-GB/en-GB.plg_content_finder.ini /administrator/language/en-GB/en-GB.plg_content_finder.ini
/administrator/language/en-GB/en-GB.plg_content_finder.sys.ini /administrator/language/en-GB/en-GB.plg_content_finder.sys.ini
/administrator/language/en-GB/en-GB.plg_editors-xtd_module*
/administrator/language/en-GB/en-GB.plg_finder_categories.ini /administrator/language/en-GB/en-GB.plg_finder_categories.ini
/administrator/language/en-GB/en-GB.plg_finder_categories.sys.ini /administrator/language/en-GB/en-GB.plg_finder_categories.sys.ini
/administrator/language/en-GB/en-GB.plg_finder_contacts.ini /administrator/language/en-GB/en-GB.plg_finder_contacts.ini
...@@ -64,6 +65,10 @@ ...@@ -64,6 +65,10 @@
/administrator/language/en-GB/en-GB.plg_finder_tags.sys.ini /administrator/language/en-GB/en-GB.plg_finder_tags.sys.ini
/administrator/language/en-GB/en-GB.plg_finder_weblinks.ini /administrator/language/en-GB/en-GB.plg_finder_weblinks.ini
/administrator/language/en-GB/en-GB.plg_finder_weblinks.sys.ini /administrator/language/en-GB/en-GB.plg_finder_weblinks.sys.ini
/administrator/language/en-GB/en-GB.plg_installer_folderinstaller*
/administrator/language/en-GB/en-GB.plg_installer_packageinstaller*
/administrator/language/en-GB/en-GB.plg_installer_packageinstaller
/administrator/language/en-GB/en-GB.plg_installer_urlinstaller*
/administrator/language/en-GB/en-GB.plg_installer_webinstaller.ini /administrator/language/en-GB/en-GB.plg_installer_webinstaller.ini
/administrator/language/en-GB/en-GB.plg_installer_webinstaller.sys.ini /administrator/language/en-GB/en-GB.plg_installer_webinstaller.sys.ini
/administrator/language/en-GB/en-GB.plg_quickicon_joomlaupdate.ini /administrator/language/en-GB/en-GB.plg_quickicon_joomlaupdate.ini
...@@ -72,6 +77,8 @@ ...@@ -72,6 +77,8 @@
/administrator/language/en-GB/en-GB.plg_search_tags.sys.ini /administrator/language/en-GB/en-GB.plg_search_tags.sys.ini
/administrator/language/en-GB/en-GB.plg_system_languagecode.ini /administrator/language/en-GB/en-GB.plg_system_languagecode.ini
/administrator/language/en-GB/en-GB.plg_system_languagecode.sys.ini /administrator/language/en-GB/en-GB.plg_system_languagecode.sys.ini
/administrator/language/en-GB/en-GB.plg_system_stats*
/administrator/language/en-GB/en-GB.plg_system_updatenotification*
/administrator/language/en-GB/en-GB.plg_twofactorauth_totp.ini /administrator/language/en-GB/en-GB.plg_twofactorauth_totp.ini
/administrator/language/en-GB/en-GB.plg_twofactorauth_totp.sys.ini /administrator/language/en-GB/en-GB.plg_twofactorauth_totp.sys.ini
/administrator/language/en-GB/en-GB.plg_twofactorauth_yubikey.ini /administrator/language/en-GB/en-GB.plg_twofactorauth_yubikey.ini
...@@ -249,8 +256,10 @@ ...@@ -249,8 +256,10 @@
/administrator/language/en-GB/en-GB.tpl_hathor.sys.ini /administrator/language/en-GB/en-GB.tpl_hathor.sys.ini
/administrator/language/en-GB/en-GB.xml /administrator/language/en-GB/en-GB.xml
/administrator/language/en-GB/index.html /administrator/language/en-GB/index.html
/administrator/language/ru-RU/index.html
/administrator/language/overrides/* /administrator/language/overrides/*
/administrator/language/index.html /administrator/language/index.html
/administrator/logs/index.html
/administrator/manifests/* /administrator/manifests/*
/administrator/modules/mod_custom/* /administrator/modules/mod_custom/*
/administrator/modules/mod_feed/* /administrator/modules/mod_feed/*
...@@ -289,6 +298,7 @@ ...@@ -289,6 +298,7 @@
/components/com_finder/* /components/com_finder/*
/components/com_mailto/* /components/com_mailto/*
/components/com_media/* /components/com_media/*
/components/com_modules/*
/components/com_newsfeeds/* /components/com_newsfeeds/*
/components/com_search/* /components/com_search/*
/components/com_users/* /components/com_users/*
...@@ -407,6 +417,7 @@ ...@@ -407,6 +417,7 @@
/libraries/idna_convert/* /libraries/idna_convert/*
/libraries/joomla/* /libraries/joomla/*
/libraries/legacy/* /libraries/legacy/*
/libraries/php-encryption/*
/libraries/phpass/* /libraries/phpass/*
/libraries/phpmailer/* /libraries/phpmailer/*
/libraries/phputf8/* /libraries/phputf8/*
...@@ -431,9 +442,11 @@ ...@@ -431,9 +442,11 @@
/media/media/* /media/media/*
/media/mod_languages/* /media/mod_languages/*
/media/overrider/* /media/overrider/*
/media/plg_captcha_recaptcha/*
/media/plg_quickicon_extensionupdate/* /media/plg_quickicon_extensionupdate/*
/media/plg_quickicon_joomlaupdate/* /media/plg_quickicon_joomlaupdate/*
/media/plg_system_highlight/* /media/plg_system_highlight/*
/media/plg_system_stats/*
/media/system/* /media/system/*
/media/index.html /media/index.html
/modules/mod_articles_archive/* /modules/mod_articles_archive/*
...@@ -486,6 +499,7 @@ ...@@ -486,6 +499,7 @@
/plugins/editors/none/* /plugins/editors/none/*
/plugins/editors/tinymce/* /plugins/editors/tinymce/*
/plugins/editors/index.html /plugins/editors/index.html
/plugins/editors-xtd/module/*
/plugins/editors-xtd/article/* /plugins/editors-xtd/article/*
/plugins/editors-xtd/image/* /plugins/editors-xtd/image/*
/plugins/editors-xtd/pagebreak/* /plugins/editors-xtd/pagebreak/*
...@@ -523,6 +537,8 @@ ...@@ -523,6 +537,8 @@
/plugins/system/redirect/* /plugins/system/redirect/*
/plugins/system/remember/* /plugins/system/remember/*
/plugins/system/sef/* /plugins/system/sef/*
/plugins/system/stats/*
/plugins/system/updatenotification/*
/plugins/system/index.html /plugins/system/index.html
/plugins/twofactorauth/* /plugins/twofactorauth/*
/plugins/user/contactcreator/* /plugins/user/contactcreator/*
......
...@@ -34,5 +34,8 @@ jspm_packages ...@@ -34,5 +34,8 @@ jspm_packages
# Optional npm cache directory # Optional npm cache directory
.npm .npm
# Optional eslint cache
.eslintcache
# Optional REPL history # Optional REPL history
.node_repl_history .node_repl_history
...@@ -50,7 +50,9 @@ Carthage/Build ...@@ -50,7 +50,9 @@ Carthage/Build
# https://github.com/fastlane/fastlane/blob/master/fastlane/docs/Gitignore.md # https://github.com/fastlane/fastlane/blob/master/fastlane/docs/Gitignore.md
fastlane/report.xml fastlane/report.xml
fastlane/Preview.html
fastlane/screenshots fastlane/screenshots
fastlane/test_output
# Code Injection # Code Injection
# #
......
...@@ -79,6 +79,7 @@ celerybeat-schedule ...@@ -79,6 +79,7 @@ celerybeat-schedule
.env .env
# virtualenv # virtualenv
.venv/
venv/ venv/
ENV/ ENV/
......
...@@ -12,9 +12,11 @@ capybara-*.html ...@@ -12,9 +12,11 @@ capybara-*.html
rerun.txt rerun.txt
pickle-email-*.html pickle-email-*.html
# TODO Comment out these rules if you are OK with secrets being uploaded to the repo # TODO Comment out this rule if you are OK with secrets being uploaded to the repo
config/initializers/secret_token.rb config/initializers/secret_token.rb
config/secrets.yml
# Only include if you have production secrets in this file, which is no longer a Rails default
# config/secrets.yml
# dotenv # dotenv
# TODO Comment out this rule if environment variables can be committed # TODO Comment out this rule if environment variables can be committed
......
...@@ -251,3 +251,10 @@ paket-files/ ...@@ -251,3 +251,10 @@ paket-files/
# JetBrains Rider # JetBrains Rider
.idea/ .idea/
*.sln.iml *.sln.iml
# CodeRush
.cr/
# Python Tools for Visual Studio (PTVS)
__pycache__/
*.pyc
# Official docker image. # Official docker image.
image: docker:latest image: docker:latest
services:
- docker:dind
build: build:
stage: build stage: build
script: script:
- docker build -t test . - docker login -u "gitlab-ci-token" -p "$CI_BUILD_TOKEN" $CI_REGISTRY
- docker build --pull -t "$CI_REGISTRY_IMAGE:$CI_BUILD_REF_NAME" .
- docker push "$CI_REGISTRY_IMAGE:$CI_BUILD_REF_NAME"
...@@ -43,3 +43,12 @@ rails: ...@@ -43,3 +43,12 @@ rails:
- bundle exec rake db:migrate - bundle exec rake db:migrate
- bundle exec rake db:seed - bundle exec rake db:seed
- bundle exec rake test - bundle exec rake test
# This deploy job uses a simple deploy flow to Heroku, other providers, e.g. AWS Elastic Beanstalk
# are supported too: https://github.com/travis-ci/dpl
deploy:
type: deploy
environment: production
script:
- gem install dpl
- dpl --provider=heroku --app=$HEROKU_APP_NAME --api-key=$HEROKU_PRODUCTION_KEY
# Lifted from: https://about.gitlab.com/2016/03/10/setting-up-gitlab-ci-for-ios-projects/
# This file assumes an own GitLab CI runner, setup on an OS X system.
stages:
- build
- archive
build_project:
stage: build
script:
- xcodebuild clean -project ProjectName.xcodeproj -scheme SchemeName | xcpretty
- xcodebuild test -project ProjectName.xcodeproj -scheme SchemeName -destination 'platform=iOS Simulator,name=iPhone 6s,OS=9.2' | xcpretty -s
tags:
- ios_9-2
- xcode_7-2
- osx_10-11
archive_project:
stage: archive
script:
- xcodebuild clean archive -archivePath build/ProjectName -scheme SchemeName
- xcodebuild -exportArchive -exportFormat ipa -archivePath "build/ProjectName.xcarchive" -exportPath "build/ProjectName.ipa" -exportProvisioningProfile "ProvisioningProfileName"
only:
- master
artifacts:
paths:
- build/ProjectName.ipa
tags:
- ios_9-2
- xcode_7-2
- osx_10-11
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment