summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.flayignore1
-rw-r--r--.gitlab-ci.yml9
-rw-r--r--.haml-lint.yml103
-rw-r--r--.rubocop_todo.yml125
-rw-r--r--CHANGELOG39
-rw-r--r--CONTRIBUTING.md18
-rw-r--r--GITLAB_SHELL_VERSION2
-rw-r--r--Gemfile7
-rw-r--r--Gemfile.lock27
-rw-r--r--app/assets/stylesheets/framework/mobile.scss4
-rw-r--r--app/assets/stylesheets/pages/issuable.scss2
-rw-r--r--app/assets/stylesheets/pages/issues.scss9
-rw-r--r--app/controllers/concerns/creates_commit.rb3
-rw-r--r--app/controllers/projects/blob_controller.rb10
-rw-r--r--app/controllers/projects/merge_requests_controller.rb6
-rw-r--r--app/helpers/search_helper.rb31
-rw-r--r--app/models/blob.rb12
-rw-r--r--app/models/ci/build.rb11
-rw-r--r--app/models/member.rb33
-rw-r--r--app/models/merge_request.rb10
-rw-r--r--app/models/project.rb18
-rw-r--r--app/models/repository.rb35
-rw-r--r--app/services/ci/process_pipeline_service.rb6
-rw-r--r--app/services/projects/destroy_service.rb2
-rw-r--r--app/services/projects/housekeeping_service.rb12
-rw-r--r--app/views/admin/builds/_build.html.haml77
-rw-r--r--app/views/admin/builds/index.html.haml43
-rw-r--r--app/views/profiles/keys/index.html.haml1
-rw-r--r--app/views/projects/builds/_table.html.haml24
-rw-r--r--app/views/projects/builds/index.html.haml47
-rw-r--r--app/views/projects/ci/builds/_build.html.haml38
-rw-r--r--app/views/projects/issues/_merge_requests.html.haml2
-rw-r--r--app/views/projects/issues/_related_branches.html.haml2
-rw-r--r--app/views/projects/merge_requests/_discussion.html.haml2
-rw-r--r--app/views/projects/merge_requests/_show.html.haml31
-rw-r--r--app/views/projects/notes/_note.html.haml3
-rw-r--r--app/views/search/results/_blob.html.haml2
-rw-r--r--app/views/search/results/_wiki_blob.html.haml2
-rw-r--r--app/views/shared/builds/_tabs.html.haml24
-rw-r--r--config/initializers/metrics.rb3
-rw-r--r--config/initializers/mime_types.rb8
-rw-r--r--db/migrate/20160725104020_merge_request_diff_remove_uniq.rb20
-rw-r--r--db/migrate/20160913162434_remove_projects_pushes_since_gc.rb19
-rw-r--r--db/schema.rb3
-rw-r--r--doc/administration/container_registry.md4
-rw-r--r--doc/api/ci/builds.md9
-rw-r--r--doc/ci/variables/README.md6
-rw-r--r--doc/development/instrumentation.md15
-rw-r--r--doc/update/8.11-to-8.12.md2
-rw-r--r--doc/user/project/merge_requests.md3
-rw-r--r--doc/workflow/importing/import_projects_from_github.md1
-rw-r--r--lib/api/commit_statuses.rb54
-rw-r--r--lib/api/helpers.rb4
-rw-r--r--lib/banzai/filter/wiki_link_filter/rewriter.rb1
-rw-r--r--lib/ci/api/builds.rb2
-rw-r--r--lib/ci/api/helpers.rb8
-rw-r--r--lib/gitlab/backend/shell.rb2
-rw-r--r--lib/gitlab/checks/change_access.rb1
-rw-r--r--lib/gitlab/git/hook.rb12
-rw-r--r--lib/gitlab/github_import/base_formatter.rb5
-rw-r--r--lib/gitlab/github_import/comment_formatter.rb8
-rw-r--r--lib/gitlab/github_import/importer.rb13
-rw-r--r--lib/gitlab/github_import/issue_formatter.rb8
-rw-r--r--lib/gitlab/github_import/pull_request_formatter.rb8
-rw-r--r--lib/gitlab/github_import/release_formatter.rb23
-rw-r--r--lib/gitlab/popen.rb12
-rw-r--r--lib/gitlab/workhorse.rb2
-rw-r--r--lib/tasks/haml-lint.rake5
-rw-r--r--spec/controllers/projects_controller_spec.rb19
-rw-r--r--spec/factories/ci/runners.rb4
-rw-r--r--spec/factories/issues.rb4
-rw-r--r--spec/features/profiles/keys_spec.rb18
-rw-r--r--spec/features/projects_spec.rb8
-rw-r--r--spec/helpers/search_helper_spec.rb32
-rw-r--r--spec/lib/banzai/pipeline/wiki_pipeline_spec.rb7
-rw-r--r--spec/lib/gitlab/github_import/comment_formatter_spec.rb6
-rw-r--r--spec/lib/gitlab/github_import/importer_spec.rb30
-rw-r--r--spec/lib/gitlab/github_import/issue_formatter_spec.rb6
-rw-r--r--spec/lib/gitlab/github_import/pull_request_formatter_spec.rb6
-rw-r--r--spec/lib/gitlab/github_import/release_formatter_spec.rb54
-rw-r--r--spec/lib/gitlab/workhorse_spec.rb5
-rw-r--r--spec/models/blob_spec.rb20
-rw-r--r--spec/models/build_spec.rb28
-rw-r--r--spec/models/member_spec.rb42
-rw-r--r--spec/models/merge_request_spec.rb77
-rw-r--r--spec/models/project_spec.rb86
-rw-r--r--spec/models/repository_spec.rb26
-rw-r--r--spec/requests/api/commit_statuses_spec.rb39
-rw-r--r--spec/requests/api/issues_spec.rb3
-rw-r--r--spec/requests/ci/api/builds_spec.rb60
-rw-r--r--spec/services/projects/housekeeping_service_spec.rb29
-rw-r--r--vendor/gitignore/Global/NetBeans.gitignore1
-rw-r--r--vendor/gitignore/Global/Tags.gitignore1
-rw-r--r--vendor/gitignore/Global/macOS.gitignore (renamed from vendor/gitignore/Global/OSX.gitignore)3
-rw-r--r--vendor/gitignore/Haskell.gitignore1
-rw-r--r--vendor/gitignore/Joomla.gitignore16
-rw-r--r--vendor/gitignore/Node.gitignore3
-rw-r--r--vendor/gitignore/Objective-C.gitignore2
-rw-r--r--vendor/gitignore/Python.gitignore1
-rw-r--r--vendor/gitignore/Rails.gitignore6
-rw-r--r--vendor/gitignore/VisualStudio.gitignore7
-rw-r--r--vendor/gitlab-ci-yml/Docker.gitlab-ci.yml7
-rw-r--r--vendor/gitlab-ci-yml/Ruby.gitlab-ci.yml9
-rw-r--r--vendor/gitlab-ci-yml/Swift.gitlab-ci.yml30
104 files changed, 1288 insertions, 502 deletions
diff --git a/.flayignore b/.flayignore
index 9c9875d4f9e..f120de527bd 100644
--- a/.flayignore
+++ b/.flayignore
@@ -1 +1,2 @@
*.erb
+lib/gitlab/sanitizers/svg/whitelist.rb
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index f51d506f64a..b167fc74996 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -206,10 +206,15 @@ spinach 9 10 ruby21: *spinach-knapsack-ruby21
- bundle exec $CI_BUILD_NAME
rubocop: *exec
+rake haml_lint: *exec
rake scss_lint: *exec
rake brakeman: *exec
-rake flog: *exec
-rake flay: *exec
+rake flog:
+ <<: *exec
+ allow_failure: yes
+rake flay:
+ <<: *exec
+ allow_failure: yes
license_finder: *exec
rake downtime_check: *exec
diff --git a/.haml-lint.yml b/.haml-lint.yml
new file mode 100644
index 00000000000..da9a43d9c6d
--- /dev/null
+++ b/.haml-lint.yml
@@ -0,0 +1,103 @@
+# 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
diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml
index 20daf1619a7..87520c67dd5 100644
--- a/.rubocop_todo.yml
+++ b/.rubocop_todo.yml
@@ -1,21 +1,21 @@
# This configuration was generated by
# `rubocop --auto-gen-config --exclude-limit 0`
-# on 2016-07-13 12:36:08 -0600 using RuboCop version 0.41.2.
+# 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
# one by one as the offenses are removed from the code base.
# Note that changes in the inspected code, or installation of new
# versions of RuboCop, may require this file to be generated again.
-# Offense count: 154
+# Offense count: 158
Lint/AmbiguousRegexpLiteral:
Enabled: false
-# Offense count: 43
+# Offense count: 41
# Configuration parameters: AllowSafeAssignment.
Lint/AssignmentInCondition:
Enabled: false
-# Offense count: 14
+# Offense count: 16
Lint/HandleExceptions:
Enabled: false
@@ -23,28 +23,28 @@ Lint/HandleExceptions:
Lint/Loop:
Enabled: false
-# Offense count: 15
+# Offense count: 16
Lint/ShadowingOuterLocalVariable:
Enabled: false
-# Offense count: 3
+# Offense count: 6
# Cop supports --auto-correct.
Lint/StringConversionInInterpolation:
Enabled: false
-# Offense count: 44
+# Offense count: 49
# Cop supports --auto-correct.
# Configuration parameters: IgnoreEmptyBlocks, AllowUnusedKeywordArguments.
Lint/UnusedBlockArgument:
Enabled: false
-# Offense count: 129
+# Offense count: 144
# Cop supports --auto-correct.
# Configuration parameters: AllowUnusedKeywordArguments, IgnoreEmptyMethods.
Lint/UnusedMethodArgument:
Enabled: false
-# Offense count: 12
+# Offense count: 9
# Cop supports --auto-correct.
Performance/PushSplat:
Enabled: false
@@ -59,51 +59,51 @@ Performance/RedundantBlockCall:
Performance/RedundantMatch:
Enabled: false
-# Offense count: 24
+# Offense count: 27
# Cop supports --auto-correct.
# Configuration parameters: MaxKeyValuePairs.
Performance/RedundantMerge:
Enabled: false
-# Offense count: 60
+# Offense count: 61
Rails/OutputSafety:
Enabled: false
-# Offense count: 128
+# Offense count: 129
# Configuration parameters: EnforcedStyle, SupportedStyles.
# SupportedStyles: strict, flexible
Rails/TimeZone:
Enabled: false
-# Offense count: 12
+# Offense count: 15
# Cop supports --auto-correct.
# Configuration parameters: Include.
# Include: app/models/**/*.rb
Rails/Validation:
Enabled: false
-# Offense count: 217
+# Offense count: 273
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle, SupportedStyles, IndentationWidth.
# SupportedStyles: with_first_parameter, with_fixed_indentation
Style/AlignParameters:
Enabled: false
-# Offense count: 32
+# Offense count: 30
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle, SupportedStyles.
# SupportedStyles: always, conditionals
Style/AndOr:
Enabled: false
-# Offense count: 47
+# Offense count: 50
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle, SupportedStyles.
# SupportedStyles: percent_q, bare_percent
Style/BarePercentLiterals:
Enabled: false
-# Offense count: 258
+# Offense count: 289
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle, SupportedStyles.
# SupportedStyles: braces, no_braces, context_dependent
@@ -126,14 +126,14 @@ Style/ColonMethodCall:
Style/CommentAnnotation:
Enabled: false
-# Offense count: 34
+# Offense count: 33
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle, SupportedStyles, SingleLineConditionsOnly.
# SupportedStyles: assign_to_condition, assign_inside_condition
Style/ConditionalAssignment:
Enabled: false
-# Offense count: 789
+# Offense count: 881
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle, SupportedStyles.
# SupportedStyles: leading, trailing
@@ -144,11 +144,12 @@ Style/DotPosition:
Style/DoubleNegation:
Enabled: false
-# Offense count: 3
+# Offense count: 4
+# Cop supports --auto-correct.
Style/EachWithObject:
Enabled: false
-# Offense count: 30
+# Offense count: 25
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle, SupportedStyles.
# SupportedStyles: empty, nil, both
@@ -160,7 +161,7 @@ Style/EmptyElse:
Style/EmptyLiteral:
Enabled: false
-# Offense count: 123
+# Offense count: 135
# Cop supports --auto-correct.
# Configuration parameters: AllowForAlignment, ForceEqualSignAlignment.
Style/ExtraSpacing:
@@ -172,16 +173,16 @@ Style/ExtraSpacing:
Style/FormatString:
Enabled: false
-# Offense count: 48
+# Offense count: 51
# Configuration parameters: MinBodyLength.
Style/GuardClause:
Enabled: false
-# Offense count: 11
+# Offense count: 9
Style/IfInsideElse:
Enabled: false
-# Offense count: 177
+# Offense count: 174
# Cop supports --auto-correct.
# Configuration parameters: MaxLineLength.
Style/IfUnlessModifier:
@@ -194,7 +195,7 @@ Style/IfUnlessModifier:
Style/IndentArray:
Enabled: false
-# Offense count: 89
+# Offense count: 97
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle, SupportedStyles, IndentationWidth.
# SupportedStyles: special_inside_parentheses, consistent, align_braces
@@ -208,7 +209,7 @@ Style/IndentHash:
Style/Lambda:
Enabled: false
-# Offense count: 6
+# Offense count: 5
# Cop supports --auto-correct.
Style/LineEndConcatenation:
Enabled: false
@@ -218,17 +219,21 @@ Style/LineEndConcatenation:
Style/MethodCallParentheses:
Enabled: false
-# Offense count: 62
+# Offense count: 8
+Style/MethodMissing:
+ Enabled: false
+
+# Offense count: 85
# Cop supports --auto-correct.
Style/MutableConstant:
Enabled: false
-# Offense count: 10
+# Offense count: 8
# Cop supports --auto-correct.
Style/NestedParenthesizedCalls:
Enabled: false
-# Offense count: 12
+# Offense count: 13
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle, MinBodyLength, SupportedStyles.
# SupportedStyles: skip_modifier_ifs, always
@@ -242,12 +247,19 @@ Style/Next:
Style/NumericLiteralPrefix:
Enabled: false
+# Offense count: 64
+# Cop supports --auto-correct.
+# Configuration parameters: EnforcedStyle, SupportedStyles.
+# SupportedStyles: predicate, comparison
+Style/NumericPredicate:
+ Enabled: false
+
# Offense count: 29
# Cop supports --auto-correct.
Style/ParallelAssignment:
Enabled: false
-# Offense count: 208
+# Offense count: 264
# Cop supports --auto-correct.
# Configuration parameters: PreferredDelimiters.
Style/PercentLiteralDelimiters:
@@ -265,7 +277,7 @@ Style/PercentQLiterals:
Style/PerlBackrefs:
Enabled: false
-# Offense count: 32
+# Offense count: 35
# Configuration parameters: NamePrefix, NamePrefixBlacklist, NameWhitelist.
# NamePrefix: is_, has_, have_
# NamePrefixBlacklist: is_, has_, have_
@@ -273,7 +285,7 @@ Style/PerlBackrefs:
Style/PredicateName:
Enabled: false
-# Offense count: 28
+# Offense count: 27
# Cop supports --auto-correct.
Style/PreferredHashMethods:
Enabled: false
@@ -283,14 +295,14 @@ Style/PreferredHashMethods:
Style/Proc:
Enabled: false
-# Offense count: 20
+# Offense count: 22
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle, SupportedStyles.
# SupportedStyles: compact, exploded
Style/RaiseArgs:
Enabled: false
-# Offense count: 3
+# Offense count: 4
# Cop supports --auto-correct.
Style/RedundantBegin:
Enabled: false
@@ -300,29 +312,29 @@ Style/RedundantBegin:
Style/RedundantException:
Enabled: false
-# Offense count: 23
+# Offense count: 24
# Cop supports --auto-correct.
Style/RedundantFreeze:
Enabled: false
-# Offense count: 377
+# Offense count: 408
# Cop supports --auto-correct.
Style/RedundantSelf:
Enabled: false
-# Offense count: 94
+# Offense count: 93
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle, SupportedStyles, AllowInnerSlashes.
# SupportedStyles: slashes, percent_r, mixed
Style/RegexpLiteral:
Enabled: false
-# Offense count: 17
+# Offense count: 18
# Cop supports --auto-correct.
Style/RescueModifier:
Enabled: false
-# Offense count: 2
+# Offense count: 5
# Cop supports --auto-correct.
Style/SelfAssignment:
Enabled: false
@@ -339,42 +351,42 @@ Style/SingleLineBlockParams:
Style/SingleLineMethods:
Enabled: false
-# Offense count: 119
+# Offense count: 124
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle, SupportedStyles.
# SupportedStyles: space, no_space
Style/SpaceBeforeBlockBraces:
Enabled: false
-# Offense count: 11
+# Offense count: 10
# Cop supports --auto-correct.
# Configuration parameters: AllowForAlignment.
Style/SpaceBeforeFirstArg:
Enabled: false
-# Offense count: 130
+# Offense count: 141
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle, SupportedStyles, EnforcedStyleForEmptyBraces, SpaceBeforeBlockParameters.
# SupportedStyles: space, no_space
Style/SpaceInsideBlockBraces:
Enabled: false
-# Offense count: 98
+# Offense count: 96
# Cop supports --auto-correct.
Style/SpaceInsideBrackets:
Enabled: false
-# Offense count: 60
+# Offense count: 62
# Cop supports --auto-correct.
Style/SpaceInsideParens:
Enabled: false
-# Offense count: 5
+# Offense count: 7
# Cop supports --auto-correct.
Style/SpaceInsidePercentLiteralDelimiters:
Enabled: false
-# Offense count: 36
+# Offense count: 40
# Cop supports --auto-correct.
# Configuration parameters: SupportedStyles.
# SupportedStyles: use_perl_names, use_english_names
@@ -388,21 +400,28 @@ Style/SpecialGlobalVars:
Style/StringLiteralsInInterpolation:
Enabled: false
-# Offense count: 24
+# Offense count: 32
# Cop supports --auto-correct.
# Configuration parameters: IgnoredMethods.
# IgnoredMethods: respond_to, define_method
Style/SymbolProc:
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.
# Configuration parameters: EnforcedStyleForMultiline, SupportedStyles.
# SupportedStyles: comma, consistent_comma, no_comma
Style/TrailingCommaInArguments:
Enabled: false
-# Offense count: 113
+# Offense count: 102
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyleForMultiline, SupportedStyles.
# SupportedStyles: comma, consistent_comma, no_comma
@@ -415,7 +434,7 @@ Style/TrailingCommaInLiteral:
Style/TrailingUnderscoreVariable:
Enabled: false
-# Offense count: 90
+# Offense count: 76
# Cop supports --auto-correct.
Style/TrailingWhitespace:
Enabled: false
@@ -427,12 +446,12 @@ Style/TrailingWhitespace:
Style/TrivialAccessors:
Enabled: false
-# Offense count: 3
+# Offense count: 2
# Cop supports --auto-correct.
Style/UnlessElse:
Enabled: false
-# Offense count: 13
+# Offense count: 14
# Cop supports --auto-correct.
Style/UnneededInterpolation:
Enabled: false
diff --git a/CHANGELOG b/CHANGELOG
index 132122d460d..e410d73d1f6 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -2,24 +2,29 @@ Please view this file on the master branch, on stable branches it's out of date.
v 8.12.0 (unreleased)
- 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)
- Cleanup misalignments in Issue list view !6206
- Prune events older than 12 months. (ritave)
- Prepend blank line to `Closes` message on merge request linked to issue (lukehowell)
- 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.
- Make push events have equal vertical spacing.
- Add two-factor recovery endpoint to internal API !5510
- Pass the "Remember me" value to the U2F authentication form
- 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)
- Change logo animation to CSS (ClemMakesApps)
- 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 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)
- 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
- Reduce contributions calendar data payload (ClemMakesApps)
- Add `web_url` field to issue, merge request, and snippet API objects (Ben Boeckel)
@@ -76,6 +81,7 @@ v 8.12.0 (unreleased)
- Remove inconsistent font weight for sidebar's labels (ClemMakesApps)
- Align add button on repository view (ClemMakesApps)
- Fix contributions calendar month label truncation (ClemMakesApps)
+ - Import release note descriptions from GitHub (EspadaV8)
- Added tests for diff notes
- Add pipeline events to Slack integration !5525
- Add a button to download latest successful artifacts for branches and tags !5142
@@ -87,12 +93,14 @@ v 8.12.0 (unreleased)
- Fix repo title alignment (ClemMakesApps)
- Change update interval of contacted_at
- 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)
- Fix duplicate "me" in award emoji tooltip !5218 (jlogandavison)
- Order award emoji tooltips in order they were added (EspadaV8)
- 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
- Fix button missing type (ClemMakesApps)
+ - Gitlab::Checks is now instrumented
- 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)
- Load branches asynchronously in Cherry Pick and Revert dialogs.
@@ -111,6 +119,8 @@ v 8.12.0 (unreleased)
- Avoid conflict with admin labels when importing GitHub labels
- User can edit closed MR with deleted fork (Katarzyna Kobierska Ula Budziszewska) !5496
- 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
- Fix error on raw build trace download for old builds stored in database !4822
- Refactor the triggers page and documentation !6217
@@ -119,8 +129,23 @@ v 8.12.0 (unreleased)
- API for Ci Lint !5953 (Katarzyna Kobierska Urszula Budziszewska)
- 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
- Optimize branch lookups and force a repository reload for Repository#find_branch. !6087
@@ -325,6 +350,13 @@ v 8.11.0
- Update gitlab_git gem to 10.4.7
- 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
- Upgrade Hamlit to 2.6.1. !5873
- Upgrade Doorkeeper to 4.2.0. !5881
@@ -550,6 +582,9 @@ v 8.10.0
- Fix migration corrupting import data for old version upgrades
- 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
- Upgrade Doorkeeper to 4.2.0. !5881
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index c77dcd96a7d..549918284c1 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -91,19 +91,7 @@ This was inspired by [an article by Kent C. Dodds][medium-up-for-grabs].
## Implement design & UI elements
-### Design reference
-
-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.
+Please see the [UI Guide for building GitLab].
## Issue tracker
@@ -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"
[scss-styleguide]: doc/development/scss_styleguide.md "SCSS styleguide"
[newlines-styleguide]: doc/development/newlines_styleguide.md "Newlines styleguide"
-[gitlab-design]: https://gitlab.com/gitlab-org/gitlab-design
-[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/
+[UI Guide for building GitLab]: https://gitlab.com/gitlab-org/gitlab-ce/blob/master/doc/development/ui_guide.md
[license-finder-doc]: doc/development/licensing.md
diff --git a/GITLAB_SHELL_VERSION b/GITLAB_SHELL_VERSION
index 18091983f59..1545d966571 100644
--- a/GITLAB_SHELL_VERSION
+++ b/GITLAB_SHELL_VERSION
@@ -1 +1 @@
-3.4.0
+3.5.0
diff --git a/Gemfile b/Gemfile
index 81b7002027a..70d8495325f 100644
--- a/Gemfile
+++ b/Gemfile
@@ -26,7 +26,7 @@ gem 'omniauth-auth0', '~> 1.4.1'
gem 'omniauth-azure-oauth2', '~> 0.0.6'
gem 'omniauth-bitbucket', '~> 0.0.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-gitlab', '~> 1.0.0'
gem 'omniauth-google-oauth2', '~> 0.4.1'
@@ -53,7 +53,7 @@ gem 'browser', '~> 2.2'
# Extracting information from a git repository
# Provide access to Gitlab::Git library
-gem 'gitlab_git', '~> 10.6.3'
+gem 'gitlab_git', '~> 10.6.6'
# LDAP Auth
# GitLab fork with several improvements to original library. For full list of changes
@@ -295,9 +295,10 @@ group :development, :test do
gem 'spring-commands-spinach', '~> 1.1.0'
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 'scss_lint', '~> 0.47.0', require: false
+ gem 'haml_lint', '~> 0.18.2', require: false
gem 'simplecov', '0.12.0', require: false
gem 'flog', '~> 4.3.2', require: false
gem 'flay', '~> 2.6.1', require: false
diff --git a/Gemfile.lock b/Gemfile.lock
index c421713f6a1..e2b5a58d973 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -279,7 +279,7 @@ GEM
diff-lcs (~> 1.1)
mime-types (>= 1.16, < 3)
posix-spawn (~> 0.3)
- gitlab_git (10.6.3)
+ gitlab_git (10.6.6)
activesupport (~> 4.0)
charlock_holmes (~> 0.7.3)
github-linguist (~> 4.7.0)
@@ -322,11 +322,18 @@ GEM
grape-entity (0.4.8)
activesupport
multi_json (>= 1.3.2)
+ 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)
temple (~> 0.7.6)
thor
tilt
- hashie (3.4.3)
+ hashie (3.4.4)
health_check (2.1.0)
rails (>= 4.0)
hipchat (1.5.2)
@@ -394,7 +401,7 @@ GEM
mime-types (>= 1.16, < 4)
mail_room (0.8.0)
method_source (0.8.2)
- mime-types (2.99.2)
+ mime-types (2.99.3)
mimemagic (0.3.0)
mini_portile2 (2.1.0)
minitest (5.7.0)
@@ -437,7 +444,7 @@ GEM
addressable (~> 2.3)
nokogiri (~> 1.6.6)
omniauth (~> 1.2)
- omniauth-facebook (3.0.0)
+ omniauth-facebook (4.0.0)
omniauth-oauth2 (~> 1.2)
omniauth-github (1.1.2)
omniauth (~> 1.0)
@@ -612,7 +619,7 @@ GEM
rspec-retry (0.4.5)
rspec-core
rspec-support (3.5.0)
- rubocop (0.41.2)
+ rubocop (0.42.0)
parser (>= 2.3.1.1, < 3.0)
powerpack (~> 0.1)
rainbow (>= 1.99.1, < 3.0)
@@ -723,6 +730,7 @@ GEM
stringex (2.5.2)
sys-filesystem (1.1.6)
ffi
+ sysexits (1.2.0)
systemu (2.6.5)
task_list (1.0.2)
html-pipeline
@@ -754,7 +762,7 @@ GEM
unf (0.1.4)
unf_ext
unf_ext (0.0.7.2)
- unicode-display_width (1.1.0)
+ unicode-display_width (1.1.1)
unicorn (4.9.0)
kgio (~> 2.6)
rack
@@ -858,7 +866,7 @@ DEPENDENCIES
github-linguist (~> 4.7.0)
github-markup (~> 1.4)
gitlab-flowdock-git-hook (~> 1.0.1)
- gitlab_git (~> 10.6.3)
+ gitlab_git (~> 10.6.6)
gitlab_meta (= 7.0)
gitlab_omniauth-ldap (~> 1.2.1)
gollum-lib (~> 4.2)
@@ -866,6 +874,7 @@ DEPENDENCIES
gon (~> 6.1.0)
grape (~> 0.15.0)
grape-entity (~> 0.4.2)
+ haml_lint (~> 0.18.2)
hamlit (~> 2.6.1)
health_check (~> 2.1.0)
hipchat (~> 1.5.0)
@@ -900,7 +909,7 @@ DEPENDENCIES
omniauth-azure-oauth2 (~> 0.0.6)
omniauth-bitbucket (~> 0.0.2)
omniauth-cas3 (~> 1.1.2)
- omniauth-facebook (~> 3.0.0)
+ omniauth-facebook (~> 4.0.0)
omniauth-github (~> 1.1.1)
omniauth-gitlab (~> 1.0.0)
omniauth-google-oauth2 (~> 0.4.1)
@@ -935,7 +944,7 @@ DEPENDENCIES
rqrcode-rails3 (~> 0.1.7)
rspec-rails (~> 3.5.0)
rspec-retry (~> 0.4.5)
- rubocop (~> 0.41.2)
+ rubocop (~> 0.42.0)
rubocop-rspec (~> 1.5.0)
ruby-fogbugz (~> 0.2.1)
ruby-prof (~> 0.15.9)
diff --git a/app/assets/stylesheets/framework/mobile.scss b/app/assets/stylesheets/framework/mobile.scss
index 367c7d01944..76b93b23b95 100644
--- a/app/assets/stylesheets/framework/mobile.scss
+++ b/app/assets/stylesheets/framework/mobile.scss
@@ -79,10 +79,6 @@
padding-left: 15px !important;
}
- .issue-info, .merge-request-info {
- display: none;
- }
-
.nav-links, .nav-links {
li a {
font-size: 14px;
diff --git a/app/assets/stylesheets/pages/issuable.scss b/app/assets/stylesheets/pages/issuable.scss
index 63845e6b9ba..41079b6eeb5 100644
--- a/app/assets/stylesheets/pages/issuable.scss
+++ b/app/assets/stylesheets/pages/issuable.scss
@@ -206,7 +206,7 @@
padding-top: 0;
.block {
- width: $sidebar_collapsed_width - 1px;
+ width: $sidebar_collapsed_width - 2px;
margin-left: -19px;
padding: 15px 0 0;
border-bottom: none;
diff --git a/app/assets/stylesheets/pages/issues.scss b/app/assets/stylesheets/pages/issues.scss
index 7a26b7ad497..60a0d50ba73 100644
--- a/app/assets/stylesheets/pages/issues.scss
+++ b/app/assets/stylesheets/pages/issues.scss
@@ -37,6 +37,15 @@ form.edit-issue {
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 {
font-size: 16px;
font-weight: 600;
diff --git a/app/controllers/concerns/creates_commit.rb b/app/controllers/concerns/creates_commit.rb
index f2b8f297bc2..dacb5679dd3 100644
--- a/app/controllers/concerns/creates_commit.rb
+++ b/app/controllers/concerns/creates_commit.rb
@@ -7,8 +7,7 @@ module CreatesCommit
commit_params = @commit_params.merge(
source_project: @project,
source_branch: @ref,
- target_branch: @target_branch,
- previous_path: @previous_path
+ target_branch: @target_branch
)
result = service.new(@tree_edit_project, current_user, commit_params).execute
diff --git a/app/controllers/projects/blob_controller.rb b/app/controllers/projects/blob_controller.rb
index cdf9a04bacf..b78cc6585ba 100644
--- a/app/controllers/projects/blob_controller.rb
+++ b/app/controllers/projects/blob_controller.rb
@@ -38,12 +38,7 @@ class Projects::BlobController < Projects::ApplicationController
end
def update
- if params[:file_path].present?
- @previous_path = @path
- @path = params[:file_path]
- @commit_params[:file_path] = @path
- end
-
+ @path = params[:file_path] if params[:file_path].present?
after_edit_path =
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) +
@@ -143,6 +138,8 @@ class Projects::BlobController < Projects::ApplicationController
params[:file_name] = params[:file].original_filename
end
File.join(@path, params[:file_name])
+ elsif params[:file_path].present?
+ params[:file_path]
else
@path
end
@@ -155,6 +152,7 @@ class Projects::BlobController < Projects::ApplicationController
@commit_params = {
file_path: @file_path,
commit_message: params[:commit_message],
+ previous_path: @path,
file_content: params[:content],
file_content_encoding: params[:encoding],
last_commit_sha: params[:last_commit_sha]
diff --git a/app/controllers/projects/merge_requests_controller.rb b/app/controllers/projects/merge_requests_controller.rb
index 8895cb955bd..aa8645ba8cc 100644
--- a/app/controllers/projects/merge_requests_controller.rb
+++ b/app/controllers/projects/merge_requests_controller.rb
@@ -428,17 +428,11 @@ class Projects::MergeRequestsController < Projects::ApplicationController
end
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
# if there is no saved commits between source & target branch
if @merge_request.commits.blank?
# and if target branch doesn't exist
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
diff --git a/app/helpers/search_helper.rb b/app/helpers/search_helper.rb
index e523c46e879..8a7446b7cc7 100644
--- a/app/helpers/search_helper.rb
+++ b/app/helpers/search_helper.rb
@@ -30,6 +30,37 @@ module SearchHelper
"Showing #{from} - #{to} of #{count} #{scope.humanize(capitalize: false)} for \"#{term}\""
end
+ def parse_search_result(result)
+ ref = nil
+ filename = nil
+ basename = nil
+ startline = 0
+
+ result.each_line.each_with_index do |line, index|
+ if line =~ /^.*:.*:\d+:/
+ ref, filename, startline = line.split(':')
+ startline = startline.to_i - index
+ extname = Regexp.escape(File.extname(filename))
+ basename = filename.sub(/#{extname}$/, '')
+ break
+ end
+ end
+
+ data = ""
+
+ result.each_line do |line|
+ data << line.sub(ref, '').sub(filename, '').sub(/^:-\d+-/, '').sub(/^::\d+:/, '')
+ end
+
+ OpenStruct.new(
+ filename: filename,
+ basename: basename,
+ ref: ref,
+ startline: startline,
+ data: data
+ )
+ end
+
private
# Autocomplete results for various settings pages
diff --git a/app/models/blob.rb b/app/models/blob.rb
index 12cc5aaafba..ab92e820335 100644
--- a/app/models/blob.rb
+++ b/app/models/blob.rb
@@ -22,6 +22,18 @@ class Blob < SimpleDelegator
new(blob)
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?
size && size > 1.megabyte
end
diff --git a/app/models/ci/build.rb b/app/models/ci/build.rb
index 61052437318..fb16bc06d71 100644
--- a/app/models/ci/build.rb
+++ b/app/models/ci/build.rb
@@ -148,6 +148,7 @@ module Ci
variables += runner.predefined_variables if runner
variables += project.container_registry_variables
variables += yaml_variables
+ variables += user_variables
variables += project.secret_variables
variables += trigger_request.user_variables if trigger_request
variables
@@ -434,6 +435,15 @@ module Ci
read_attribute(:yaml_variables) || build_attributes_from_config[:yaml_variables] || []
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
def update_artifacts_size
@@ -469,6 +479,7 @@ module Ci
]
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_MANUAL', value: 'true', public: true } if manual?
variables
end
diff --git a/app/models/member.rb b/app/models/member.rb
index 64e0d33fb20..69406379948 100644
--- a/app/models/member.rb
+++ b/app/models/member.rb
@@ -28,17 +28,34 @@ class Member < ActiveRecord::Base
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 :non_invite, -> { where(invite_token: nil) }
scope :request, -> { where.not(requested_at: nil) }
- scope :has_access, -> { where('access_level > 0') }
-
- scope :guests, -> { where(access_level: GUEST) }
- scope :reporters, -> { where(access_level: REPORTER) }
- scope :developers, -> { where(access_level: DEVELOPER) }
- scope :masters, -> { where(access_level: MASTER) }
- scope :owners, -> { where(access_level: OWNER) }
- scope :owners_and_masters, -> { where(access_level: [OWNER, MASTER]) }
+
+ scope :has_access, -> { active.where('access_level > 0') }
+
+ scope :guests, -> { active.where(access_level: GUEST) }
+ scope :reporters, -> { active.where(access_level: REPORTER) }
+ scope :developers, -> { active.where(access_level: DEVELOPER) }
+ scope :masters, -> { active.where(access_level: 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? }
diff --git a/app/models/merge_request.rb b/app/models/merge_request.rb
index b0b1313f94a..f7d1253d957 100644
--- a/app/models/merge_request.rb
+++ b/app/models/merge_request.rb
@@ -316,6 +316,10 @@ class MergeRequest < ActiveRecord::Base
closed? && forked_source_project_missing?
end
+ def closed_without_source_project?
+ closed? && !source_project
+ end
+
def forked_source_project_missing?
return false unless for_fork?
return true unless source_project
@@ -323,6 +327,12 @@ class MergeRequest < ActiveRecord::Base
!source_project.forked_from?(target_project)
end
+ def reopenable?
+ return false if closed_without_fork? || closed_without_source_project? || merged?
+
+ closed?
+ end
+
def ensure_merge_request_diff
merge_request_diff || create_merge_request_diff
end
diff --git a/app/models/project.rb b/app/models/project.rb
index a6de2c48071..f3f3ffbbd28 100644
--- a/app/models/project.rb
+++ b/app/models/project.rb
@@ -58,7 +58,7 @@ class Project < ActiveRecord::Base
# Relations
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
has_one :last_event, -> {order 'events.created_at DESC'}, class_name: 'Event', foreign_key: 'project_id'
@@ -1288,8 +1288,24 @@ class Project < ActiveRecord::Base
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
+ def pushes_since_gc_redis_key
+ "projects/#{id}/pushes_since_gc"
+ end
+
# Prevents the creation of project_feature record for every project
def setup_project_feature
build_project_feature unless project_feature
diff --git a/app/models/repository.rb b/app/models/repository.rb
index 7b7090b8a73..c69e5a22a69 100644
--- a/app/models/repository.rb
+++ b/app/models/repository.rb
@@ -813,7 +813,7 @@ class Repository
update: true
}
- if previous_path
+ if previous_path && previous_path != path
options[:file][:previous_path] = previous_path
Gitlab::Git::Blob.rename(raw_repository, options)
else
@@ -990,37 +990,6 @@ class Repository
Gitlab::Popen.popen(args, path_to_repo).first.scrub.split(/^--$/)
end
- def parse_search_result(result)
- ref = nil
- filename = nil
- basename = nil
- startline = 0
-
- result.each_line.each_with_index do |line, index|
- if line =~ /^.*:.*:\d+:/
- ref, filename, startline = line.split(':')
- startline = startline.to_i - index
- extname = Regexp.escape(File.extname(filename))
- basename = filename.sub(/#{extname}$/, '')
- break
- end
- end
-
- data = ""
-
- result.each_line do |line|
- data << line.sub(ref, '').sub(filename, '').sub(/^:-\d+-/, '').sub(/^::\d+:/, '')
- end
-
- OpenStruct.new(
- filename: filename,
- basename: basename,
- ref: ref,
- startline: startline,
- data: data
- )
- end
-
def fetch_ref(source_path, source_ref, target_ref)
args = %W(#{Gitlab.config.git.bin_path} fetch --no-tags -f #{source_path} #{source_ref}:#{target_ref})
Gitlab::Popen.popen(args, path_to_repo)
@@ -1048,7 +1017,7 @@ class Repository
GitHooksService.new.execute(current_user, path_to_repo, oldrev, newrev, ref) do
update_ref!(ref, newrev, oldrev)
-
+
if was_empty || !target_branch
# If repo was empty expire cache
after_create if was_empty
diff --git a/app/services/ci/process_pipeline_service.rb b/app/services/ci/process_pipeline_service.rb
index de48a50774e..36c93dddadb 100644
--- a/app/services/ci/process_pipeline_service.rb
+++ b/app/services/ci/process_pipeline_service.rb
@@ -31,13 +31,13 @@ module Ci
current_status = status_for_prior_stages(index)
created_builds_in_stage(index).select do |build|
- process_build(build, current_status)
+ if HasStatus::COMPLETED_STATUSES.include?(current_status)
+ process_build(build, current_status)
+ end
end
end
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)
build.enqueue
true
diff --git a/app/services/projects/destroy_service.rb b/app/services/projects/destroy_service.rb
index 8a53f65aec1..a08c6fcd94b 100644
--- a/app/services/projects/destroy_service.rb
+++ b/app/services/projects/destroy_service.rb
@@ -27,6 +27,8 @@ module Projects
# Git data (e.g. a list of branch names).
flush_caches(project, wiki_path)
+ Projects::UnlinkForkService.new(project, current_user).execute
+
Project.transaction do
project.destroy!
diff --git a/app/services/projects/housekeeping_service.rb b/app/services/projects/housekeeping_service.rb
index 29b3981f49f..c3dfc8cfbe8 100644
--- a/app/services/projects/housekeeping_service.rb
+++ b/app/services/projects/housekeeping_service.rb
@@ -30,10 +30,8 @@ module Projects
end
def increment!
- if Gitlab::ExclusiveLease.new("project_housekeeping:increment!:#{@project.id}", timeout: 60).try_obtain
- Gitlab::Metrics.measure(:increment_pushes_since_gc) do
- update_pushes_since_gc(@project.pushes_since_gc + 1)
- end
+ Gitlab::Metrics.measure(:increment_pushes_since_gc) do
+ @project.increment_pushes_since_gc
end
end
@@ -43,14 +41,10 @@ module Projects
GitGarbageCollectWorker.perform_async(@project.id)
ensure
Gitlab::Metrics.measure(:reset_pushes_since_gc) do
- update_pushes_since_gc(0)
+ @project.reset_pushes_since_gc
end
end
- def update_pushes_since_gc(new_value)
- @project.update_column(:pushes_since_gc, new_value)
- end
-
def try_obtain_lease
Gitlab::Metrics.measure(:obtain_housekeeping_lease) do
lease = ::Gitlab::ExclusiveLease.new("project_housekeeping:#{@project.id}", timeout: LEASE_TIMEOUT)
diff --git a/app/views/admin/builds/_build.html.haml b/app/views/admin/builds/_build.html.haml
deleted file mode 100644
index f29d9c94441..00000000000
--- a/app/views/admin/builds/_build.html.haml
+++ /dev/null
@@ -1,77 +0,0 @@
-- 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
diff --git a/app/views/admin/builds/index.html.haml b/app/views/admin/builds/index.html.haml
index 3d77634d8fa..26a8846b609 100644
--- a/app/views/admin/builds/index.html.haml
+++ b/app/views/admin/builds/index.html.haml
@@ -4,26 +4,8 @@
%div{ class: container_class }
.top-area
- %ul.nav-links
- %li{class: ('active' if @scope.nil?)}
- = 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))
+ - build_path_proc = ->(scope) { admin_builds_path(scope: scope) }
+ = render "shared/builds/tabs", build_path_proc: build_path_proc, all_builds: @all_builds, scope: @scope
.nav-controls
- if @all_builds.running_or_pending.any?
@@ -33,23 +15,4 @@
#{(@scope || 'all').capitalize} builds
%ul.content-list.builds-content-list
- - if @builds.blank?
- %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'
+ = render "projects/builds/table", builds: @builds, admin: true
diff --git a/app/views/profiles/keys/index.html.haml b/app/views/profiles/keys/index.html.haml
index a42b3b8eb38..93187873501 100644
--- a/app/views/profiles/keys/index.html.haml
+++ b/app/views/profiles/keys/index.html.haml
@@ -1,4 +1,5 @@
- page_title "SSH Keys"
+= render 'profiles/head'
.row.prepend-top-default
.col-lg-3.profile-settings-sidebar
diff --git a/app/views/projects/builds/_table.html.haml b/app/views/projects/builds/_table.html.haml
new file mode 100644
index 00000000000..61eff73da26
--- /dev/null
+++ b/app/views/projects/builds/_table.html.haml
@@ -0,0 +1,24 @@
+- 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'
diff --git a/app/views/projects/builds/index.html.haml b/app/views/projects/builds/index.html.haml
index 2af625f69cd..5c60b7a7364 100644
--- a/app/views/projects/builds/index.html.haml
+++ b/app/views/projects/builds/index.html.haml
@@ -4,30 +4,8 @@
%div{ class: container_class }
.top-area
- %ul.nav-links
- %li{class: ('active' if @scope.nil?)}
- = 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))
+ - build_path_proc = ->(scope) { project_builds_path(@project, scope: scope) }
+ = render "shared/builds/tabs", build_path_proc: build_path_proc, all_builds: @all_builds, scope: @scope
.nav-controls
- if can?(current_user, :update_build, @project)
@@ -42,23 +20,4 @@
%span CI Lint
%ul.content-list.builds-content-list
- - if @builds.blank?
- %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'
+ = render "table", builds: @builds, project: @project
diff --git a/app/views/projects/ci/builds/_build.html.haml b/app/views/projects/ci/builds/_build.html.haml
index 73de8abe55b..75192c48188 100644
--- a/app/views/projects/ci/builds/_build.html.haml
+++ b/app/views/projects/ci/builds/_build.html.haml
@@ -1,3 +1,11 @@
+- 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
%td.status
- if can?(current_user, :read_build, build)
@@ -9,11 +17,11 @@
.branch-commit
- if can?(current_user, :read_build, build)
= link_to namespace_project_build_url(build.project.namespace, build.project, build) do
- %span ##{build.id}
+ %span.build-link ##{build.id}
- else
- %span ##{build.id}
+ %span.build-link ##{build.id}
- - if defined?(ref) && ref
+ - if ref
- if build.ref
.icon-container
= build.tag? ? icon('tag') : icon('code-fork')
@@ -23,12 +31,12 @@
.icon-container
= 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"
- if build.stuck?
= 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.')
.label-container
@@ -40,19 +48,24 @@
%span.label.label-info triggered
- if build.try(:allow_failure)
%span.label.label-danger allowed to fail
- - if defined?(retried) && retried
+ - if retried
%span.label.label-warning retried
- if build.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
- if build.try(:runner)
= runner_link(build.runner)
- else
.light none
- - if defined?(stage) && stage
+ - if stage
%td
= build.stage
@@ -64,13 +77,14 @@
%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
+ %td.coverage
+ - if coverage
- if build.try(:coverage)
#{build.coverage}%
@@ -83,10 +97,10 @@
- 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
= icon('remove', class: 'cred')
- - elsif defined?(allow_retry) && allow_retry
+ - elsif allow_retry
- 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
= 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
= custom_icon('icon_play')
diff --git a/app/views/projects/issues/_merge_requests.html.haml b/app/views/projects/issues/_merge_requests.html.haml
index d8075371853..31d3ec23276 100644
--- a/app/views/projects/issues/_merge_requests.html.haml
+++ b/app/views/projects/issues/_merge_requests.html.haml
@@ -1,7 +1,7 @@
- if @merge_requests.any?
%h2.merge-requests-title
= pluralize(@merge_requests.count, 'Related Merge Request')
- %ul.unstyled-list
+ %ul.unstyled-list.related-merge-requests
- has_any_ci = @merge_requests.any?(&:pipeline)
- @merge_requests.each do |merge_request|
%li
diff --git a/app/views/projects/issues/_related_branches.html.haml b/app/views/projects/issues/_related_branches.html.haml
index a8eeab3e55e..44683c8bcdb 100644
--- a/app/views/projects/issues/_related_branches.html.haml
+++ b/app/views/projects/issues/_related_branches.html.haml
@@ -1,7 +1,7 @@
- if @related_branches.any?
%h2.related-branches-title
= pluralize(@related_branches.count, 'Related Branch')
- %ul.unstyled-list
+ %ul.unstyled-list.related-merge-requests
- @related_branches.each do |branch|
%li
- target = @project.repository.find_branch(branch).target
diff --git a/app/views/projects/merge_requests/_discussion.html.haml b/app/views/projects/merge_requests/_discussion.html.haml
index d070979bcfe..3900b4f6f17 100644
--- a/app/views/projects/merge_requests/_discussion.html.haml
+++ b/app/views/projects/merge_requests/_discussion.html.haml
@@ -2,7 +2,7 @@
- if can?(current_user, :update_merge_request, @merge_request)
- 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"}
- - 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"}
%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}" } }
diff --git a/app/views/projects/merge_requests/_show.html.haml b/app/views/projects/merge_requests/_show.html.haml
index 4b4d418e8ec..d03ff9ec7e8 100644
--- a/app/views/projects/merge_requests/_show.html.haml
+++ b/app/views/projects/merge_requests/_show.html.haml
@@ -29,17 +29,19 @@
%ul.dropdown-menu.dropdown-menu-align-right
%li= link_to "Email Patches", merge_request_path(@merge_request, format: :patch)
%li= link_to "Plain Diff", merge_request_path(@merge_request, format: :diff)
- .normal
- %span Request to merge
- %span.label-branch= source_branch_with_namespace(@merge_request)
- %span into
- %span.label-branch
- = link_to @merge_request.target_branch, namespace_project_commits_path(@project.namespace, @project, @merge_request.target_branch)
- - if @merge_request.open? && @merge_request.diverged_from_target_branch?
- %span (#{pluralize(@merge_request.diverged_commits_count, 'commit')} behind)
+ - unless @merge_request.closed_without_fork?
+ .normal
+ %span Request to merge
+ %span.label-branch= source_branch_with_namespace(@merge_request)
+ %span into
+ %span.label-branch
+ = link_to @merge_request.target_branch, namespace_project_commits_path(@project.namespace, @project, @merge_request.target_branch)
+ - if @merge_request.open? && @merge_request.diverged_from_target_branch?
+ %span (#{pluralize(@merge_request.diverged_commits_count, 'commit')} behind)
- = render "projects/merge_requests/show/how_to_merge"
- = render "projects/merge_requests/widget/show.html.haml"
+ - unless @merge_request.closed_without_source_project?
+ = render "projects/merge_requests/show/how_to_merge"
+ = render "projects/merge_requests/widget/show.html.haml"
- if @merge_request.source_branch_exists? && @merge_request.mergeable? && @merge_request.can_be_merged_by?(current_user)
.light.prepend-top-default.append-bottom-default
@@ -53,10 +55,11 @@
= link_to namespace_project_merge_request_path(@project.namespace, @project, @merge_request), data: { target: 'div#notes', action: 'notes', toggle: 'tab' } do
Discussion
%span.badge= @merge_request.mr_and_commit_notes.user.count
- %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
- Commits
- %span.badge= @commits_count
+ - unless @merge_request.closed_without_source_project?
+ %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
+ Commits
+ %span.badge= @commits_count
- if @pipeline
%li.pipelines-tab
= link_to pipelines_namespace_project_merge_request_path(@project.namespace, @project, @merge_request), data: { target: '#pipelines', action: 'pipelines', toggle: 'tab' } do
diff --git a/app/views/projects/notes/_note.html.haml b/app/views/projects/notes/_note.html.haml
index 7c82177f9ea..9ec17cf6e76 100644
--- a/app/views/projects/notes/_note.html.haml
+++ b/app/views/projects/notes/_note.html.haml
@@ -1,6 +1,5 @@
- return unless note.author
- return if note.cross_reference_not_visible_for?(current_user)
-- can_resolve = can?(current_user, :resolve_note, 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} }
@@ -24,6 +23,8 @@
%span.note-role.hidden-xs= access
- if note.resolvable?
+ - can_resolve = can?(current_user, :resolve_note, note)
+
%resolve-btn{ ":namespace-path" => "'#{note.project.namespace.path}'",
":project-path" => "'#{note.project.path}'",
":discussion-id" => "'#{note.discussion_id}'",
diff --git a/app/views/search/results/_blob.html.haml b/app/views/search/results/_blob.html.haml
index 290743feb4a..6f0a0ea36ec 100644
--- a/app/views/search/results/_blob.html.haml
+++ b/app/views/search/results/_blob.html.haml
@@ -1,4 +1,4 @@
-- blob = @project.repository.parse_search_result(blob)
+- blob = parse_search_result(blob)
.blob-result
.file-holder
.file-title
diff --git a/app/views/search/results/_wiki_blob.html.haml b/app/views/search/results/_wiki_blob.html.haml
index 235106c4f74..648d0bd76cb 100644
--- a/app/views/search/results/_wiki_blob.html.haml
+++ b/app/views/search/results/_wiki_blob.html.haml
@@ -1,4 +1,4 @@
-- wiki_blob = @project.repository.parse_search_result(wiki_blob)
+- wiki_blob = parse_search_result(wiki_blob)
.blob-result
.file-holder
.file-title
diff --git a/app/views/shared/builds/_tabs.html.haml b/app/views/shared/builds/_tabs.html.haml
new file mode 100644
index 00000000000..60353aee7f1
--- /dev/null
+++ b/app/views/shared/builds/_tabs.html.haml
@@ -0,0 +1,24 @@
+%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))
diff --git a/config/initializers/metrics.rb b/config/initializers/metrics.rb
index 52522e099e7..be22085b0df 100644
--- a/config/initializers/metrics.rb
+++ b/config/initializers/metrics.rb
@@ -68,7 +68,8 @@ if Gitlab::Metrics.enabled?
['app', 'mailers', 'emails'] => ['app', 'mailers'],
['app', 'services', '**'] => ['app', 'services'],
['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)|
diff --git a/config/initializers/mime_types.rb b/config/initializers/mime_types.rb
index f498732feca..5e3e4c966cb 100644
--- a/config/initializers/mime_types.rb
+++ b/config/initializers/mime_types.rb
@@ -13,9 +13,5 @@ Mime::Type.register "video/mp4", :mp4, [], [:m4v, :mov]
Mime::Type.register "video/webm", :webm
Mime::Type.register "video/ogg", :ogv
-middlewares = Gitlab::Application.config.middleware
-middlewares.swap(ActionDispatch::ParamsParser, ActionDispatch::ParamsParser, {
- Mime::Type.lookup('application/vnd.git-lfs+json') => lambda do |body|
- ActiveSupport::JSON.decode(body)
- end
-})
+Mime::Type.unregister :json
+Mime::Type.register 'application/json', :json, %w(application/vnd.git-lfs+json application/json)
diff --git a/db/migrate/20160725104020_merge_request_diff_remove_uniq.rb b/db/migrate/20160725104020_merge_request_diff_remove_uniq.rb
index c8cbd2718ff..75a3eb15124 100644
--- a/db/migrate/20160725104020_merge_request_diff_remove_uniq.rb
+++ b/db/migrate/20160725104020_merge_request_diff_remove_uniq.rb
@@ -8,14 +8,28 @@ class MergeRequestDiffRemoveUniq < ActiveRecord::Migration
DOWNTIME = false
def up
- if index_exists?(:merge_request_diffs, :merge_request_id)
- remove_index :merge_request_diffs, :merge_request_id
+ constraint_name = 'merge_request_diffs_merge_request_id_key'
+
+ transaction do
+ if index_exists?(: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
def down
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
+
+ def constraint_exists?(name)
+ indexes(:merge_request_diffs).map(&:name).include?(name)
+ end
end
diff --git a/db/migrate/20160913162434_remove_projects_pushes_since_gc.rb b/db/migrate/20160913162434_remove_projects_pushes_since_gc.rb
new file mode 100644
index 00000000000..c5b8c35e961
--- /dev/null
+++ b/db/migrate/20160913162434_remove_projects_pushes_since_gc.rb
@@ -0,0 +1,19 @@
+# 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
diff --git a/db/schema.rb b/db/schema.rb
index 5c283141084..61873e38113 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -11,7 +11,7 @@
#
# It's strongly recommended that you check this file into your version control system.
-ActiveRecord::Schema.define(version: 20160902122721) do
+ActiveRecord::Schema.define(version: 20160913162434) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
@@ -824,7 +824,6 @@ ActiveRecord::Schema.define(version: 20160902122721) do
t.integer "build_timeout", default: 3600, null: false
t.boolean "pending_delete", default: false
t.boolean "public_builds", default: true, null: false
- t.integer "pushes_since_gc", default: 0
t.boolean "last_repository_check_failed"
t.datetime "last_repository_check_at"
t.boolean "container_registry_enabled"
diff --git a/doc/administration/container_registry.md b/doc/administration/container_registry.md
index 28c4c7c86ca..c5611e2a121 100644
--- a/doc/administration/container_registry.md
+++ b/doc/administration/container_registry.md
@@ -406,7 +406,8 @@ To configure the storage driver in Omnibus:
's3' => {
'accesskey' => 's3-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:
accesskey: 'AKIAKIAKI'
secretkey: 'secret123'
bucket: 'gitlab-registry-bucket-AKIAKIAKI'
+ region: 'your-s3-region'
cache:
blobdescriptor: inmemory
delete:
diff --git a/doc/api/ci/builds.md b/doc/api/ci/builds.md
index 2a71b087f19..b6d79706a84 100644
--- a/doc/api/ci/builds.md
+++ b/doc/api/ci/builds.md
@@ -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"
```
+**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
```
diff --git a/doc/ci/variables/README.md b/doc/ci/variables/README.md
index c32831d3aaa..6a971c3ae87 100644
--- a/doc/ci/variables/README.md
+++ b/doc/ci/variables/README.md
@@ -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_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_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_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 |
@@ -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_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 |
+| **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.**
@@ -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_NAME="spec:other"
export CI_BUILD_STAGE="test"
+export CI_BUILD_MANUAL="true"
export CI_BUILD_TRIGGERED="true"
export CI_BUILD_TOKEN="abcde-1234ABCD5678ef"
export CI_PIPELINE_ID="1000"
@@ -78,6 +82,8 @@ export CI_SERVER="yes"
export CI_SERVER_NAME="GitLab"
export CI_SERVER_REVISION="70606bf"
export CI_SERVER_VERSION="8.9.0"
+export GITLAB_USER_ID="42"
+export GITLAB_USER_EMAIL="alexzander@sporer.com"
```
### YAML-defined variables
diff --git a/doc/development/instrumentation.md b/doc/development/instrumentation.md
index c2272ab0a2b..105e2f1242a 100644
--- a/doc/development/instrumentation.md
+++ b/doc/development/instrumentation.md
@@ -137,3 +137,18 @@ end
```
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`.
diff --git a/doc/update/8.11-to-8.12.md b/doc/update/8.11-to-8.12.md
index 011c2b0e969..8017c36587e 100644
--- a/doc/update/8.11-to-8.12.md
+++ b/doc/update/8.11-to-8.12.md
@@ -70,7 +70,7 @@ sudo -u git -H git checkout 8-12-stable-ee
```bash
cd /home/git/gitlab-shell
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
diff --git a/doc/user/project/merge_requests.md b/doc/user/project/merge_requests.md
index f79535d1542..5af9a5d049c 100644
--- a/doc/user/project/merge_requests.md
+++ b/doc/user/project/merge_requests.md
@@ -93,6 +93,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
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
Add the following alias to your `~/.gitconfig`:
diff --git a/doc/workflow/importing/import_projects_from_github.md b/doc/workflow/importing/import_projects_from_github.md
index 306caabf6e6..370d885d366 100644
--- a/doc/workflow/importing/import_projects_from_github.md
+++ b/doc/workflow/importing/import_projects_from_github.md
@@ -15,6 +15,7 @@ At its current state, GitHub importer can import:
- the wiki pages (introduced in GitLab 8.4)
- the milestones (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.
diff --git a/lib/api/commit_statuses.rb b/lib/api/commit_statuses.rb
index 5e3c9563703..dfbdd597d29 100644
--- a/lib/api/commit_statuses.rb
+++ b/lib/api/commit_statuses.rb
@@ -37,7 +37,7 @@ module API
# id (required) - The ID of a project
# sha (required) - The commit hash
# 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
# 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"
@@ -46,7 +46,7 @@ module API
post ':id/statuses/:sha' do
authorize! :create_commit_status, user_project
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])
not_found! 'Commit' unless commit
@@ -58,36 +58,38 @@ module API
# the first found branch on that commit
ref = params[:ref]
- unless ref
- branches = @project.repository.branch_names_contains(commit.sha)
- not_found! 'References for commit' if branches.none?
- ref = branches.first
- end
+ ref ||= @project.repository.branch_names_contains(commit.sha).first
+ not_found! 'References for commit' unless ref
+
+ name = params[:name] || params[:context] || 'default'
pipeline = @project.ensure_pipeline(ref, commit.sha, current_user)
- name = params[:name] || params[:context]
- status = GenericCommitStatus.running_or_pending.find_by(pipeline: pipeline, name: name, ref: params[:ref])
- status ||= GenericCommitStatus.new(project: @project, pipeline: pipeline, user: current_user)
- status.update(attrs)
+ status = GenericCommitStatus.running_or_pending.find_or_initialize_by(
+ project: @project, pipeline: pipeline,
+ user: current_user, name: name, ref: ref)
+ status.attributes = attrs
- case params[:state].to_s
- when 'running'
- status.run
- when 'success'
- status.success
- when 'failed'
- status.drop
- when 'canceled'
- status.cancel
- else
- status.status = params[:state].to_s
- end
+ begin
+ case params[:state].to_s
+ when 'pending'
+ status.enqueue!
+ when 'running'
+ status.enqueue
+ status.run!
+ when 'success'
+ status.success!
+ when 'failed'
+ status.drop!
+ when 'canceled'
+ status.cancel!
+ else
+ render_api_error!('invalid state', 400)
+ end
- if status.save
present status, with: Entities::CommitStatus
- else
- render_validation_error!(status)
+ rescue StateMachines::InvalidTransition => e
+ render_api_error!(e.message, 400)
end
end
end
diff --git a/lib/api/helpers.rb b/lib/api/helpers.rb
index 6a20ba95a79..150875ed4f0 100644
--- a/lib/api/helpers.rb
+++ b/lib/api/helpers.rb
@@ -269,6 +269,10 @@ module API
render_api_error!('304 Not Modified', 304)
end
+ def no_content!
+ render_api_error!('204 No Content', 204)
+ end
+
def render_validation_error!(model)
if model.errors.any?
render_api_error!(model.errors.messages || '400 Bad Request', 400)
diff --git a/lib/banzai/filter/wiki_link_filter/rewriter.rb b/lib/banzai/filter/wiki_link_filter/rewriter.rb
index 2e2c8da311e..e7a1ec8457d 100644
--- a/lib/banzai/filter/wiki_link_filter/rewriter.rb
+++ b/lib/banzai/filter/wiki_link_filter/rewriter.rb
@@ -31,6 +31,7 @@ module Banzai
def apply_relative_link_rules!
if @uri.relative? && @uri.path.present?
link = ::File.join(@wiki_base_path, @uri.path)
+ link = "#{link}##{@uri.fragment}" if @uri.fragment
@uri = Addressable::URI.parse(link)
end
end
diff --git a/lib/ci/api/builds.rb b/lib/ci/api/builds.rb
index 54db63d4628..59f85416ee5 100644
--- a/lib/ci/api/builds.rb
+++ b/lib/ci/api/builds.rb
@@ -27,7 +27,7 @@ module Ci
else
Gitlab::Metrics.add_event(:build_not_found)
- not_found!
+ build_not_found!
end
end
diff --git a/lib/ci/api/helpers.rb b/lib/ci/api/helpers.rb
index bcabf7a21b2..ba80c89df78 100644
--- a/lib/ci/api/helpers.rb
+++ b/lib/ci/api/helpers.rb
@@ -32,6 +32,14 @@ module Ci
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
@runner ||= Runner.find_by_token(params[:token].to_s)
end
diff --git a/lib/gitlab/backend/shell.rb b/lib/gitlab/backend/shell.rb
index 839a4fa30d5..c412249a01e 100644
--- a/lib/gitlab/backend/shell.rb
+++ b/lib/gitlab/backend/shell.rb
@@ -195,7 +195,7 @@ module Gitlab
# Create (if necessary) and link the secret token file
def generate_and_link_secret_token
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.
token = SecureRandom.hex(16)
File.write(secret_file, token)
diff --git a/lib/gitlab/checks/change_access.rb b/lib/gitlab/checks/change_access.rb
index 4b32eb966aa..cb1065223d4 100644
--- a/lib/gitlab/checks/change_access.rb
+++ b/lib/gitlab/checks/change_access.rb
@@ -23,6 +23,7 @@ module Gitlab
protected
def protected_branch_checks
+ return unless @branch_name
return unless project.protected_branch?(@branch_name)
if forced_push? && user_access.cannot_do_action?(:force_push_code_to_protected_branches)
diff --git a/lib/gitlab/git/hook.rb b/lib/gitlab/git/hook.rb
index 9b681e636c7..bd90d24a2ec 100644
--- a/lib/gitlab/git/hook.rb
+++ b/lib/gitlab/git/hook.rb
@@ -17,11 +17,13 @@ module Gitlab
def trigger(gl_id, oldrev, newrev, ref)
return [true, nil] unless exists?
- case name
- when "pre-receive", "post-receive"
- call_receive_hook(gl_id, oldrev, newrev, ref)
- when "update"
- call_update_hook(gl_id, oldrev, newrev, ref)
+ Bundler.with_clean_env do
+ case name
+ when "pre-receive", "post-receive"
+ call_receive_hook(gl_id, oldrev, newrev, ref)
+ when "update"
+ call_update_hook(gl_id, oldrev, newrev, ref)
+ end
end
end
diff --git a/lib/gitlab/github_import/base_formatter.rb b/lib/gitlab/github_import/base_formatter.rb
index d546e102c63..8cacf4f4925 100644
--- a/lib/gitlab/github_import/base_formatter.rb
+++ b/lib/gitlab/github_import/base_formatter.rb
@@ -20,6 +20,11 @@ module Gitlab
find_by("identities.extern_uid = ? AND identities.provider = 'github'", github_id.to_s).
try(:id)
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
diff --git a/lib/gitlab/github_import/comment_formatter.rb b/lib/gitlab/github_import/comment_formatter.rb
index 1c7c1a73c77..2bddcde2b7c 100644
--- a/lib/gitlab/github_import/comment_formatter.rb
+++ b/lib/gitlab/github_import/comment_formatter.rb
@@ -21,7 +21,7 @@ module Gitlab
end
def author_id
- gitlab_user_id(raw_data.user.id) || project.creator_id
+ gitlab_author_id || project.creator_id
end
def body
@@ -52,7 +52,11 @@ module Gitlab
end
def note
- formatter.author_line(author) + body
+ if gitlab_author_id
+ body
+ else
+ formatter.author_line(author) + body
+ end
end
def type
diff --git a/lib/gitlab/github_import/importer.rb b/lib/gitlab/github_import/importer.rb
index 0388c58f811..d35ee2a1c65 100644
--- a/lib/gitlab/github_import/importer.rb
+++ b/lib/gitlab/github_import/importer.rb
@@ -24,6 +24,7 @@ module Gitlab
import_issues
import_pull_requests
import_wiki
+ import_releases
handle_errors
true
@@ -177,6 +178,18 @@ module Gitlab
errors << { type: :wiki, errors: e.message }
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
diff --git a/lib/gitlab/github_import/issue_formatter.rb b/lib/gitlab/github_import/issue_formatter.rb
index ad4f1d8ae99..77621de9f4c 100644
--- a/lib/gitlab/github_import/issue_formatter.rb
+++ b/lib/gitlab/github_import/issue_formatter.rb
@@ -49,7 +49,7 @@ module Gitlab
end
def author_id
- gitlab_user_id(raw_data.user.id) || project.creator_id
+ gitlab_author_id || project.creator_id
end
def body
@@ -57,7 +57,11 @@ module Gitlab
end
def description
- @formatter.author_line(author) + body
+ if gitlab_author_id
+ body
+ else
+ formatter.author_line(author) + body
+ end
end
def milestone
diff --git a/lib/gitlab/github_import/pull_request_formatter.rb b/lib/gitlab/github_import/pull_request_formatter.rb
index 87e031b27f8..1408683100f 100644
--- a/lib/gitlab/github_import/pull_request_formatter.rb
+++ b/lib/gitlab/github_import/pull_request_formatter.rb
@@ -77,7 +77,7 @@ module Gitlab
end
def author_id
- gitlab_user_id(raw_data.user.id) || project.creator_id
+ gitlab_author_id || project.creator_id
end
def body
@@ -85,7 +85,11 @@ module Gitlab
end
def description
- formatter.author_line(author) + body
+ if gitlab_author_id
+ body
+ else
+ formatter.author_line(author) + body
+ end
end
def milestone
diff --git a/lib/gitlab/github_import/release_formatter.rb b/lib/gitlab/github_import/release_formatter.rb
new file mode 100644
index 00000000000..73d643b00ad
--- /dev/null
+++ b/lib/gitlab/github_import/release_formatter.rb
@@ -0,0 +1,23 @@
+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
diff --git a/lib/gitlab/popen.rb b/lib/gitlab/popen.rb
index a0fd41161a5..cc74bb29087 100644
--- a/lib/gitlab/popen.rb
+++ b/lib/gitlab/popen.rb
@@ -18,18 +18,18 @@ module Gitlab
FileUtils.mkdir_p(path)
end
- @cmd_output = ""
- @cmd_status = 0
+ cmd_output = ""
+ cmd_status = 0
Open3.popen3(vars, *cmd, options) do |stdin, stdout, stderr, wait_thr|
yield(stdin) if block_given?
stdin.close
- @cmd_output << stdout.read
- @cmd_output << stderr.read
- @cmd_status = wait_thr.value.exitstatus
+ cmd_output << stdout.read
+ cmd_output << stderr.read
+ cmd_status = wait_thr.value.exitstatus
end
- [@cmd_output, @cmd_status]
+ [cmd_output, cmd_status]
end
end
end
diff --git a/lib/gitlab/workhorse.rb b/lib/gitlab/workhorse.rb
index efe4aeb399d..60aae541d46 100644
--- a/lib/gitlab/workhorse.rb
+++ b/lib/gitlab/workhorse.rb
@@ -102,7 +102,7 @@ module Gitlab
def secret
@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
bytes
end
diff --git a/lib/tasks/haml-lint.rake b/lib/tasks/haml-lint.rake
new file mode 100644
index 00000000000..609dfaa48e3
--- /dev/null
+++ b/lib/tasks/haml-lint.rake
@@ -0,0 +1,5 @@
+unless Rails.env.production?
+ require 'haml_lint/rake_task'
+
+ HamlLint::RakeTask.new
+end
diff --git a/spec/controllers/projects_controller_spec.rb b/spec/controllers/projects_controller_spec.rb
index ffe0641ddd7..b0f740f48f7 100644
--- a/spec/controllers/projects_controller_spec.rb
+++ b/spec/controllers/projects_controller_spec.rb
@@ -181,6 +181,25 @@ describe ProjectsController do
expect(response).to have_http_status(302)
expect(response).to redirect_to(dashboard_projects_path)
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
describe "POST #toggle_star" do
diff --git a/spec/factories/ci/runners.rb b/spec/factories/ci/runners.rb
index 5b645fab32e..45eaebb2576 100644
--- a/spec/factories/ci/runners.rb
+++ b/spec/factories/ci/runners.rb
@@ -30,5 +30,9 @@ FactoryGirl.define do
trait :shared do
is_shared true
end
+
+ trait :inactive do
+ active false
+ end
end
end
diff --git a/spec/factories/issues.rb b/spec/factories/issues.rb
index 2c0a2dd94ca..2b4670be468 100644
--- a/spec/factories/issues.rb
+++ b/spec/factories/issues.rb
@@ -1,4 +1,8 @@
FactoryGirl.define do
+ sequence :issue_created_at do |n|
+ 4.hours.ago + ( 2 * n ).seconds
+ end
+
factory :issue do
title
author
diff --git a/spec/features/profiles/keys_spec.rb b/spec/features/profiles/keys_spec.rb
new file mode 100644
index 00000000000..3b20d38c520
--- /dev/null
+++ b/spec/features/profiles/keys_spec.rb
@@ -0,0 +1,18 @@
+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
diff --git a/spec/features/projects_spec.rb b/spec/features/projects_spec.rb
index e00d85904d5..2242cb6236a 100644
--- a/spec/features/projects_spec.rb
+++ b/spec/features/projects_spec.rb
@@ -57,7 +57,7 @@ feature 'Project', feature: true do
describe 'removal', js: true do
let(:user) { create(:user) }
- let(:project) { create(:project, namespace: user.namespace) }
+ let(:project) { create(:project, namespace: user.namespace, name: 'project1') }
before do
login_with(user)
@@ -65,8 +65,12 @@ feature 'Project', feature: true do
visit edit_namespace_project_path(project.namespace, project)
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(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
diff --git a/spec/helpers/search_helper_spec.rb b/spec/helpers/search_helper_spec.rb
index 4b2ca3514f8..c5b5aa8c445 100644
--- a/spec/helpers/search_helper_spec.rb
+++ b/spec/helpers/search_helper_spec.rb
@@ -6,6 +6,38 @@ describe SearchHelper do
str
end
+ describe 'parsing result' do
+ let(:project) { create(:project) }
+ let(:repository) { project.repository }
+ let(:results) { repository.search_files('feature', 'master') }
+ let(:search_result) { results.first }
+
+ subject { helper.parse_search_result(search_result) }
+
+ it "returns a valid OpenStruct object" do
+ is_expected.to be_an OpenStruct
+ expect(subject.filename).to eq('CHANGELOG')
+ expect(subject.basename).to eq('CHANGELOG')
+ expect(subject.ref).to eq('master')
+ expect(subject.startline).to eq(186)
+ expect(subject.data.lines[2]).to eq(" - Feature: Replace teams with group membership\n")
+ end
+
+ context "when filename has extension" do
+ let(:search_result) { "master:CONTRIBUTE.md:5:- [Contribute to GitLab](#contribute-to-gitlab)\n" }
+
+ it { expect(subject.filename).to eq('CONTRIBUTE.md') }
+ it { expect(subject.basename).to eq('CONTRIBUTE') }
+ end
+
+ context "when file under directory" do
+ let(:search_result) { "master:a/b/c.md:5:a b c\n" }
+
+ it { expect(subject.filename).to eq('a/b/c.md') }
+ it { expect(subject.basename).to eq('a/b/c') }
+ end
+ end
+
describe 'search_autocomplete_source' do
context "with no current user" do
before do
diff --git a/spec/lib/banzai/pipeline/wiki_pipeline_spec.rb b/spec/lib/banzai/pipeline/wiki_pipeline_spec.rb
index 51c89ac4889..ac9bde6baf1 100644
--- a/spec/lib/banzai/pipeline/wiki_pipeline_spec.rb
+++ b/spec/lib/banzai/pipeline/wiki_pipeline_spec.rb
@@ -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\"")
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
describe "when creating root links" do
diff --git a/spec/lib/gitlab/github_import/comment_formatter_spec.rb b/spec/lib/gitlab/github_import/comment_formatter_spec.rb
index 9ae02a6c45f..c520a9c53ad 100644
--- a/spec/lib/gitlab/github_import/comment_formatter_spec.rb
+++ b/spec/lib/gitlab/github_import/comment_formatter_spec.rb
@@ -73,6 +73,12 @@ describe Gitlab::GithubImport::CommentFormatter, lib: true do
gl_user = create(:omniauth_user, extern_uid: octocat.id, provider: 'github')
expect(comment.attributes.fetch(:author_id)).to eq gl_user.id
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
diff --git a/spec/lib/gitlab/github_import/importer_spec.rb b/spec/lib/gitlab/github_import/importer_spec.rb
index 7df288f619f..553c849c9b4 100644
--- a/spec/lib/gitlab/github_import/importer_spec.rb
+++ b/spec/lib/gitlab/github_import/importer_spec.rb
@@ -98,6 +98,30 @@ describe Gitlab::GithubImport::Importer, lib: true do
)
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
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)
@@ -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(: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(:releases).and_return([release1, release2])
allow_any_instance_of(Gitlab::Shell).to receive(:import_repository).and_raise(Gitlab::Shell::Error)
end
@@ -127,8 +152,9 @@ 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: :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: :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" }
+ ]
}
described_class.new(project).execute
diff --git a/spec/lib/gitlab/github_import/issue_formatter_spec.rb b/spec/lib/gitlab/github_import/issue_formatter_spec.rb
index d60c4111e99..c2f1f6b91a1 100644
--- a/spec/lib/gitlab/github_import/issue_formatter_spec.rb
+++ b/spec/lib/gitlab/github_import/issue_formatter_spec.rb
@@ -109,6 +109,12 @@ describe Gitlab::GithubImport::IssueFormatter, lib: true do
expect(issue.attributes.fetch(:author_id)).to eq gl_user.id
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
diff --git a/spec/lib/gitlab/github_import/pull_request_formatter_spec.rb b/spec/lib/gitlab/github_import/pull_request_formatter_spec.rb
index edfc6ad81c6..302f0fc0623 100644
--- a/spec/lib/gitlab/github_import/pull_request_formatter_spec.rb
+++ b/spec/lib/gitlab/github_import/pull_request_formatter_spec.rb
@@ -140,6 +140,12 @@ describe Gitlab::GithubImport::PullRequestFormatter, lib: true do
expect(pull_request.attributes.fetch(:author_id)).to eq gl_user.id
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
context 'when it has a milestone' do
diff --git a/spec/lib/gitlab/github_import/release_formatter_spec.rb b/spec/lib/gitlab/github_import/release_formatter_spec.rb
new file mode 100644
index 00000000000..793128c6ab9
--- /dev/null
+++ b/spec/lib/gitlab/github_import/release_formatter_spec.rb
@@ -0,0 +1,54 @@
+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
diff --git a/spec/lib/gitlab/workhorse_spec.rb b/spec/lib/gitlab/workhorse_spec.rb
index 395192149a9..6c7fa7e7c15 100644
--- a/spec/lib/gitlab/workhorse_spec.rb
+++ b/spec/lib/gitlab/workhorse_spec.rb
@@ -30,6 +30,11 @@ describe Gitlab::Workhorse, lib: true do
expect(subject.encoding).to eq(Encoding::ASCII_8BIT)
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
File.delete(described_class.secret_path)
expect { subject }.to raise_exception(Errno::ENOENT)
diff --git a/spec/models/blob_spec.rb b/spec/models/blob_spec.rb
index cee20234e1f..03d02b4d382 100644
--- a/spec/models/blob_spec.rb
+++ b/spec/models/blob_spec.rb
@@ -1,3 +1,4 @@
+# encoding: utf-8
require 'rails_helper'
describe Blob do
@@ -7,6 +8,25 @@ describe Blob do
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
it 'is falsey when not text' do
git_blob = double(text?: false)
diff --git a/spec/models/build_spec.rb b/spec/models/build_spec.rb
index c45c2635cf4..8eab4281bc7 100644
--- a/spec/models/build_spec.rb
+++ b/spec/models/build_spec.rb
@@ -231,6 +231,34 @@ describe Ci::Build, models: true do
it { is_expected.to eq(predefined_variables) }
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
let(:tag_variable) do
{ key: 'CI_BUILD_TAG', value: 'master', public: true }
diff --git a/spec/models/member_spec.rb b/spec/models/member_spec.rb
index fef90d9b5cb..0b1634f654a 100644
--- a/spec/models/member_spec.rb
+++ b/spec/models/member_spec.rb
@@ -57,7 +57,7 @@ describe Member, models: true do
describe 'Scopes & finders' do
before do
- project = create(:project)
+ project = create(:empty_project)
group = create(:group)
@owner_user = create(:user).tap { |u| group.add_owner(u) }
@owner = group.members.find_by(user_id: @owner_user.id)
@@ -65,6 +65,15 @@ describe Member, models: true do
@master_user = create(:user).tap { |u| project.team << [u, :master] }
@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(
project.members,
'toto1@example.com',
@@ -73,7 +82,7 @@ describe Member, models: true do
)
@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(
project.members,
'toto2@example.com',
@@ -91,7 +100,7 @@ describe Member, models: true do
describe '.access_for_user_ids' 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 = {
@owner_user.id => Gitlab::Access::OWNER,
@master_user.id => Gitlab::Access::MASTER
@@ -125,6 +134,19 @@ describe Member, models: true do
it { expect(described_class.request).not_to include @accepted_request_member }
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
it { expect(described_class.owners_and_masters).to include @owner }
it { expect(described_class.owners_and_masters).to include @master }
@@ -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 @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 @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
diff --git a/spec/models/merge_request_spec.rb b/spec/models/merge_request_spec.rb
index 5bf3b8e609e..3b815ded2d3 100644
--- a/spec/models/merge_request_spec.rb
+++ b/spec/models/merge_request_spec.rb
@@ -1038,4 +1038,81 @@ describe MergeRequest, models: true do
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
diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb
index 4a41fafb84d..f6e811828fc 100644
--- a/spec/models/project_spec.rb
+++ b/spec/models/project_spec.rb
@@ -6,6 +6,7 @@ describe Project, models: true do
it { is_expected.to belong_to(:namespace) }
it { is_expected.to belong_to(:creator).class_name('User') }
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(:merge_requests).dependent(:destroy) }
it { is_expected.to have_many(:issues).dependent(:destroy) }
@@ -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(:asana_service).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(:pipelines) }
it { is_expected.to have_many(:builds) }
@@ -31,9 +56,16 @@ describe Project, models: true do
it { is_expected.to have_many(:runners) }
it { is_expected.to have_many(:variables) }
it { is_expected.to have_many(:triggers) }
+ 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(:deployments).dependent(:destroy) }
it { is_expected.to have_many(:todos).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
let(:project) { create(:project) }
@@ -178,7 +210,7 @@ describe Project, models: true do
expect(project.runners_token).not_to eq('')
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'
expect(project.runners_token).to eq('my-token')
end
@@ -1497,4 +1529,56 @@ describe Project, models: true do
project.change_head(project.default_branch)
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
diff --git a/spec/models/repository_spec.rb b/spec/models/repository_spec.rb
index 7624050878e..94681004c96 100644
--- a/spec/models/repository_spec.rb
+++ b/spec/models/repository_spec.rb
@@ -186,32 +186,6 @@ describe Repository, models: true do
it { is_expected.to be_an String }
it { expect(subject.lines[2]).to eq("master:CHANGELOG:188: - Feature: Replace teams with group membership\n") }
end
-
- describe 'parsing result' do
- subject { repository.parse_search_result(search_result) }
- let(:search_result) { results.first }
-
- it { is_expected.to be_an OpenStruct }
- it { expect(subject.filename).to eq('CHANGELOG') }
- it { expect(subject.basename).to eq('CHANGELOG') }
- it { expect(subject.ref).to eq('master') }
- it { expect(subject.startline).to eq(186) }
- it { expect(subject.data.lines[2]).to eq(" - Feature: Replace teams with group membership\n") }
-
- context "when filename has extension" do
- let(:search_result) { "master:CONTRIBUTE.md:5:- [Contribute to GitLab](#contribute-to-gitlab)\n" }
-
- it { expect(subject.filename).to eq('CONTRIBUTE.md') }
- it { expect(subject.basename).to eq('CONTRIBUTE') }
- end
-
- context "when file under directory" do
- let(:search_result) { "master:a/b/c.md:5:a b c\n" }
-
- it { expect(subject.filename).to eq('a/b/c.md') }
- it { expect(subject.basename).to eq('a/b/c') }
- end
- end
end
describe "#changelog" do
diff --git a/spec/requests/api/commit_statuses_spec.rb b/spec/requests/api/commit_statuses_spec.rb
index 2d6093fec7a..7aa7e85a9e2 100644
--- a/spec/requests/api/commit_statuses_spec.rb
+++ b/spec/requests/api/commit_statuses_spec.rb
@@ -117,17 +117,36 @@ describe API::CommitStatuses, api: true do
let(:post_url) { "/projects/#{project.id}/statuses/#{sha}" }
context 'developer user' do
- context 'only required parameters' do
- before { post api(post_url, developer), state: 'success' }
+ %w[pending running success failed canceled].each do |status|
+ context "for #{status}" do
+ context 'uses only required parameters' do
+ it 'creates commit status' do
+ post api(post_url, developer), state: status
+
+ expect(response).to have_http_status(201)
+ expect(json_response['sha']).to eq(commit.id)
+ expect(json_response['status']).to eq(status)
+ expect(json_response['name']).to eq('default')
+ expect(json_response['ref']).not_to be_empty
+ expect(json_response['target_url']).to be_nil
+ expect(json_response['description']).to be_nil
+ end
+ end
+ end
+ end
- it 'creates commit status' do
- expect(response).to have_http_status(201)
- expect(json_response['sha']).to eq(commit.id)
- expect(json_response['status']).to eq('success')
- expect(json_response['name']).to eq('default')
- expect(json_response['ref']).to be_nil
- expect(json_response['target_url']).to be_nil
- expect(json_response['description']).to be_nil
+ 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
diff --git a/spec/requests/api/issues_spec.rb b/spec/requests/api/issues_spec.rb
index 86d994be079..f840778ae9b 100644
--- a/spec/requests/api/issues_spec.rb
+++ b/spec/requests/api/issues_spec.rb
@@ -18,6 +18,7 @@ describe API::API, api: true do
project: project,
state: :closed,
milestone: milestone,
+ created_at: generate(:issue_created_at),
updated_at: 3.hours.ago
end
let!(:confidential_issue) do
@@ -26,6 +27,7 @@ describe API::API, api: true do
project: project,
author: author,
assignee: assignee,
+ created_at: generate(:issue_created_at),
updated_at: 2.hours.ago
end
let!(:issue) do
@@ -34,6 +36,7 @@ describe API::API, api: true do
assignee: user,
project: project,
milestone: milestone,
+ created_at: generate(:issue_created_at),
updated_at: 1.hour.ago
end
let!(:label) do
diff --git a/spec/requests/ci/api/builds_spec.rb b/spec/requests/ci/api/builds_spec.rb
index 9e390bea50b..780bd7f2859 100644
--- a/spec/requests/ci/api/builds_spec.rb
+++ b/spec/requests/ci/api/builds_spec.rb
@@ -15,6 +15,25 @@ describe Ci::API::API do
describe "POST /builds/register" do
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
register_builds info: { platform: :darwin }
@@ -33,36 +52,30 @@ describe Ci::API::API do
context 'when builds are finished' do
before do
build.success
- end
-
- it "returns 404 error if no builds for specific runner" do
register_builds
-
- expect(response).to have_http_status(404)
end
+
+ it_behaves_like 'no builds available'
end
context 'for other project with builds' do
before do
build.success
create(:ci_build, :pending)
- end
-
- it "returns 404 error if no builds for shared runner" do
register_builds
-
- expect(response).to have_http_status(404)
end
+
+ it_behaves_like 'no builds available'
end
context 'for shared runner' do
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
-
- expect(response).to have_http_status(404)
end
+
+ it_behaves_like 'no builds available'
end
context 'for triggered build' do
@@ -136,18 +149,27 @@ describe Ci::API::API do
end
context 'when runner is not allowed to pick untagged builds' do
- before { runner.update_column(:run_untagged, false) }
-
- it 'does not pick build' do
+ before do
+ runner.update_column(:run_untagged, false)
register_builds
-
- expect(response).to have_http_status 404
end
+
+ it_behaves_like 'no builds available'
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
+
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
diff --git a/spec/services/projects/housekeeping_service_spec.rb b/spec/services/projects/housekeeping_service_spec.rb
index ad0d58672b3..c6160f4fa57 100644
--- a/spec/services/projects/housekeeping_service_spec.rb
+++ b/spec/services/projects/housekeeping_service_spec.rb
@@ -4,12 +4,11 @@ describe Projects::HousekeepingService do
subject { Projects::HousekeepingService.new(project) }
let(:project) { create :project }
- describe 'execute' do
- before do
- project.pushes_since_gc = 3
- project.save!
- end
+ after do
+ project.reset_pushes_since_gc
+ end
+ describe '#execute' do
it 'enqueues a sidekiq job' do
expect(subject).to receive(:try_obtain_lease).and_return(true)
expect(GitGarbageCollectWorker).to receive(:perform_async).with(project.id)
@@ -32,12 +31,12 @@ describe Projects::HousekeepingService do
it 'does not reset pushes_since_gc' do
expect do
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
- describe 'needed?' do
+ describe '#needed?' do
it 'when the count is low enough' do
expect(subject.needed?).to eq(false)
end
@@ -48,25 +47,11 @@ describe Projects::HousekeepingService do
end
end
- describe 'increment!' do
- let(:lease_key) { "project_housekeeping:increment!:#{project.id}" }
-
+ describe '#increment!' 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
subject.increment!
end.to change { project.pushes_since_gc }.from(0).to(1)
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
diff --git a/vendor/gitignore/Global/NetBeans.gitignore b/vendor/gitignore/Global/NetBeans.gitignore
index 520d91ff584..254108cd23b 100644
--- a/vendor/gitignore/Global/NetBeans.gitignore
+++ b/vendor/gitignore/Global/NetBeans.gitignore
@@ -3,5 +3,4 @@ build/
nbbuild/
dist/
nbdist/
-nbactions.xml
.nb-gradle/
diff --git a/vendor/gitignore/Global/Tags.gitignore b/vendor/gitignore/Global/Tags.gitignore
index c0318165a27..91927af4cd6 100644
--- a/vendor/gitignore/Global/Tags.gitignore
+++ b/vendor/gitignore/Global/Tags.gitignore
@@ -9,6 +9,7 @@ gtags.files
GTAGS
GRTAGS
GPATH
+GSYMS
cscope.files
cscope.out
cscope.in.out
diff --git a/vendor/gitignore/Global/OSX.gitignore b/vendor/gitignore/Global/macOS.gitignore
index 5972fe50f66..828a509a137 100644
--- a/vendor/gitignore/Global/OSX.gitignore
+++ b/vendor/gitignore/Global/macOS.gitignore
@@ -3,7 +3,8 @@
.LSOverride
# Icon must end with two \r
-Icon
+Icon
+
# Thumbnails
._*
diff --git a/vendor/gitignore/Haskell.gitignore b/vendor/gitignore/Haskell.gitignore
index a4ee41ab62b..450f32ec40c 100644
--- a/vendor/gitignore/Haskell.gitignore
+++ b/vendor/gitignore/Haskell.gitignore
@@ -17,3 +17,4 @@ cabal.sandbox.config
*.eventlog
.stack-work/
cabal.project.local
+.HTF/
diff --git a/vendor/gitignore/Joomla.gitignore b/vendor/gitignore/Joomla.gitignore
index 0d7a0de298f..93103fdbe77 100644
--- a/vendor/gitignore/Joomla.gitignore
+++ b/vendor/gitignore/Joomla.gitignore
@@ -52,6 +52,7 @@
/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.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.sys.ini
/administrator/language/en-GB/en-GB.plg_finder_contacts.ini
@@ -64,6 +65,10 @@
/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.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.sys.ini
/administrator/language/en-GB/en-GB.plg_quickicon_joomlaupdate.ini
@@ -72,6 +77,8 @@
/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.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.sys.ini
/administrator/language/en-GB/en-GB.plg_twofactorauth_yubikey.ini
@@ -249,8 +256,10 @@
/administrator/language/en-GB/en-GB.tpl_hathor.sys.ini
/administrator/language/en-GB/en-GB.xml
/administrator/language/en-GB/index.html
+/administrator/language/ru-RU/index.html
/administrator/language/overrides/*
/administrator/language/index.html
+/administrator/logs/index.html
/administrator/manifests/*
/administrator/modules/mod_custom/*
/administrator/modules/mod_feed/*
@@ -289,6 +298,7 @@
/components/com_finder/*
/components/com_mailto/*
/components/com_media/*
+/components/com_modules/*
/components/com_newsfeeds/*
/components/com_search/*
/components/com_users/*
@@ -407,6 +417,7 @@
/libraries/idna_convert/*
/libraries/joomla/*
/libraries/legacy/*
+/libraries/php-encryption/*
/libraries/phpass/*
/libraries/phpmailer/*
/libraries/phputf8/*
@@ -431,9 +442,11 @@
/media/media/*
/media/mod_languages/*
/media/overrider/*
+/media/plg_captcha_recaptcha/*
/media/plg_quickicon_extensionupdate/*
/media/plg_quickicon_joomlaupdate/*
/media/plg_system_highlight/*
+/media/plg_system_stats/*
/media/system/*
/media/index.html
/modules/mod_articles_archive/*
@@ -486,6 +499,7 @@
/plugins/editors/none/*
/plugins/editors/tinymce/*
/plugins/editors/index.html
+/plugins/editors-xtd/module/*
/plugins/editors-xtd/article/*
/plugins/editors-xtd/image/*
/plugins/editors-xtd/pagebreak/*
@@ -523,6 +537,8 @@
/plugins/system/redirect/*
/plugins/system/remember/*
/plugins/system/sef/*
+/plugins/system/stats/*
+/plugins/system/updatenotification/*
/plugins/system/index.html
/plugins/twofactorauth/*
/plugins/user/contactcreator/*
diff --git a/vendor/gitignore/Node.gitignore b/vendor/gitignore/Node.gitignore
index aea5294de9d..bf7525f9912 100644
--- a/vendor/gitignore/Node.gitignore
+++ b/vendor/gitignore/Node.gitignore
@@ -34,5 +34,8 @@ jspm_packages
# Optional npm cache directory
.npm
+# Optional eslint cache
+.eslintcache
+
# Optional REPL history
.node_repl_history
diff --git a/vendor/gitignore/Objective-C.gitignore b/vendor/gitignore/Objective-C.gitignore
index 20592083931..58c51ecaed4 100644
--- a/vendor/gitignore/Objective-C.gitignore
+++ b/vendor/gitignore/Objective-C.gitignore
@@ -50,7 +50,9 @@ Carthage/Build
# https://github.com/fastlane/fastlane/blob/master/fastlane/docs/Gitignore.md
fastlane/report.xml
+fastlane/Preview.html
fastlane/screenshots
+fastlane/test_output
# Code Injection
#
diff --git a/vendor/gitignore/Python.gitignore b/vendor/gitignore/Python.gitignore
index 72364f99fe4..37fc9d40817 100644
--- a/vendor/gitignore/Python.gitignore
+++ b/vendor/gitignore/Python.gitignore
@@ -79,6 +79,7 @@ celerybeat-schedule
.env
# virtualenv
+.venv/
venv/
ENV/
diff --git a/vendor/gitignore/Rails.gitignore b/vendor/gitignore/Rails.gitignore
index d8c256c1925..e97427608c1 100644
--- a/vendor/gitignore/Rails.gitignore
+++ b/vendor/gitignore/Rails.gitignore
@@ -12,9 +12,11 @@ capybara-*.html
rerun.txt
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/secrets.yml
+
+# Only include if you have production secrets in this file, which is no longer a Rails default
+# config/secrets.yml
# dotenv
# TODO Comment out this rule if environment variables can be committed
diff --git a/vendor/gitignore/VisualStudio.gitignore b/vendor/gitignore/VisualStudio.gitignore
index 67acbf42f5e..d56f8b53288 100644
--- a/vendor/gitignore/VisualStudio.gitignore
+++ b/vendor/gitignore/VisualStudio.gitignore
@@ -251,3 +251,10 @@ paket-files/
# JetBrains Rider
.idea/
*.sln.iml
+
+# CodeRush
+.cr/
+
+# Python Tools for Visual Studio (PTVS)
+__pycache__/
+*.pyc
diff --git a/vendor/gitlab-ci-yml/Docker.gitlab-ci.yml b/vendor/gitlab-ci-yml/Docker.gitlab-ci.yml
index 396d3f1b042..f3fa3949656 100644
--- a/vendor/gitlab-ci-yml/Docker.gitlab-ci.yml
+++ b/vendor/gitlab-ci-yml/Docker.gitlab-ci.yml
@@ -1,7 +1,12 @@
# Official docker image.
image: docker:latest
+services:
+ - docker:dind
+
build:
stage: build
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"
diff --git a/vendor/gitlab-ci-yml/Ruby.gitlab-ci.yml b/vendor/gitlab-ci-yml/Ruby.gitlab-ci.yml
index 166f146ee05..08b57c8c0ac 100644
--- a/vendor/gitlab-ci-yml/Ruby.gitlab-ci.yml
+++ b/vendor/gitlab-ci-yml/Ruby.gitlab-ci.yml
@@ -43,3 +43,12 @@ rails:
- bundle exec rake db:migrate
- bundle exec rake db:seed
- 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
diff --git a/vendor/gitlab-ci-yml/Swift.gitlab-ci.yml b/vendor/gitlab-ci-yml/Swift.gitlab-ci.yml
new file mode 100644
index 00000000000..c9c35906d1c
--- /dev/null
+++ b/vendor/gitlab-ci-yml/Swift.gitlab-ci.yml
@@ -0,0 +1,30 @@
+# 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