diff options
author | Ruben Davila <rdavila84@gmail.com> | 2016-09-16 18:08:27 +0300 |
---|---|---|
committer | Ruben Davila <rdavila84@gmail.com> | 2016-09-16 18:08:27 +0300 |
commit | 380687c75d9abdbdd0e0b2e57de495f144f81344 (patch) | |
tree | 0fde36ccc14f509f902a67004b5a5d3465256b06 | |
parent | ee249dbe4fc5f5922d49cd952ba5d07398dd1dcf (diff) | |
parent | 7afee665b091f2afb89f0fdda90fa46d56d3e341 (diff) |
Merge branch 'master' into 8-12-stable
126 files changed, 1193 insertions, 1002 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 b5eef681d0e..b167fc74996 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -209,8 +209,12 @@ 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/.rubocop.yml b/.rubocop.yml index 5bd31ccf329..b054675d677 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -767,26 +767,33 @@ Rails/ScopeArgs: RSpec/AnyInstance: Enabled: false -# Check that the first argument to the top level describe is the tested class or -# module. +# Check for expectations where `be(...)` can replace `eql(...)`. +RSpec/BeEql: + Enabled: false + +# Check that the first argument to the top level describe is a constant. RSpec/DescribeClass: Enabled: false -# Use `described_class` for tested class / module. +# Checks that tests use `described_class`. +RSpec/DescribedClass: + Enabled: false + +# Checks that the second argument to `describe` specifies a method. RSpec/DescribeMethod: Enabled: false -# Checks that the second argument to top level describe is the tested method -# name. -RSpec/DescribedClass: +# Checks if an example group does not include any tests. +RSpec/EmptyExampleGroup: Enabled: false + CustomIncludeMethods: [] -# Checks for long example. +# Checks for long examples. RSpec/ExampleLength: Enabled: false Max: 5 -# Do not use should when describing your tests. +# Checks that example descriptions do not start with "should". RSpec/ExampleWording: Enabled: false CustomTransform: @@ -795,6 +802,10 @@ RSpec/ExampleWording: not: does not IgnoredWords: [] +# Checks for `expect(...)` calls containing literal values. +RSpec/ExpectActual: + Enabled: false + # Checks the file and folder naming of the spec file. RSpec/FilePath: Enabled: false @@ -806,19 +817,65 @@ RSpec/FilePath: RSpec/Focus: Enabled: true +# Checks the arguments passed to `before`, `around`, and `after`. +RSpec/HookArgument: + Enabled: false + EnforcedStyle: implicit + +# Check that a consistent implict expectation style is used. +# TODO (rspeicher): Available in rubocop-rspec 1.8.0 +# RSpec/ImplicitExpect: +# Enabled: true +# EnforcedStyle: is_expected + # Checks for the usage of instance variables. RSpec/InstanceVariable: Enabled: false -# Checks for multiple top-level describes. +# Checks for `subject` definitions that come after `let` definitions. +RSpec/LeadingSubject: + Enabled: false + +# Checks unreferenced `let!` calls being used for test setup. +RSpec/LetSetup: + Enabled: false + +# Check that chains of messages are not being stubbed. +RSpec/MessageChain: + Enabled: false + +# Checks for consistent message expectation style. +RSpec/MessageExpectation: + Enabled: false + EnforcedStyle: allow + +# Checks for multiple top level describes. RSpec/MultipleDescribes: Enabled: false -# Enforces the usage of the same method on all negative message expectations. +# Checks if examples contain too many `expect` calls. +RSpec/MultipleExpectations: + Enabled: false + Max: 1 + +# Checks for explicitly referenced test subjects. +RSpec/NamedSubject: + Enabled: false + +# Checks for nested example groups. +RSpec/NestedGroups: + Enabled: false + MaxNesting: 2 + +# Checks for consistent method usage for negating expectations. RSpec/NotToNot: EnforcedStyle: not_to Enabled: true +# Checks for stubbed test subjects. +RSpec/SubjectStub: + Enabled: false + # Prefer using verifying doubles over normal doubles. RSpec/VerifiedDoubles: 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 9d813c9e35f..950a44acc47 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -7,6 +7,7 @@ v 8.12.0 (unreleased) - 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) + - Fix issues/merge-request templates dropdown for forked projects - 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. @@ -21,6 +22,7 @@ v 8.12.0 (unreleased) - Use Search::GlobalService.new in the `GET /projects/search/:query` endpoint - Fix pagination on user snippets page - Fix sorting of issues in API + - Sort project variables by key. !6275 (Diego Souza) - 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 @@ -30,17 +32,21 @@ v 8.12.0 (unreleased) - Add `web_url` field to issue, merge request, and snippet API objects (Ben Boeckel) - Enable pipeline events by default !6278 - Move parsing of sidekiq ps into helper !6245 (pascalbetz) + - Added go to issue boards keyboard shortcut - Expose `sha` and `merge_commit_sha` in merge request API (Ben Boeckel) - Set path for all JavaScript cookies to honor GitLab's subdirectory setting !5627 (Mike Greiling) - Fix blame table layout width - Fix bug where pagination is still displayed despite all todos marked as done (ClemMakesApps) - Request only the LDAP attributes we need !6187 - Center build stage columns in pipeline overview (ClemMakesApps) + - Fix bug with tooltip not hiding on discussion toggle button - Rename behaviour to behavior in bug issue template for consistency (ClemMakesApps) + - Fix bug stopping issue description being scrollable after selecting issue template - Remove suggested colors hover underline (ClemMakesApps) - Shorten task status phrase (ClemMakesApps) - Fix project visibility level fields on settings - Add hover color to emoji icon (ClemMakesApps) + - Increase ci_builds artifacts_size column to 8-byte integer to allow larger files - Add textarea autoresize after comment (ClemMakesApps) - Refresh todos count cache when an Issue/MR is deleted - Fix branches page dropdown sort alignment (ClemMakesApps) @@ -60,6 +66,7 @@ v 8.12.0 (unreleased) - Use 'git update-ref' for safer web commits !6130 - Sort pipelines requested through the API - Automatically expand hidden discussions when accessed by a permalink !5585 (Mike Greiling) + - Fix issue boards loading on large screens - Change pipeline duration to be jobs running time instead of simple wall time from start to end !6084 - Show queued time when showing a pipeline !6084 - Remove unused mixins (ClemMakesApps) @@ -74,7 +81,8 @@ v 8.12.0 (unreleased) - Add last commit time to repo view (ClemMakesApps) - Fix accessibility and visibility of project list dropdown button !6140 - Fix missing flash messages on service edit page (airatshigapov) - - Added project specific enable/disable setting for LFS !5997 + - Added project-specific enable/disable setting for LFS !5997 + - Added group-specific enable/disable setting for LFS !6164 - Don't expose a user's token in the `/api/v3/user` API (!6047) - Remove redundant js-timeago-pending from user activity log (ClemMakesApps) - Ability to manage project issues, snippets, wiki, merge requests and builds access level @@ -130,14 +138,23 @@ v 8.12.0 (unreleased) - Allow bulk update merge requests from merge requests index page - Add notification_settings API calls !5632 (mahcsig) - 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) - -v 8.11.6 (unreleased) - - Fix an error where we were unable to create a CommitStatus for running state + - Clean environment variables when running git hooks + - Fix non-master branch readme display in tree view + +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 @@ -342,6 +359,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 @@ -567,6 +591,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..d5e15bfce14 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 @@ -289,6 +277,8 @@ request is as follows: 1. For more complex migrations, write tests. 1. Merge requests **must** adhere to the [merge request performance guidelines](doc/development/merge_request_performance_guidelines.md). +1. For tests that use Capybara or PhantomJS, see this [article on how + to write reliable asynchronous tests](https://robots.thoughtbot.com/write-reliable-asynchronous-integration-tests-with-capybara). The **official merge window** is in the beginning of the month from the 1st to the 7th day of the month. This is the best time to submit an MR and get @@ -489,7 +479,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 @@ -295,8 +295,8 @@ 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-rspec', '~> 1.5.0', require: false + gem 'rubocop', '~> 0.42.0', require: false + gem 'rubocop-rspec', '~> 1.7.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 diff --git a/Gemfile.lock b/Gemfile.lock index cecd87e2e2b..1edb218373d 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -619,14 +619,14 @@ 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) ruby-progressbar (~> 1.7) unicode-display_width (~> 1.0, >= 1.0.1) - rubocop-rspec (1.5.0) - rubocop (>= 0.40.0) + rubocop-rspec (1.7.0) + rubocop (>= 0.42.0) ruby-fogbugz (0.2.1) crack (~> 0.4) ruby-prof (0.15.9) @@ -762,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 @@ -944,8 +944,8 @@ DEPENDENCIES rqrcode-rails3 (~> 0.1.7) rspec-rails (~> 3.5.0) rspec-retry (~> 0.4.5) - rubocop (~> 0.41.2) - rubocop-rspec (~> 1.5.0) + rubocop (~> 0.42.0) + rubocop-rspec (~> 1.7.0) ruby-fogbugz (~> 0.2.1) ruby-prof (~> 0.15.9) sanitize (~> 2.0) diff --git a/app/assets/javascripts/application.js b/app/assets/javascripts/application.js index 31fa508d6c1..c029bf3b5ca 100644 --- a/app/assets/javascripts/application.js +++ b/app/assets/javascripts/application.js @@ -251,6 +251,7 @@ } else { notesHolders.hide(); } + $this.trigger('blur'); return e.preventDefault(); }); $document.off("click", '.js-confirm-danger'); diff --git a/app/assets/javascripts/blob/template_selector.js b/app/assets/javascripts/blob/template_selector.js index b18b6962382..95352164d76 100644 --- a/app/assets/javascripts/blob/template_selector.js +++ b/app/assets/javascripts/blob/template_selector.js @@ -13,6 +13,9 @@ this.buildDropdown(); this.bindEvents(); this.onFilenameUpdate(); + + this.autosizeUpdateEvent = document.createEvent('Event'); + this.autosizeUpdateEvent.initEvent('autosize:update', true, false); } TemplateSelector.prototype.buildDropdown = function() { @@ -72,6 +75,10 @@ TemplateSelector.prototype.requestFileSuccess = function(file, skipFocus) { this.editor.setValue(file.content, 1); if (!skipFocus) this.editor.focus(); + + if (this.editor instanceof jQuery) { + this.editor.get(0).dispatchEvent(this.autosizeUpdateEvent); + } }; TemplateSelector.prototype.startLoadingSpinner = function() { diff --git a/app/assets/javascripts/boards/components/board_list.js.es6 b/app/assets/javascripts/boards/components/board_list.js.es6 index 50fc11d7737..474805c1437 100644 --- a/app/assets/javascripts/boards/components/board_list.js.es6 +++ b/app/assets/javascripts/boards/components/board_list.js.es6 @@ -34,6 +34,11 @@ }, issues () { this.$nextTick(() => { + if (this.scrollHeight() <= this.listHeight() && this.list.issuesSize > this.list.issues.length) { + this.list.page++; + this.list.getIssues(false); + } + if (this.scrollHeight() > this.listHeight()) { this.showCount = true; } else { diff --git a/app/assets/javascripts/gl_dropdown.js b/app/assets/javascripts/gl_dropdown.js index bea141bae51..087f27d9f4c 100644 --- a/app/assets/javascripts/gl_dropdown.js +++ b/app/assets/javascripts/gl_dropdown.js @@ -352,7 +352,13 @@ if (self.options.clicked) { self.options.clicked(selected, $el, e); } - return $el.trigger('blur'); + + // Update label right after all modifications in dropdown has been done + if (self.options.toggleLabel) { + self.updateLabel(selected, $el, self); + } + + $el.trigger('blur'); }); } } @@ -529,7 +535,7 @@ } else { if (!selected) { value = this.options.id ? this.options.id(data) : data.id; - fieldName = typeof this.options.fieldName === 'function' ? this.options.fieldName() : this.options.fieldName; + fieldName = this.options.fieldName; field = this.dropdown.parent().find("input[name='" + fieldName + "'][value='" + value + "']"); if (field.length) { @@ -589,6 +595,7 @@ GitLabDropdown.prototype.rowClicked = function(el) { var field, fieldName, groupName, isInput, selectedIndex, selectedObject, value; + fieldName = this.options.fieldName; isInput = $(this.el).is('input'); if (this.renderedData) { groupName = el.data('group'); @@ -600,7 +607,6 @@ selectedObject = this.renderedData[selectedIndex]; } } - fieldName = typeof this.options.fieldName === 'function' ? this.options.fieldName(selectedObject) : this.options.fieldName; value = this.options.id ? this.options.id(selectedObject, el) : selectedObject.id; if (isInput) { field = $(this.el); @@ -644,11 +650,6 @@ } } - // Update label right after input has been added - if (this.options.toggleLabel) { - this.updateLabel(selectedObject, el, this); - } - return selectedObject; }; @@ -659,9 +660,6 @@ if (this.options.inputId != null) { $input.attr('id', this.options.inputId); } - if (selectedObject && selectedObject.type) { - $input.attr('data-type', selectedObject.type); - } return this.dropdown.before($input); }; diff --git a/app/assets/javascripts/shortcuts_navigation.js b/app/assets/javascripts/shortcuts_navigation.js index 469e25482bb..b04159420d1 100644 --- a/app/assets/javascripts/shortcuts_navigation.js +++ b/app/assets/javascripts/shortcuts_navigation.js @@ -34,6 +34,9 @@ Mousetrap.bind('g i', function() { return ShortcutsNavigation.findAndFollowLink('.shortcuts-issues'); }); + Mousetrap.bind('g l', function() { + ShortcutsNavigation.findAndFollowLink('.shortcuts-issue-boards'); + }); Mousetrap.bind('g m', function() { return ShortcutsNavigation.findAndFollowLink('.shortcuts-merge_requests'); }); diff --git a/app/assets/stylesheets/framework/lists.scss b/app/assets/stylesheets/framework/lists.scss index 965fcc06518..46af18580d5 100644 --- a/app/assets/stylesheets/framework/lists.scss +++ b/app/assets/stylesheets/framework/lists.scss @@ -162,6 +162,10 @@ ul.content-list { margin-right: 0; } } + + .no-comments { + opacity: 0.5; + } } // When dragging a list item diff --git a/app/assets/stylesheets/pages/issues.scss b/app/assets/stylesheets/pages/issues.scss index 60a0d50ba73..3ac34cbc829 100644 --- a/app/assets/stylesheets/pages/issues.scss +++ b/app/assets/stylesheets/pages/issues.scss @@ -10,10 +10,6 @@ .issue-labels { display: inline-block; } - - .issue-no-comments { - opacity: 0.5; - } } } diff --git a/app/assets/stylesheets/pages/merge_requests.scss b/app/assets/stylesheets/pages/merge_requests.scss index 2a44b95de64..96c06086867 100644 --- a/app/assets/stylesheets/pages/merge_requests.scss +++ b/app/assets/stylesheets/pages/merge_requests.scss @@ -231,10 +231,6 @@ .merge-request-labels { display: inline-block; } - - .merge-request-no-comments { - opacity: 0.5; - } } .merge-request-angle { diff --git a/app/assets/stylesheets/pages/pipelines.scss b/app/assets/stylesheets/pages/pipelines.scss index 2d66ab25da6..1b4d12d3053 100644 --- a/app/assets/stylesheets/pages/pipelines.scss +++ b/app/assets/stylesheets/pages/pipelines.scss @@ -147,14 +147,37 @@ } .stage-cell { - text-align: center; + font-size: 0; svg { height: 18px; width: 18px; + position: relative; + z-index: 2; vertical-align: middle; overflow: visible; } + + .stage-container { + display: inline-block; + position: relative; + margin-right: 6px; + + .tooltip { + white-space: nowrap; + } + + &:not(:last-child) { + &::after { + content: ''; + width: 8px; + position: absolute;; + right: -7px; + bottom: 8px; + border-bottom: 2px solid $border-color; + } + } + } } .duration, @@ -318,9 +341,17 @@ .build-content { width: 130px; - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; + + .ci-status-text { + width: 110px; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + vertical-align: middle; + display: inline-block; + position: relative; + top: -1px; + } a { color: $layout-link-gray; @@ -331,13 +362,74 @@ text-decoration: underline; } } + } + + .dropdown-menu-toggle { + border: none; + width: auto; + padding: 0; + color: $layout-link-gray; + + .ci-status-text { + width: 80px; + } + } + + .grouped-pipeline-dropdown { + padding: 8px 0; + width: 200px; + left: auto; + right: -214px; + top: -9px; + + a:hover { + .ci-status-text { + text-decoration: none; + } + } + .ci-status-text { + width: 145px; + } + + .arrow { + &:before, + &:after { + content: ''; + display: inline-block; + position: absolute; + width: 0; + height: 0; + border-color: transparent; + border-style: solid; + top: 18px; + } + + &:before { + left: -5px; + margin-top: -6px; + border-width: 7px 5px 7px 0; + border-right-color: $border-color; + } + + &:after { + left: -4px; + margin-top: -9px; + border-width: 10px 7px 10px 0; + border-right-color: $white-light; + } + } + } + + .badge { + background-color: $gray-dark; + color: $layout-link-gray; + font-weight: normal; } } svg { - position: relative; - top: 2px; + vertical-align: middle; margin-right: 5px; } @@ -442,7 +534,7 @@ width: 21px; height: 25px; position: absolute; - top: -28.5px; + top: -29px; border-top: 2px solid $border-color; } diff --git a/app/assets/stylesheets/pages/projects.scss b/app/assets/stylesheets/pages/projects.scss index 3e6e50375f6..db46d8072ce 100644 --- a/app/assets/stylesheets/pages/projects.scss +++ b/app/assets/stylesheets/pages/projects.scss @@ -334,6 +334,10 @@ a.deploy-project-label { a { color: $gl-dark-link-color; } + + .dropdown-menu { + width: 240px; + } } .last-push-widget { diff --git a/app/assets/stylesheets/pages/snippets.scss b/app/assets/stylesheets/pages/snippets.scss index 2aa939b7dc3..5270aea4e79 100644 --- a/app/assets/stylesheets/pages/snippets.scss +++ b/app/assets/stylesheets/pages/snippets.scss @@ -2,20 +2,6 @@ padding: 2px; } -.snippet-holder { - margin-bottom: -$gl-padding; - - .file-holder { - border-top: 0; - } - - .file-actions { - .btn-clipboard { - @extend .btn; - } - } -} - .markdown-snippet-copy { position: fixed; top: -10px; @@ -24,29 +10,18 @@ max-width: 0; } -.file-holder.snippet-file-content { - padding-bottom: $gl-padding; - border-bottom: 1px solid $border-color; - - .file-title { - padding-top: $gl-padding; - padding-bottom: $gl-padding; - } - - .file-actions { - top: 12px; - } - - .file-content { - border-left: 1px solid $border-color; - border-right: 1px solid $border-color; - border-bottom: 1px solid $border-color; +.snippet-file-content { + border-radius: 3px; + .btn-clipboard { + @extend .btn; } } .snippet-title { font-size: 24px; - font-weight: normal; + font-weight: 600; + padding: $gl-padding; + padding-left: 0; } .snippet-actions { diff --git a/app/controllers/admin/groups_controller.rb b/app/controllers/admin/groups_controller.rb index cdfa8d91a28..aed77d0358a 100644 --- a/app/controllers/admin/groups_controller.rb +++ b/app/controllers/admin/groups_controller.rb @@ -60,6 +60,14 @@ class Admin::GroupsController < Admin::ApplicationController end def group_params - params.require(:group).permit(:name, :description, :path, :avatar, :visibility_level, :request_access_enabled) + params.require(:group).permit( + :avatar, + :description, + :lfs_enabled, + :name, + :path, + :request_access_enabled, + :visibility_level + ) end end diff --git a/app/controllers/groups_controller.rb b/app/controllers/groups_controller.rb index cb82d62616c..b83c3a872cf 100644 --- a/app/controllers/groups_controller.rb +++ b/app/controllers/groups_controller.rb @@ -121,7 +121,17 @@ class GroupsController < Groups::ApplicationController end def group_params - params.require(:group).permit(:name, :description, :path, :avatar, :public, :visibility_level, :share_with_group_lock, :request_access_enabled) + params.require(:group).permit( + :avatar, + :description, + :lfs_enabled, + :name, + :path, + :public, + :request_access_enabled, + :share_with_group_lock, + :visibility_level + ) end def load_events diff --git a/app/controllers/projects/builds_controller.rb b/app/controllers/projects/builds_controller.rb index 77934ff9962..f13fb1df373 100644 --- a/app/controllers/projects/builds_controller.rb +++ b/app/controllers/projects/builds_controller.rb @@ -74,7 +74,7 @@ class Projects::BuildsController < Projects::ApplicationController def erase @build.erase(erased_by: current_user) redirect_to namespace_project_build_path(project.namespace, project, @build), - notice: "Build has been sucessfully erased!" + notice: "Build has been successfully erased!" end def raw diff --git a/app/helpers/groups_helper.rb b/app/helpers/groups_helper.rb index b9211e88473..ab880ed6de0 100644 --- a/app/helpers/groups_helper.rb +++ b/app/helpers/groups_helper.rb @@ -23,4 +23,29 @@ module GroupsHelper full_title end end + + def projects_lfs_status(group) + lfs_status = + if group.lfs_enabled? + group.projects.select(&:lfs_enabled?).size + else + group.projects.reject(&:lfs_enabled?).size + end + + size = group.projects.size + + if lfs_status == size + 'for all projects' + else + "for #{lfs_status} out of #{pluralize(size, 'project')}" + end + end + + def group_lfs_status(group) + status = group.lfs_enabled? ? 'enabled' : 'disabled' + + content_tag(:span, class: "lfs-#{status}") do + "#{status.humanize} #{projects_lfs_status(group)}" + end + end end diff --git a/app/helpers/projects_helper.rb b/app/helpers/projects_helper.rb index 16a8e52a4ca..56477733ea2 100644 --- a/app/helpers/projects_helper.rb +++ b/app/helpers/projects_helper.rb @@ -27,7 +27,7 @@ module ProjectsHelper author_html = "" # Build avatar image tag - author_html << image_tag(avatar_icon(author, opts[:size]), width: opts[:size], class: "avatar avatar-inline #{"s#{opts[:size]}" if opts[:size]}", alt: '') if opts[:avatar] + author_html << image_tag(avatar_icon(author, opts[:size]), width: opts[:size], class: "avatar avatar-inline #{"s#{opts[:size]}" if opts[:size]} #{opts[:avatar_class] if opts[:avatar_class]}", alt: '') if opts[:avatar] # Build name span tag if opts[:by_username] diff --git a/app/helpers/snippets_helper.rb b/app/helpers/snippets_helper.rb index 0a5a8eb5aee..7e33a562077 100644 --- a/app/helpers/snippets_helper.rb +++ b/app/helpers/snippets_helper.rb @@ -1,10 +1,10 @@ module SnippetsHelper - def reliable_snippet_path(snippet) + def reliable_snippet_path(snippet, opts = nil) if snippet.project_id? namespace_project_snippet_path(snippet.project.namespace, - snippet.project, snippet) + snippet.project, snippet, opts) else - snippet_path(snippet) + snippet_path(snippet, opts) end end diff --git a/app/models/ci/variable.rb b/app/models/ci/variable.rb index c9c47ec7419..6959223aed9 100644 --- a/app/models/ci/variable.rb +++ b/app/models/ci/variable.rb @@ -1,7 +1,7 @@ module Ci class Variable < ActiveRecord::Base extend Ci::Model - + belongs_to :project, class_name: '::Project', foreign_key: :gl_project_id validates_uniqueness_of :key, scope: :gl_project_id @@ -11,7 +11,9 @@ module Ci format: { with: /\A[a-zA-Z0-9_]+\z/, message: "can contain only letters, digits and '_'." } - attr_encrypted :value, + scope :order_key_asc, -> { reorder(key: :asc) } + + attr_encrypted :value, mode: :per_attribute_iv_and_salt, insecure_mode: true, key: Gitlab::Application.secrets.db_key_base, diff --git a/app/models/commit_status.rb b/app/models/commit_status.rb index 4a628924499..c85561291c8 100644 --- a/app/models/commit_status.rb +++ b/app/models/commit_status.rb @@ -69,17 +69,15 @@ class CommitStatus < ActiveRecord::Base commit_status.update_attributes finished_at: Time.now end - # We use around_transition to process pipeline on next stages as soon as possible, before the `after_*` is executed - around_transition any => [:success, :failed, :canceled] do |commit_status, block| - block.call - - commit_status.pipeline.try(:process!) - end - after_transition do |commit_status, transition| commit_status.pipeline.try(:build_updated) unless transition.loopback? end + after_transition any => [:success, :failed, :canceled] do |commit_status| + commit_status.pipeline.try(:process!) + true + end + after_transition [:created, :pending, :running] => :success do |commit_status| MergeRequests::MergeWhenBuildSucceedsService.new(commit_status.pipeline.project, nil).trigger(commit_status) end @@ -95,6 +93,10 @@ class CommitStatus < ActiveRecord::Base pipeline.before_sha || Gitlab::Git::BLANK_SHA end + def group_name + name.gsub(/\d+[\s:\/\\]+\d+\s*/, '').strip + end + def self.stages # We group by stage name, but order stages by theirs' index unscoped.from(all, :sg).group('stage').order('max(stage_idx)', 'stage').pluck('sg.stage') @@ -113,6 +115,10 @@ class CommitStatus < ActiveRecord::Base allow_failure? && (failed? || canceled?) end + def playable? + false + end + def duration calculate_duration end diff --git a/app/models/concerns/has_status.rb b/app/models/concerns/has_status.rb index f7b8352405c..d658552f695 100644 --- a/app/models/concerns/has_status.rb +++ b/app/models/concerns/has_status.rb @@ -8,8 +8,9 @@ module HasStatus class_methods do def status_sql - scope = all.relevant + scope = all builds = scope.select('count(*)').to_sql + created = scope.created.select('count(*)').to_sql success = scope.success.select('count(*)').to_sql ignored = scope.ignored.select('count(*)').to_sql if scope.respond_to?(:ignored) ignored ||= '0' @@ -19,12 +20,12 @@ module HasStatus skipped = scope.skipped.select('count(*)').to_sql deduce_status = "(CASE - WHEN (#{builds})=0 THEN NULL + WHEN (#{builds})=(#{created}) THEN NULL WHEN (#{builds})=(#{skipped}) THEN 'skipped' WHEN (#{builds})=(#{success})+(#{ignored})+(#{skipped}) THEN 'success' - WHEN (#{builds})=(#{pending})+(#{skipped}) THEN 'pending' + WHEN (#{builds})=(#{created})+(#{pending})+(#{skipped}) THEN 'pending' WHEN (#{builds})=(#{canceled})+(#{success})+(#{ignored})+(#{skipped}) THEN 'canceled' - WHEN (#{running})+(#{pending})>0 THEN 'running' + WHEN (#{running})+(#{pending})+(#{created})>0 THEN 'running' ELSE 'failed' END)" diff --git a/app/models/group.rb b/app/models/group.rb index c48869ae465..aefb94b2ada 100644 --- a/app/models/group.rb +++ b/app/models/group.rb @@ -95,6 +95,13 @@ class Group < Namespace end end + def lfs_enabled? + return false unless Gitlab.config.lfs.enabled + return Gitlab.config.lfs.enabled if self[:lfs_enabled].nil? + + self[:lfs_enabled] + end + def add_users(user_ids, access_level, current_user: nil, expires_at: nil) user_ids.each do |user_id| Member.add_user( 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 f7d1253d957..75f48fd4ba5 100644 --- a/app/models/merge_request.rb +++ b/app/models/merge_request.rb @@ -652,7 +652,7 @@ class MergeRequest < ActiveRecord::Base end def environments - return unless diff_head_commit + return [] unless diff_head_commit target_project.environments.select do |environment| environment.includes_commit?(diff_head_commit) diff --git a/app/models/namespace.rb b/app/models/namespace.rb index 7c29d27ce97..919b3b1f095 100644 --- a/app/models/namespace.rb +++ b/app/models/namespace.rb @@ -141,6 +141,11 @@ class Namespace < ActiveRecord::Base projects.joins(:forked_project_link).find_by('forked_project_links.forked_from_project_id = ?', project.id) end + def lfs_enabled? + # User namespace will always default to the global setting + Gitlab.config.lfs.enabled + end + private def repository_storage_paths diff --git a/app/models/project.rb b/app/models/project.rb index f3f3ffbbd28..8b5a6f167bd 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -393,10 +393,9 @@ class Project < ActiveRecord::Base end def lfs_enabled? - return false unless Gitlab.config.lfs.enabled - return Gitlab.config.lfs.enabled if self[:lfs_enabled].nil? + return namespace.lfs_enabled? if self[:lfs_enabled].nil? - self[:lfs_enabled] + self[:lfs_enabled] && Gitlab.config.lfs.enabled end def repository_storage_path diff --git a/app/services/commits/change_service.rb b/app/services/commits/change_service.rb index ed73d8cb8c2..1c82599c579 100644 --- a/app/services/commits/change_service.rb +++ b/app/services/commits/change_service.rb @@ -16,11 +16,29 @@ module Commits error(ex.message) end + private + def commit raise NotImplementedError end - private + def commit_change(action) + raise NotImplementedError unless repository.respond_to?(action) + + into = @create_merge_request ? @commit.public_send("#{action}_branch_name") : @target_branch + tree_id = repository.public_send("check_#{action}_content", @commit, @target_branch) + + if tree_id + create_target_branch(into) if @create_merge_request + + repository.public_send(action, current_user, @commit, into, tree_id) + success + else + error_msg = "Sorry, we cannot #{action.to_s.dasherize} this #{@commit.change_type_title} automatically. + It may have already been #{action.to_s.dasherize}, or a more recent commit may have updated some of its content." + raise ChangeError, error_msg + end + end def check_push_permissions allowed = ::Gitlab::UserAccess.new(current_user, project: project).can_push_to_branch?(@target_branch) diff --git a/app/services/commits/cherry_pick_service.rb b/app/services/commits/cherry_pick_service.rb index f9a4efa7182..605cca36f9c 100644 --- a/app/services/commits/cherry_pick_service.rb +++ b/app/services/commits/cherry_pick_service.rb @@ -1,19 +1,7 @@ module Commits class CherryPickService < ChangeService def commit - cherry_pick_into = @create_merge_request ? @commit.cherry_pick_branch_name : @target_branch - cherry_pick_tree_id = repository.check_cherry_pick_content(@commit, @target_branch) - - if cherry_pick_tree_id - create_target_branch(cherry_pick_into) if @create_merge_request - - repository.cherry_pick(current_user, @commit, cherry_pick_into, cherry_pick_tree_id) - success - else - error_msg = "Sorry, we cannot cherry-pick this #{@commit.change_type_title} automatically. - It may have already been cherry-picked, or a more recent commit may have updated some of its content." - raise ChangeError, error_msg - end + commit_change(:cherry_pick) end end end diff --git a/app/services/commits/revert_service.rb b/app/services/commits/revert_service.rb index c7de9f6f35e..addd55cb32f 100644 --- a/app/services/commits/revert_service.rb +++ b/app/services/commits/revert_service.rb @@ -1,19 +1,7 @@ module Commits class RevertService < ChangeService def commit - revert_into = @create_merge_request ? @commit.revert_branch_name : @target_branch - revert_tree_id = repository.check_revert_content(@commit, @target_branch) - - if revert_tree_id - create_target_branch(revert_into) if @create_merge_request - - repository.revert(current_user, @commit, revert_into, revert_tree_id) - success - else - error_msg = "Sorry, we cannot revert this #{@commit.change_type_title} automatically. - It may have already been reverted, or a more recent commit may have updated some of its content." - raise ChangeError, error_msg - end + commit_change(:revert) end end end diff --git a/app/views/admin/groups/_form.html.haml b/app/views/admin/groups/_form.html.haml index 5f7fdfdb011..817910f7ddf 100644 --- a/app/views/admin/groups/_form.html.haml +++ b/app/views/admin/groups/_form.html.haml @@ -13,6 +13,8 @@ .col-sm-offset-2.col-sm-10 = render 'shared/allow_request_access', form: f + = render 'groups/group_lfs_settings', f: f + - if @group.new_record? .form-group .col-sm-offset-2.col-sm-10 diff --git a/app/views/admin/groups/show.html.haml b/app/views/admin/groups/show.html.haml index bb374694400..0188ed448ce 100644 --- a/app/views/admin/groups/show.html.haml +++ b/app/views/admin/groups/show.html.haml @@ -37,6 +37,12 @@ %strong = @group.created_at.to_s(:medium) + %li + %span.light Group Git LFS status: + %strong + = group_lfs_status(@group) + = link_to icon('question-circle'), help_page_path('workflow/lfs/manage_large_binaries_with_git_lfs') + .panel.panel-default .panel-heading %h3.panel-title diff --git a/app/views/groups/_group_lfs_settings.html.haml b/app/views/groups/_group_lfs_settings.html.haml new file mode 100644 index 00000000000..af57065f0fc --- /dev/null +++ b/app/views/groups/_group_lfs_settings.html.haml @@ -0,0 +1,11 @@ +- if current_user.admin? + .form-group + .col-sm-offset-2.col-sm-10 + .checkbox + = f.label :lfs_enabled do + = f.check_box :lfs_enabled, checked: @group.lfs_enabled? + %strong + Allow projects within this group to use Git LFS + = link_to icon('question-circle'), help_page_path('workflow/lfs/manage_large_binaries_with_git_lfs') + %br/ + %span.descr This setting can be overridden in each project.
\ No newline at end of file diff --git a/app/views/groups/edit.html.haml b/app/views/groups/edit.html.haml index decb89b2fd6..c766370d5a0 100644 --- a/app/views/groups/edit.html.haml +++ b/app/views/groups/edit.html.haml @@ -25,6 +25,8 @@ .col-sm-offset-2.col-sm-10 = render 'shared/allow_request_access', form: f + = render 'group_lfs_settings', f: f + .form-group %hr = f.label :share_with_group_lock, class: 'control-label' do diff --git a/app/views/help/_shortcuts.html.haml b/app/views/help/_shortcuts.html.haml index 16c16cec137..65842a0479b 100644 --- a/app/views/help/_shortcuts.html.haml +++ b/app/views/help/_shortcuts.html.haml @@ -165,6 +165,12 @@ %tr %td.shortcut .key g + .key l + %td + Go to issue boards + %tr + %td.shortcut + .key g .key m %td Go to merge requests diff --git a/app/views/layouts/nav/_project.html.haml b/app/views/layouts/nav/_project.html.haml index f7012595a5a..8e4937b7aa0 100644 --- a/app/views/layouts/nav/_project.html.haml +++ b/app/views/layouts/nav/_project.html.haml @@ -113,3 +113,7 @@ %li.hidden = link_to project_commits_path(@project), title: 'Commits', class: 'shortcuts-commits' do Commits + + -# Shortcut to issue boards + %li.hidden + = link_to 'Issue Boards', namespace_project_board_path(@project.namespace, @project), title: 'Issue Boards', class: 'shortcuts-issue-boards' diff --git a/app/views/profiles/update_username.js.haml b/app/views/profiles/update_username.js.haml index 249680bcab6..de1337a2a24 100644 --- a/app/views/profiles/update_username.js.haml +++ b/app/views/profiles/update_username.js.haml @@ -1,6 +1,6 @@ - if @user.valid? :plain - new Flash("Username sucessfully changed", "notice") + new Flash("Username successfully changed", "notice") - else :plain new Flash("Username change failed - #{@user.errors.full_messages.first}", "alert") diff --git a/app/views/projects/ci/builds/_build_pipeline.html.haml b/app/views/projects/ci/builds/_build_pipeline.html.haml index 36fb0300aeb..547bc0c9c19 100644 --- a/app/views/projects/ci/builds/_build_pipeline.html.haml +++ b/app/views/projects/ci/builds/_build_pipeline.html.haml @@ -1,15 +1,12 @@ - is_playable = subject.playable? && can?(current_user, :update_build, @project) -%li.build{class: ("playable" if is_playable)} - .curve - .build-content - - if is_playable - = link_to play_namespace_project_build_path(subject.project.namespace, subject.project, subject, return_to: request.original_url), method: :post, title: 'Play' do - = render_status_with_link('build', 'play') - %span.ci-status-text= subject.name - - elsif can?(current_user, :read_build, @project) - = link_to namespace_project_build_path(subject.project.namespace, subject.project, subject) do - = render_status_with_link('build', subject.status) - %span.ci-status-text= subject.name - - else - = render_status_with_link('build', subject.status) - = ci_icon_for_status(subject.status) +- if is_playable + = link_to play_namespace_project_build_path(subject.project.namespace, subject.project, subject, return_to: request.original_url), method: :post, title: 'Play' do + = render_status_with_link('build', 'play') + .ci-status-text= subject.name +- elsif can?(current_user, :read_build, @project) + = link_to namespace_project_build_path(subject.project.namespace, subject.project, subject) do + = render_status_with_link('build', subject.status) + .ci-status-text= subject.name +- else + = render_status_with_link('build', subject.status) + = ci_icon_for_status(subject.status) diff --git a/app/views/projects/ci/pipelines/_pipeline.html.haml b/app/views/projects/ci/pipelines/_pipeline.html.haml index bb9493f5158..6391c67021b 100644 --- a/app/views/projects/ci/pipelines/_pipeline.html.haml +++ b/app/views/projects/ci/pipelines/_pipeline.html.haml @@ -36,16 +36,14 @@ - stages_status = pipeline.statuses.relevant.latest.stages_status - - stages.each do |stage| - %td.stage-cell + %td.stage-cell + - stages.each do |stage| - status = stages_status[stage] - tooltip = "#{stage.titleize}: #{status || 'not found'}" - if status - = link_to namespace_project_pipeline_path(pipeline.project.namespace, pipeline.project, pipeline.id, anchor: stage), class: "has-tooltip ci-status-icon-#{status}", title: tooltip do - = ci_icon_for_status(status) - - else - .light.has-tooltip{ title: tooltip } - \- + .stage-container + = link_to namespace_project_pipeline_path(pipeline.project.namespace, pipeline.project, pipeline.id, anchor: stage), class: "has-tooltip ci-status-icon-#{status}", title: tooltip do + = ci_icon_for_status(status) %td - if pipeline.duration diff --git a/app/views/projects/commit/_pipeline.html.haml b/app/views/projects/commit/_pipeline.html.haml index 20a85148ab5..9258f4b3c25 100644 --- a/app/views/projects/commit/_pipeline.html.haml +++ b/app/views/projects/commit/_pipeline.html.haml @@ -39,8 +39,7 @@ = stage.titleize .builds-container %ul - - statuses.each do |status| - = render "projects/#{status.to_partial_path}_pipeline", subject: status + = render "projects/commit/pipeline_stage", statuses: statuses - if pipeline.yaml_errors.present? diff --git a/app/views/projects/commit/_pipeline_stage.html.haml b/app/views/projects/commit/_pipeline_stage.html.haml new file mode 100644 index 00000000000..23c5c51fbc2 --- /dev/null +++ b/app/views/projects/commit/_pipeline_stage.html.haml @@ -0,0 +1,14 @@ +- status_groups = statuses.group_by(&:group_name) +- status_groups.each do |group_name, grouped_statuses| + - if grouped_statuses.one? + - status = grouped_statuses.first + - is_playable = status.playable? && can?(current_user, :update_build, @project) + %li.build{ class: ("playable" if is_playable) } + .curve + .build-content + = render "projects/#{status.to_partial_path}_pipeline", subject: status + - else + %li.build + .curve + .build-content + = render "projects/commit/pipeline_status_group", name: group_name, subject: grouped_statuses diff --git a/app/views/projects/commit/_pipeline_status_group.html.haml b/app/views/projects/commit/_pipeline_status_group.html.haml new file mode 100644 index 00000000000..4e7a6f1af08 --- /dev/null +++ b/app/views/projects/commit/_pipeline_status_group.html.haml @@ -0,0 +1,11 @@ +- group_status = CommitStatus.where(id: subject).status += render_status_with_link('build', group_status) +.dropdown.inline + %button.dropdown-menu-toggle{ type: 'button', data: { toggle: 'dropdown' } } + %span.ci-status-text + = name + %span.badge= subject.size + %ul.dropdown-menu.grouped-pipeline-dropdown + .arrow + - subject.each do |status| + = render "projects/#{status.to_partial_path}_pipeline", subject: status diff --git a/app/views/projects/edit.html.haml b/app/views/projects/edit.html.haml index f6d751a343e..a04d53e02bf 100644 --- a/app/views/projects/edit.html.haml +++ b/app/views/projects/edit.html.haml @@ -84,15 +84,14 @@ = project_feature_access_select(:snippets_access_level) - if Gitlab.config.lfs.enabled && current_user.admin? - .form-group - .checkbox - = f.label :lfs_enabled do - = f.check_box :lfs_enabled, checked: @project.lfs_enabled? - %strong LFS - %br - %span.descr - Git Large File Storage - = link_to icon('question-circle'), help_page_path('workflow/lfs/manage_large_binaries_with_git_lfs') + .row + .col-md-9 + = f.label :lfs_enabled, 'LFS', class: 'label-light' + %span.help-block + Git Large File Storage + = link_to icon('question-circle'), help_page_path('workflow/lfs/manage_large_binaries_with_git_lfs') + .col-md-3 + = f.select :lfs_enabled, [%w(Enabled true), %w(Disabled false)], {}, selected: @project.lfs_enabled?, class: 'pull-right form-control' - if Gitlab.config.registry.enabled .form-group diff --git a/app/views/projects/generic_commit_statuses/_generic_commit_status_pipeline.html.haml b/app/views/projects/generic_commit_statuses/_generic_commit_status_pipeline.html.haml index 576d0bec51b..409f4701e4b 100644 --- a/app/views/projects/generic_commit_statuses/_generic_commit_status_pipeline.html.haml +++ b/app/views/projects/generic_commit_statuses/_generic_commit_status_pipeline.html.haml @@ -1,10 +1,7 @@ -%li.build - .curve - .build-content - - if subject.target_url - - link_to subject.target_url do - = render_status_with_link('commit status', subject.status) - %span.ci-status-text= subject.name - - else - = render_status_with_link('commit status', subject.status) - %span.ci-status-text= subject.name +- if subject.target_url + = link_to subject.target_url do + = render_status_with_link('commit status', subject.status) + %span.ci-status-text= subject.name +- else + = render_status_with_link('commit status', subject.status) + %span.ci-status-text= subject.name diff --git a/app/views/projects/issues/_issue.html.haml b/app/views/projects/issues/_issue.html.haml index 851d4c06990..8b1a8a8a2d9 100644 --- a/app/views/projects/issues/_issue.html.haml +++ b/app/views/projects/issues/_issue.html.haml @@ -29,7 +29,7 @@ - note_count = issue.notes.user.count %li - = link_to issue_path(issue, anchor: 'notes'), class: ('issue-no-comments' if note_count.zero?) do + = link_to issue_path(issue, anchor: 'notes'), class: ('no-comments' if note_count.zero?) do = icon('comments') = note_count diff --git a/app/views/projects/merge_requests/_merge_request.html.haml b/app/views/projects/merge_requests/_merge_request.html.haml index 31f8d0aeb5b..68fb7d5a414 100644 --- a/app/views/projects/merge_requests/_merge_request.html.haml +++ b/app/views/projects/merge_requests/_merge_request.html.haml @@ -41,7 +41,7 @@ - note_count = merge_request.mr_and_commit_notes.user.count %li - = link_to merge_request_path(merge_request, anchor: 'notes'), class: ('merge-request-no-comments' if note_count.zero?) do + = link_to merge_request_path(merge_request, anchor: 'notes'), class: ('no-comments' if note_count.zero?) do = icon('comments') = note_count diff --git a/app/views/projects/pipelines/index.html.haml b/app/views/projects/pipelines/index.html.haml index 4d957e0d890..faf28db68d1 100644 --- a/app/views/projects/pipelines/index.html.haml +++ b/app/views/projects/pipelines/index.html.haml @@ -47,13 +47,7 @@ %tbody %th Status %th Commit - - stages.each do |stage| - %th.stage - - if stage.titleize.length > 12 - %span.has-tooltip{ title: "#{stage.titleize}" } - = stage.titleize - - else - = stage.titleize + %th Stages %th %th = render @pipelines, commit_sha: true, stage: true, allow_retry: true, stages: stages diff --git a/app/views/projects/snippets/_actions.html.haml b/app/views/projects/snippets/_actions.html.haml index bdbf3e5f4d6..a5a5619fa12 100644 --- a/app/views/projects/snippets/_actions.html.haml +++ b/app/views/projects/snippets/_actions.html.haml @@ -3,11 +3,11 @@ = link_to new_namespace_project_snippet_path(@project.namespace, @project), class: 'btn btn-grouped btn-create new-snippet-link', title: "New Snippet" do New Snippet - if can?(current_user, :update_project_snippet, @snippet) - = link_to edit_namespace_project_snippet_path(@project.namespace, @project, @snippet), class: "btn btn-grouped snippable-edit" do - Edit - - if can?(current_user, :update_project_snippet, @snippet) = link_to namespace_project_snippet_path(@project.namespace, @project, @snippet), method: :delete, data: { confirm: "Are you sure?" }, class: "btn btn-grouped btn-warning", title: 'Delete Snippet' do Delete + - if can?(current_user, :update_project_snippet, @snippet) + = link_to edit_namespace_project_snippet_path(@project.namespace, @project, @snippet), class: "btn btn-grouped snippable-edit" do + Edit - if can?(current_user, :create_project_snippet, @project) || can?(current_user, :update_project_snippet, @snippet) .visible-xs-block.dropdown %button.btn.btn-default.btn-block.append-bottom-0.prepend-top-5{ data: { toggle: "dropdown" } } @@ -21,9 +21,9 @@ New Snippet - if can?(current_user, :update_project_snippet, @snippet) %li - = link_to edit_namespace_project_snippet_path(@project.namespace, @project, @snippet) do - Edit - - if can?(current_user, :update_project_snippet, @snippet) - %li = link_to namespace_project_snippet_path(@project.namespace, @project, @snippet), method: :delete, data: { confirm: "Are you sure?" }, title: 'Delete Snippet' do Delete + - if can?(current_user, :update_project_snippet, @snippet) + %li + = link_to edit_namespace_project_snippet_path(@project.namespace, @project, @snippet) do + Edit diff --git a/app/views/projects/snippets/show.html.haml b/app/views/projects/snippets/show.html.haml index bae4d8f349f..b70fda88a79 100644 --- a/app/views/projects/snippets/show.html.haml +++ b/app/views/projects/snippets/show.html.haml @@ -1,15 +1,14 @@ - page_title @snippet.title, "Snippets" -.snippet-holder - = render 'shared/snippets/header' += render 'shared/snippets/header' - %article.file-holder.file-holder-no-border.snippet-file-content - .file-title.file-title-clear - = blob_icon 0, @snippet.file_name - = @snippet.file_name - .file-actions.hidden-xs - = clipboard_button(clipboard_target: ".blob-content[data-blob-id='#{@snippet.id}']") - = link_to 'Raw', raw_namespace_project_snippet_path(@project.namespace, @project, @snippet), class: "btn btn-sm", target: "_blank" - = render 'shared/snippets/blob' +%article.file-holder.snippet-file-content + .file-title + = blob_icon 0, @snippet.file_name + = @snippet.file_name + .file-actions + = clipboard_button(clipboard_target: ".blob-content[data-blob-id='#{@snippet.id}']") + = link_to 'Raw', raw_namespace_project_snippet_path(@project.namespace, @project, @snippet), class: "btn btn-sm", target: "_blank" + = render 'shared/snippets/blob' - %div#notes= render "projects/notes/notes_with_form" +%div#notes= render "projects/notes/notes_with_form" diff --git a/app/views/projects/tree/_readme.html.haml b/app/views/projects/tree/_readme.html.haml index baaa2caa6de..a1f4e3e8ed6 100644 --- a/app/views/projects/tree/_readme.html.haml +++ b/app/views/projects/tree/_readme.html.haml @@ -1,7 +1,7 @@ %article.file-holder.readme-holder .file-title = blob_icon readme.mode, readme.name - = link_to namespace_project_blob_path(@project.namespace, @project, tree_join(@repository.root_ref, @path, readme.name)) do + = link_to namespace_project_blob_path(@project.namespace, @project, tree_join(@ref, @path, readme.name)) do %strong = readme.name .file-content.wiki diff --git a/app/views/projects/variables/_table.html.haml b/app/views/projects/variables/_table.html.haml index 6c43f822db4..07cee86ba4c 100644 --- a/app/views/projects/variables/_table.html.haml +++ b/app/views/projects/variables/_table.html.haml @@ -9,7 +9,7 @@ %th Value %th %tbody - - @project.variables.each do |variable| + - @project.variables.order_key_asc.each do |variable| - if variable.id? %tr %td= variable.key diff --git a/app/views/shared/_visibility_level.html.haml b/app/views/shared/_visibility_level.html.haml index 107ad19177c..add4536a0a2 100644 --- a/app/views/shared/_visibility_level.html.haml +++ b/app/views/shared/_visibility_level.html.haml @@ -1,7 +1,7 @@ .form-group.project-visibility-level-holder = f.label :visibility_level, class: 'control-label' do Visibility Level - = link_to "(?)", help_page_path("public_access/public_access") + = link_to icon('question-circle'), help_page_path("public_access/public_access") .col-sm-10 - if can_change_visibility_level = render('shared/visibility_radios', model_method: :visibility_level, form: f, selected_level: visibility_level, form_model: form_model) diff --git a/app/views/shared/issuable/_form.html.haml b/app/views/shared/issuable/_form.html.haml index 3856a4917b4..04373684ee9 100644 --- a/app/views/shared/issuable/_form.html.haml +++ b/app/views/shared/issuable/_form.html.haml @@ -19,7 +19,7 @@ = dropdown_tag(title, options: { toggle_class: 'js-issuable-selector', title: title, filter: true, placeholder: 'Filter', footer_content: true, - data: { data: issuable_template_names, field_name: 'issuable_template', selected: selected_template(issuable), project_path: @project.path, namespace_path: @project.namespace.path } } ) do + data: { data: issuable_template_names, field_name: 'issuable_template', selected: selected_template(issuable), project_path: ref_project.path, namespace_path: ref_project.namespace.path } } ) do %ul.dropdown-footer-list %li %a.reset-template diff --git a/app/views/shared/snippets/_header.html.haml b/app/views/shared/snippets/_header.html.haml index af753496260..7ae4211ddfd 100644 --- a/app/views/shared/snippets/_header.html.haml +++ b/app/views/shared/snippets/_header.html.haml @@ -6,12 +6,13 @@ %strong.item-title Snippet #{@snippet.to_reference} %span.creator - created by #{link_to_member(@project, @snippet.author, size: 24, author_class: "author item-title")} + authored = time_ago_with_tooltip(@snippet.created_at, placement: 'bottom', html_class: 'snippet_updated_ago') - if @snippet.updated_at != @snippet.created_at %span = icon('edit', title: 'edited') = time_ago_with_tooltip(@snippet.updated_at, placement: 'bottom', html_class: 'snippet_edited_ago') + by #{link_to_member(@project, @snippet.author, size: 24, author_class: "author item-title", avatar_class: "hidden-xs")} .snippet-actions - if @snippet.project_id? @@ -19,6 +20,5 @@ - else = render "snippets/actions" -.content-block.second-block - %h2.snippet-title.prepend-top-0.append-bottom-0 - = markdown escape_once(@snippet.title), pipeline: :single_line, author: @snippet.author +%h2.snippet-title.prepend-top-0.append-bottom-0 + = markdown escape_once(@snippet.title), pipeline: :single_line, author: @snippet.author diff --git a/app/views/shared/snippets/_snippet.html.haml b/app/views/shared/snippets/_snippet.html.haml index c96dfefe17f..ea17bec8677 100644 --- a/app/views/shared/snippets/_snippet.html.haml +++ b/app/views/shared/snippets/_snippet.html.haml @@ -3,19 +3,30 @@ .title = link_to reliable_snippet_path(snippet) do - = truncate(snippet.title, length: 60) + = snippet.title - if snippet.private? - %span.label.label-gray + %span.label.label-gray.hidden-xs = icon('lock') private - %span.monospace.pull-right + %span.monospace.pull-right.hidden-xs = snippet.file_name - %small.pull-right.cgray + %ul.controls.visible-xs + %li + - note_count = snippet.notes.user.count + = link_to reliable_snippet_path(snippet, anchor: 'notes'), class: ('no-comments' if note_count.zero?) do + = icon('comments') + = note_count + %li + %span.sr-only + = visibility_level_label(snippet.visibility_level) + = visibility_level_icon(snippet.visibility_level, fw: false) + + %small.pull-right.cgray.hidden-xs - if snippet.project_id? = link_to snippet.project.name_with_namespace, namespace_project_path(snippet.project.namespace, snippet.project) - .snippet-info + .snippet-info.hidden-xs = link_to user_snippets_path(snippet.author) do = snippet.author_name authored #{time_ago_with_tooltip(snippet.created_at)} diff --git a/app/views/snippets/_actions.html.haml b/app/views/snippets/_actions.html.haml index 160c6cd84da..fdaca199218 100644 --- a/app/views/snippets/_actions.html.haml +++ b/app/views/snippets/_actions.html.haml @@ -2,12 +2,12 @@ - if current_user = link_to new_snippet_path, class: "btn btn-grouped btn-create new-snippet-link", title: "New Snippet" do New Snippet - - if can?(current_user, :update_personal_snippet, @snippet) - = link_to edit_snippet_path(@snippet), class: "btn btn-grouped snippable-edit" do - Edit - if can?(current_user, :admin_personal_snippet, @snippet) = link_to snippet_path(@snippet), method: :delete, data: { confirm: "Are you sure?" }, class: "btn btn-grouped btn-danger", title: 'Delete Snippet' do Delete + - if can?(current_user, :update_personal_snippet, @snippet) + = link_to edit_snippet_path(@snippet), class: "btn btn-grouped snippable-edit" do + Edit - if current_user .visible-xs-block.dropdown %button.btn.btn-default.btn-block.append-bottom-0.prepend-top-5{ data: { toggle: "dropdown" } } @@ -18,11 +18,11 @@ %li = link_to new_snippet_path, title: "New Snippet" do New Snippet - - if can?(current_user, :update_personal_snippet, @snippet) - %li - = link_to edit_snippet_path(@snippet) do - Edit - if can?(current_user, :admin_personal_snippet, @snippet) %li = link_to snippet_path(@snippet), method: :delete, data: { confirm: "Are you sure?" }, title: 'Delete Snippet' do Delete + - if can?(current_user, :update_personal_snippet, @snippet) + %li + = link_to edit_snippet_path(@snippet) do + Edit diff --git a/app/views/snippets/show.html.haml b/app/views/snippets/show.html.haml index ed3992650d4..fa403da8f79 100644 --- a/app/views/snippets/show.html.haml +++ b/app/views/snippets/show.html.haml @@ -1,13 +1,12 @@ - page_title @snippet.title, "Snippets" -.snippet-holder - = render 'shared/snippets/header' += render 'shared/snippets/header' - %article.file-holder.file-holder-no-border.snippet-file-content - .file-title.file-title-clear - = blob_icon 0, @snippet.file_name - = @snippet.file_name - .file-actions.hidden-xs - = clipboard_button(clipboard_target: ".blob-content[data-blob-id='#{@snippet.id}']") - = link_to 'Raw', raw_snippet_path(@snippet), class: "btn btn-sm", target: "_blank" - = render 'shared/snippets/blob' +%article.file-holder.snippet-file-content + .file-title + = blob_icon 0, @snippet.file_name + = @snippet.file_name + .file-actions + = clipboard_button(clipboard_target: ".blob-content[data-blob-id='#{@snippet.id}']") + = link_to 'Raw', raw_snippet_path(@snippet), class: "btn btn-sm", target: "_blank" + = render 'shared/snippets/blob' diff --git a/db/fixtures/development/14_pipelines.rb b/db/fixtures/development/14_pipelines.rb index 49e6e2361b1..650b410595c 100644 --- a/db/fixtures/development/14_pipelines.rb +++ b/db/fixtures/development/14_pipelines.rb @@ -3,9 +3,13 @@ class Gitlab::Seeder::Pipelines BUILDS = [ { name: 'build:linux', stage: 'build', status: :success }, { name: 'build:osx', stage: 'build', status: :success }, - { name: 'rspec:linux', stage: 'test', status: :success }, - { name: 'rspec:windows', stage: 'test', status: :success }, - { name: 'rspec:windows', stage: 'test', status: :success }, + { name: 'rspec:linux 0 3', stage: 'test', status: :success }, + { name: 'rspec:linux 1 3', stage: 'test', status: :success }, + { name: 'rspec:linux 2 3', stage: 'test', status: :success }, + { name: 'rspec:windows 0 3', stage: 'test', status: :success }, + { name: 'rspec:windows 1 3', stage: 'test', status: :success }, + { name: 'rspec:windows 2 3', stage: 'test', status: :success }, + { name: 'rspec:windows 2 3', stage: 'test', status: :success }, { name: 'rspec:osx', stage: 'test', status_event: :success }, { name: 'spinach:linux', stage: 'test', status: :success }, { name: 'spinach:osx', stage: 'test', status: :failed, allow_failure: true}, diff --git a/db/migrate/20140502125220_migrate_repo_size.rb b/db/migrate/20140502125220_migrate_repo_size.rb index 84463727b3b..e8de7ccf3db 100644 --- a/db/migrate/20140502125220_migrate_repo_size.rb +++ b/db/migrate/20140502125220_migrate_repo_size.rb @@ -1,12 +1,15 @@ # rubocop:disable all class MigrateRepoSize < ActiveRecord::Migration + DOWNTIME = false + def up project_data = execute('SELECT projects.id, namespaces.path AS namespace_path, projects.path AS project_path FROM projects LEFT JOIN namespaces ON projects.namespace_id = namespaces.id') project_data.each do |project| id = project['id'] namespace_path = project['namespace_path'] || '' - path = File.join(Gitlab.config.gitlab_shell.repos_path, namespace_path, project['project_path'] + '.git') + repos_path = Gitlab.config.gitlab_shell['repos_path'] || Gitlab.config.repositories.storages.default + path = File.join(repos_path, namespace_path, project['project_path'] + '.git') begin repo = Gitlab::Git::Repository.new(path) diff --git a/db/migrate/20160901213340_add_lfs_enabled_to_namespaces.rb b/db/migrate/20160901213340_add_lfs_enabled_to_namespaces.rb new file mode 100644 index 00000000000..fd413d1ca8c --- /dev/null +++ b/db/migrate/20160901213340_add_lfs_enabled_to_namespaces.rb @@ -0,0 +1,12 @@ +# See http://doc.gitlab.com/ce/development/migration_style_guide.html +# for more information on how to write migrations for GitLab. + +class AddLfsEnabledToNamespaces < ActiveRecord::Migration + include Gitlab::Database::MigrationHelpers + + DOWNTIME = false + + def change + add_column :namespaces, :lfs_enabled, :boolean + end +end diff --git a/db/migrate/20160913162434_remove_projects_pushes_since_gc.rb b/db/migrate/20160913162434_remove_projects_pushes_since_gc.rb index c5b8c35e961..18ea9d43a43 100644 --- a/db/migrate/20160913162434_remove_projects_pushes_since_gc.rb +++ b/db/migrate/20160913162434_remove_projects_pushes_since_gc.rb @@ -14,6 +14,6 @@ class RemoveProjectsPushesSinceGc < ActiveRecord::Migration end def down - add_column_with_default! :projects, :pushes_since_gc, :integer, default: 0 + add_column_with_default :projects, :pushes_since_gc, :integer, default: 0 end end diff --git a/db/migrate/20160913212128_change_artifacts_size_column.rb b/db/migrate/20160913212128_change_artifacts_size_column.rb new file mode 100644 index 00000000000..063bbca537c --- /dev/null +++ b/db/migrate/20160913212128_change_artifacts_size_column.rb @@ -0,0 +1,15 @@ +class ChangeArtifactsSizeColumn < ActiveRecord::Migration + include Gitlab::Database::MigrationHelpers + + DOWNTIME = true + + DOWNTIME_REASON = 'Changing an integer column size requires a full table rewrite.' + + def up + change_column :ci_builds, :artifacts_size, :integer, limit: 8 + end + + def down + # do nothing + end +end diff --git a/db/schema.rb b/db/schema.rb index 61873e38113..974f5855cf9 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: 20160913162434) do +ActiveRecord::Schema.define(version: 20160913212128) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -177,7 +177,7 @@ ActiveRecord::Schema.define(version: 20160913162434) do t.datetime "erased_at" t.datetime "artifacts_expire_at" t.string "environment" - t.integer "artifacts_size" + t.integer "artifacts_size", limit: 8 t.string "when" t.text "yaml_variables" t.datetime "queued_at" @@ -650,6 +650,7 @@ ActiveRecord::Schema.define(version: 20160913162434) do t.integer "visibility_level", default: 20, null: false t.boolean "request_access_enabled", default: true, null: false t.datetime "deleted_at" + t.boolean "lfs_enabled" end add_index "namespaces", ["created_at"], name: "index_namespaces_on_created_at", using: :btree diff --git a/doc/api/groups.md b/doc/api/groups.md index a898387eaa2..3e94e1e4efe 100644 --- a/doc/api/groups.md +++ b/doc/api/groups.md @@ -288,6 +288,7 @@ Parameters: - `path` (required) - The path of the group - `description` (optional) - The group's description - `visibility_level` (optional) - The group's visibility. 0 for private, 10 for internal, 20 for public. +- `lfs_enabled` (optional) - Enable/disable Large File Storage (LFS) for the projects in this group ## Transfer project to group @@ -317,6 +318,7 @@ PUT /groups/:id | `path` | string | no | The path of the group | | `description` | string | no | The description of the group | | `visibility_level` | integer | no | The visibility level of the group. 0 for private, 10 for internal, 20 for public. | +| `lfs_enabled` (optional) | boolean | no | Enable/disable Large File Storage (LFS) for the projects in this group | ```bash curl --request PUT --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v3/groups/5?name=Experimental" diff --git a/doc/ci/quick_start/README.md b/doc/ci/quick_start/README.md index c835ebc2d44..c40cdd55ea5 100644 --- a/doc/ci/quick_start/README.md +++ b/doc/ci/quick_start/README.md @@ -105,7 +105,8 @@ What is important is that each job is run independently from each other. If you want to check whether your `.gitlab-ci.yml` file is valid, there is a Lint tool under the page `/ci/lint` of your GitLab instance. You can also find -the link under **Settings > CI settings** in your project. +a "CI Lint" button to go to this page under **Pipelines > Pipelines** and +**Pipelines > Builds** in your project. For more information and a complete `.gitlab-ci.yml` syntax, please read [the documentation on .gitlab-ci.yml](../yaml/README.md). diff --git a/doc/development/migration_style_guide.md b/doc/development/migration_style_guide.md index b8fab3aaff7..295eae0a88e 100644 --- a/doc/development/migration_style_guide.md +++ b/doc/development/migration_style_guide.md @@ -111,6 +111,28 @@ class MyMigration < ActiveRecord::Migration end ``` + +## Integer column type + +By default, an integer column can hold up to a 4-byte (32-bit) number. That is +a max value of 2,147,483,647. Be aware of this when creating a column that will +hold file sizes in byte units. If you are tracking file size in bytes this +restricts the maximum file size to just over 2GB. + +To allow an integer column to hold up to an 8-byte (64-bit) number, explicitly +set the limit to 8-bytes. This will allow the column to hold a value up to +9,223,372,036,854,775,807. + +Rails migration example: + +``` +add_column_with_default(:projects, :foo, :integer, default: 10, limit: 8) + +# or + +add_column(:projects, :foo, :integer, default: 10, limit: 8) +``` + ## Testing Make sure that your migration works with MySQL and PostgreSQL with data. An empty database does not guarantee that your migration is correct. diff --git a/doc/user/permissions.md b/doc/user/permissions.md index 1498cb361c8..f1b75298180 100644 --- a/doc/user/permissions.md +++ b/doc/user/permissions.md @@ -63,7 +63,7 @@ The following table depicts the various user permission levels in a project. | Force push to protected branches [^2] | | | | | | | Remove protected branches [^2] | | | | | | -[^1]: If **Allow guest to access builds** is enabled in CI settings +[^1]: If **Public pipelines** is enabled in **Project Settings > CI/CD Pipelines** [^2]: Not allowed for Guest, Reporter, Developer, Master, or Owner ## Group diff --git a/lib/api/entities.rb b/lib/api/entities.rb index 4f736e4ec2b..bfee4b6c752 100644 --- a/lib/api/entities.rb +++ b/lib/api/entities.rb @@ -86,7 +86,8 @@ module API expose(:snippets_enabled) { |project, options| project.feature_available?(:snippets, options[:user]) } expose :created_at, :last_activity_at - expose :shared_runners_enabled, :lfs_enabled + expose :shared_runners_enabled + expose :lfs_enabled?, as: :lfs_enabled expose :creator_id expose :namespace expose :forked_from_project, using: Entities::BasicProjectDetails, if: lambda{ |project, options| project.forked? } @@ -121,6 +122,7 @@ module API class Group < Grape::Entity expose :id, :name, :path, :description, :visibility_level + expose :lfs_enabled?, as: :lfs_enabled expose :avatar_url expose :web_url end diff --git a/lib/api/groups.rb b/lib/api/groups.rb index d2df77238d5..60ac9bdfa33 100644 --- a/lib/api/groups.rb +++ b/lib/api/groups.rb @@ -27,13 +27,14 @@ module API # path (required) - The path of the group # description (optional) - The description of the group # visibility_level (optional) - The visibility level of the group + # lfs_enabled (optional) - Enable/disable LFS for the projects in this group # Example Request: # POST /groups post do authorize! :create_group required_attributes! [:name, :path] - attrs = attributes_for_keys [:name, :path, :description, :visibility_level] + attrs = attributes_for_keys [:name, :path, :description, :visibility_level, :lfs_enabled] @group = Group.new(attrs) if @group.save @@ -51,13 +52,14 @@ module API # path (optional) - The path of the group # description (optional) - The description of the group # visibility_level (optional) - The visibility level of the group + # lfs_enabled (optional) - Enable/disable LFS for the projects in this group # Example Request: # PUT /groups/:id put ':id' do group = find_group(params[:id]) authorize! :admin_group, group - attrs = attributes_for_keys [:name, :path, :description, :visibility_level] + attrs = attributes_for_keys [:name, :path, :description, :visibility_level, :lfs_enabled] if ::Groups::UpdateService.new(group, current_user, attrs).execute present group, with: Entities::GroupDetail 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/gitlab/database/migration_helpers.rb b/lib/gitlab/database/migration_helpers.rb index 927f9dad20b..0bd6e148ba8 100644 --- a/lib/gitlab/database/migration_helpers.rb +++ b/lib/gitlab/database/migration_helpers.rb @@ -129,12 +129,14 @@ module Gitlab # column - The name of the column to add. # type - The column type (e.g. `:integer`). # default - The default value for the column. + # limit - Sets a column limit. For example, for :integer, the default is + # 4-bytes. Set `limit: 8` to allow 8-byte integers. # allow_null - When set to `true` the column will allow NULL values, the # default is to not allow NULL values. # # This method can also take a block which is passed directly to the # `update_column_in_batches` method. - def add_column_with_default(table, column, type, default:, allow_null: false, &block) + def add_column_with_default(table, column, type, default:, limit: nil, allow_null: false, &block) if transaction_open? raise 'add_column_with_default can not be run inside a transaction, ' \ 'you can disable transactions by calling disable_ddl_transaction! ' \ @@ -144,7 +146,11 @@ module Gitlab disable_statement_timeout transaction do - add_column(table, column, type, default: nil) + if limit + add_column(table, column, type, default: nil, limit: limit) + else + add_column(table, column, type, default: nil) + end # Changing the default before the update ensures any newly inserted # rows already use the proper default value. 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/import_export/repo_restorer.rb b/lib/gitlab/import_export/repo_restorer.rb index 6d9379acf25..d1e33ea8678 100644 --- a/lib/gitlab/import_export/repo_restorer.rb +++ b/lib/gitlab/import_export/repo_restorer.rb @@ -22,10 +22,6 @@ module Gitlab private - def repos_path - Gitlab.config.gitlab_shell.repos_path - end - def path_to_repo @project.repository.path_to_repo end diff --git a/spec/factories/ci/runner_projects.rb b/spec/factories/ci/runner_projects.rb index 83fccad679f..3372e5ab685 100644 --- a/spec/factories/ci/runner_projects.rb +++ b/spec/factories/ci/runner_projects.rb @@ -1,14 +1,3 @@ -# == Schema Information -# -# Table name: runner_projects -# -# id :integer not null, primary key -# runner_id :integer not null -# project_id :integer not null -# created_at :datetime -# updated_at :datetime -# - FactoryGirl.define do factory :ci_runner_project, class: Ci::RunnerProject do runner_id 1 diff --git a/spec/factories/ci/runners.rb b/spec/factories/ci/runners.rb index 45eaebb2576..e3b73e29987 100644 --- a/spec/factories/ci/runners.rb +++ b/spec/factories/ci/runners.rb @@ -1,22 +1,3 @@ -# == Schema Information -# -# Table name: runners -# -# id :integer not null, primary key -# token :string(255) -# created_at :datetime -# updated_at :datetime -# description :string(255) -# contacted_at :datetime -# active :boolean default(TRUE), not null -# is_shared :boolean default(FALSE) -# name :string(255) -# version :string(255) -# revision :string(255) -# platform :string(255) -# architecture :string(255) -# - FactoryGirl.define do factory :ci_runner, class: Ci::Runner do sequence :description do |n| diff --git a/spec/factories/ci/variables.rb b/spec/factories/ci/variables.rb index 856a8e725eb..6653f0bb5c3 100644 --- a/spec/factories/ci/variables.rb +++ b/spec/factories/ci/variables.rb @@ -1,17 +1,3 @@ -# == Schema Information -# -# Table name: ci_variables -# -# id :integer not null, primary key -# project_id :integer not null -# key :string(255) -# value :text -# encrypted_value :text -# encrypted_value_salt :string(255) -# encrypted_value_iv :string(255) -# gl_project_id :integer -# - FactoryGirl.define do factory :ci_variable, class: Ci::Variable do sequence(:key) { |n| "VARIABLE_#{n}" } diff --git a/spec/factories/group_members.rb b/spec/factories/group_members.rb index debb86d997f..2044ebec09a 100644 --- a/spec/factories/group_members.rb +++ b/spec/factories/group_members.rb @@ -1,16 +1,3 @@ -# == Schema Information -# -# Table name: group_members -# -# id :integer not null, primary key -# group_access :integer not null -# group_id :integer not null -# user_id :integer not null -# created_at :datetime -# updated_at :datetime -# notification_level :integer default(3), not null -# - FactoryGirl.define do factory :group_member do access_level { GroupMember::OWNER } diff --git a/spec/features/boards/boards_spec.rb b/spec/features/boards/boards_spec.rb index c6c2e2095df..e51586d32ec 100644 --- a/spec/features/boards/boards_spec.rb +++ b/spec/features/boards/boards_spec.rb @@ -2,6 +2,7 @@ require 'rails_helper' describe 'Issue Boards', feature: true, js: true do include WaitForAjax + include WaitForVueResource let(:project) { create(:empty_project, :public) } let(:user) { create(:user) } @@ -187,13 +188,13 @@ describe 'Issue Boards', feature: true, js: true do expect(page).to have_content('Showing 20 of 56 issues') evaluate_script("document.querySelectorAll('.board .board-list')[0].scrollTop = document.querySelectorAll('.board .board-list')[0].scrollHeight") - wait_for_vue_resource(spinner: false) + wait_for_vue_resource expect(page).to have_selector('.card', count: 40) expect(page).to have_content('Showing 40 of 56 issues') evaluate_script("document.querySelectorAll('.board .board-list')[0].scrollTop = document.querySelectorAll('.board .board-list')[0].scrollHeight") - wait_for_vue_resource(spinner: false) + wait_for_vue_resource expect(page).to have_selector('.card', count: 56) expect(page).to have_content('Showing all issues') @@ -372,7 +373,7 @@ describe 'Issue Boards', feature: true, js: true do page.within '.dropdown-menu-author' do click_link(user2.name) end - wait_for_vue_resource(spinner: false) + wait_for_vue_resource expect(find('.js-author-search')).to have_content(user2.name) end @@ -398,7 +399,7 @@ describe 'Issue Boards', feature: true, js: true do page.within '.dropdown-menu-assignee' do click_link(user.name) end - wait_for_vue_resource(spinner: false) + wait_for_vue_resource expect(find('.js-assignee-search')).to have_content(user.name) end @@ -424,7 +425,7 @@ describe 'Issue Boards', feature: true, js: true do page.within '.milestone-filter' do click_link(milestone.title) end - wait_for_vue_resource(spinner: false) + wait_for_vue_resource expect(find('.js-milestone-select')).to have_content(milestone.title) end @@ -449,7 +450,7 @@ describe 'Issue Boards', feature: true, js: true do page.within '.dropdown-menu-labels' do click_link(testing.title) - wait_for_vue_resource(spinner: false) + wait_for_vue_resource find('.dropdown-menu-close').click end end @@ -478,7 +479,7 @@ describe 'Issue Boards', feature: true, js: true do page.within '.dropdown-menu-labels' do click_link(testing.title) - wait_for_vue_resource(spinner: false) + wait_for_vue_resource find('.dropdown-menu-close').click end end @@ -509,9 +510,9 @@ describe 'Issue Boards', feature: true, js: true do page.within(find('.dropdown-menu-labels')) do click_link(testing.title) - wait_for_vue_resource(spinner: false) + wait_for_vue_resource click_link(bug.title) - wait_for_vue_resource(spinner: false) + wait_for_vue_resource find('.dropdown-menu-close').click end end @@ -536,7 +537,7 @@ describe 'Issue Boards', feature: true, js: true do page.within '.dropdown-menu-labels' do click_link("No Label") - wait_for_vue_resource(spinner: false) + wait_for_vue_resource find('.dropdown-menu-close').click end end @@ -559,7 +560,7 @@ describe 'Issue Boards', feature: true, js: true do expect(page).to have_selector('.card', count: 6) expect(find('.card', match: :first)).to have_content(bug.title) click_button(bug.title) - wait_for_vue_resource(spinner: false) + wait_for_vue_resource end wait_for_vue_resource @@ -584,7 +585,7 @@ describe 'Issue Boards', feature: true, js: true do page.within(find('.card', match: :first)) do click_button(bug.title) end - wait_for_vue_resource(spinner: false) + wait_for_vue_resource expect(page).to have_selector('.card', count: 1) end @@ -647,14 +648,4 @@ describe 'Issue Boards', feature: true, js: true do wait_for_vue_resource end - - def wait_for_vue_resource(spinner: true) - Timeout.timeout(Capybara.default_max_wait_time) do - loop until page.evaluate_script('Vue.activeResources').zero? - end - - if spinner - expect(find('.boards-list')).not_to have_selector('.fa-spinner') - end - end end diff --git a/spec/features/boards/keyboard_shortcut_spec.rb b/spec/features/boards/keyboard_shortcut_spec.rb new file mode 100644 index 00000000000..7ef68e9eb8d --- /dev/null +++ b/spec/features/boards/keyboard_shortcut_spec.rb @@ -0,0 +1,24 @@ +require 'rails_helper' + +describe 'Issue Boards shortcut', feature: true, js: true do + include WaitForVueResource + + let(:project) { create(:empty_project) } + + before do + project.create_board + project.board.lists.create(list_type: :backlog) + project.board.lists.create(list_type: :done) + + login_as :admin + + visit namespace_project_path(project.namespace, project) + end + + it 'takes user to issue board index' do + find('body').native.send_keys('gl') + expect(page).to have_selector('.boards-list') + + wait_for_vue_resource + end +end diff --git a/spec/features/issues_spec.rb b/spec/features/issues_spec.rb index d744d0eb6af..22359c8f938 100644 --- a/spec/features/issues_spec.rb +++ b/spec/features/issues_spec.rb @@ -144,7 +144,7 @@ describe 'Issues', feature: true do visit namespace_project_issues_path(project.namespace, project, assignee_id: @user.id) expect(page).to have_content 'foobar' - expect(page.all('.issue-no-comments').first.text).to eq "0" + expect(page.all('.no-comments').first.text).to eq "0" end end diff --git a/spec/features/projects/issuable_templates_spec.rb b/spec/features/projects/issuable_templates_spec.rb index 4a83740621a..f76c4fe8b57 100644 --- a/spec/features/projects/issuable_templates_spec.rb +++ b/spec/features/projects/issuable_templates_spec.rb @@ -13,10 +13,12 @@ feature 'issuable templates', feature: true, js: true do context 'user creates an issue using templates' do let(:template_content) { 'this is a test "bug" template' } + let(:longtemplate_content) { %Q(this\n\n\n\n\nis\n\n\n\n\na\n\n\n\n\nbug\n\n\n\n\ntemplate) } let(:issue) { create(:issue, author: user, assignee: user, project: project) } background do project.repository.commit_file(user, '.gitlab/issue_templates/bug.md', template_content, 'added issue template', 'master', false) + project.repository.commit_file(user, '.gitlab/issue_templates/test.md', longtemplate_content, 'added issue template', 'master', false) visit edit_namespace_project_issue_path project.namespace, project, issue fill_in :'issue[title]', with: 'test issue title' end @@ -27,6 +29,17 @@ feature 'issuable templates', feature: true, js: true do preview_template save_changes end + + it 'updates height of markdown textarea' do + start_height = page.evaluate_script('$(".markdown-area").outerHeight()') + + select_template 'test' + wait_for_ajax + + end_height = page.evaluate_script('$(".markdown-area").outerHeight()') + + expect(end_height).not_to eq(start_height) + end end context 'user creates a merge request using templates' do @@ -51,7 +64,7 @@ feature 'issuable templates', feature: true, js: true do let(:template_content) { 'this is a test "feature-proposal" template' } let(:fork_user) { create(:user) } let(:fork_project) { create(:project, :public) } - let(:merge_request) { create(:merge_request, :with_diffs, source_project: fork_project) } + let(:merge_request) { create(:merge_request, :with_diffs, source_project: fork_project, target_project: project) } background do logout @@ -59,16 +72,20 @@ feature 'issuable templates', feature: true, js: true do fork_project.team << [fork_user, :master] create(:forked_project_link, forked_to_project: fork_project, forked_from_project: project) login_as fork_user - fork_project.repository.commit_file(fork_user, '.gitlab/merge_request_templates/feature-proposal.md', template_content, 'added merge request template', 'master', false) - visit edit_namespace_project_merge_request_path fork_project.namespace, fork_project, merge_request + project.repository.commit_file(fork_user, '.gitlab/merge_request_templates/feature-proposal.md', template_content, 'added merge request template', 'master', false) + visit edit_namespace_project_merge_request_path project.namespace, project, merge_request fill_in :'merge_request[title]', with: 'test merge request title' end - scenario 'user selects "feature-proposal" template' do - select_template 'feature-proposal' - wait_for_ajax - preview_template - save_changes + context 'feature proposal template' do + context 'template exists in target project' do + scenario 'user selects template' do + select_template 'feature-proposal' + wait_for_ajax + preview_template + save_changes + end + end end end diff --git a/spec/features/todos/todos_filtering_spec.rb b/spec/features/todos/todos_filtering_spec.rb index 83cf306437d..b9e66243d84 100644 --- a/spec/features/todos/todos_filtering_spec.rb +++ b/spec/features/todos/todos_filtering_spec.rb @@ -29,8 +29,11 @@ describe 'Dashboard > User filters todos', feature: true, js: true do fill_in 'Search projects', with: project_1.name_with_namespace click_link project_1.name_with_namespace end + wait_for_ajax - expect('.prepend-top-default').not_to have_content project_2.name_with_namespace + + expect(page).to have_content project_1.name_with_namespace + expect(page).not_to have_content project_2.name_with_namespace end it 'filters by author' do @@ -39,8 +42,11 @@ describe 'Dashboard > User filters todos', feature: true, js: true do fill_in 'Search authors', with: user_1.name click_link user_1.name end + wait_for_ajax - expect('.prepend-top-default').not_to have_content user_2.name + + expect(find('.todos-list')).to have_content user_1.name + expect(find('.todos-list')).not_to have_content user_2.name end it 'filters by type' do @@ -48,8 +54,11 @@ describe 'Dashboard > User filters todos', feature: true, js: true do within '.dropdown-menu-type' do click_link 'Issue' end + wait_for_ajax - expect('.prepend-top-default').not_to have_content ' merge request !' + + expect(find('.todos-list')).to have_content issue.to_reference + expect(find('.todos-list')).not_to have_content merge_request.to_reference end it 'filters by action' do @@ -57,7 +66,10 @@ describe 'Dashboard > User filters todos', feature: true, js: true do within '.dropdown-menu-action' do click_link 'Assigned' end + wait_for_ajax - expect('.prepend-top-default').not_to have_content ' mentioned ' + + expect(find('.todos-list')).to have_content ' assigned you ' + expect(find('.todos-list')).not_to have_content ' mentioned ' end end diff --git a/spec/features/users/snippets_spec.rb b/spec/features/users/snippets_spec.rb index 356a8d668b0..f00abd82fea 100644 --- a/spec/features/users/snippets_spec.rb +++ b/spec/features/users/snippets_spec.rb @@ -19,7 +19,10 @@ describe 'Snippets tab on a user profile', feature: true, js: true do end context 'clicking on the link to the second page' do - before { click_link('2') } + before do + click_link('2') + wait_for_ajax + end it 'shows the remaining snippets' do expect(page.all('.snippets-list-holder .snippet-row').count).to eq(5) diff --git a/spec/helpers/groups_helper_spec.rb b/spec/helpers/groups_helper_spec.rb index 0807534720a..233d00534e5 100644 --- a/spec/helpers/groups_helper_spec.rb +++ b/spec/helpers/groups_helper_spec.rb @@ -18,4 +18,67 @@ describe GroupsHelper do expect(group_icon(group.path)).to match('group_avatar.png') end end + + describe 'group_lfs_status' do + let(:group) { create(:group) } + let!(:project) { create(:empty_project, namespace_id: group.id) } + + before do + allow(Gitlab.config.lfs).to receive(:enabled).and_return(true) + end + + context 'only one project in group' do + before do + group.update_attribute(:lfs_enabled, true) + end + + it 'returns all projects as enabled' do + expect(group_lfs_status(group)).to include('Enabled for all projects') + end + + it 'returns all projects as disabled' do + project.update_attribute(:lfs_enabled, false) + + expect(group_lfs_status(group)).to include('Enabled for 0 out of 1 project') + end + end + + context 'more than one project in group' do + before do + create(:empty_project, namespace_id: group.id) + end + + context 'LFS enabled in group' do + before do + group.update_attribute(:lfs_enabled, true) + end + + it 'returns both projects as enabled' do + expect(group_lfs_status(group)).to include('Enabled for all projects') + end + + it 'returns only one as enabled' do + project.update_attribute(:lfs_enabled, false) + + expect(group_lfs_status(group)).to include('Enabled for 1 out of 2 projects') + end + end + + context 'LFS disabled in group' do + before do + group.update_attribute(:lfs_enabled, false) + end + + it 'returns both projects as disabled' do + expect(group_lfs_status(group)).to include('Disabled for all projects') + end + + it 'returns only one as disabled' do + project.update_attribute(:lfs_enabled, true) + + expect(group_lfs_status(group)).to include('Disabled for 1 out of 2 projects') + end + end + end + end end 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/database/migration_helpers_spec.rb b/spec/lib/gitlab/database/migration_helpers_spec.rb index 4ec3f19e03f..7fd25b9e5bf 100644 --- a/spec/lib/gitlab/database/migration_helpers_spec.rb +++ b/spec/lib/gitlab/database/migration_helpers_spec.rb @@ -91,63 +91,80 @@ describe Gitlab::Database::MigrationHelpers, lib: true do describe '#add_column_with_default' do context 'outside of a transaction' do - before do - expect(model).to receive(:transaction_open?).and_return(false) + context 'when a column limit is not set' do + before do + expect(model).to receive(:transaction_open?).and_return(false) - expect(model).to receive(:transaction).and_yield + expect(model).to receive(:transaction).and_yield - expect(model).to receive(:add_column). - with(:projects, :foo, :integer, default: nil) + expect(model).to receive(:add_column). + with(:projects, :foo, :integer, default: nil) - expect(model).to receive(:change_column_default). - with(:projects, :foo, 10) - end + expect(model).to receive(:change_column_default). + with(:projects, :foo, 10) + end - it 'adds the column while allowing NULL values' do - expect(model).to receive(:update_column_in_batches). - with(:projects, :foo, 10) + it 'adds the column while allowing NULL values' do + expect(model).to receive(:update_column_in_batches). + with(:projects, :foo, 10) - expect(model).not_to receive(:change_column_null) + expect(model).not_to receive(:change_column_null) - model.add_column_with_default(:projects, :foo, :integer, - default: 10, - allow_null: true) - end + model.add_column_with_default(:projects, :foo, :integer, + default: 10, + allow_null: true) + end - it 'adds the column while not allowing NULL values' do - expect(model).to receive(:update_column_in_batches). - with(:projects, :foo, 10) + it 'adds the column while not allowing NULL values' do + expect(model).to receive(:update_column_in_batches). + with(:projects, :foo, 10) - expect(model).to receive(:change_column_null). - with(:projects, :foo, false) + expect(model).to receive(:change_column_null). + with(:projects, :foo, false) - model.add_column_with_default(:projects, :foo, :integer, default: 10) - end + model.add_column_with_default(:projects, :foo, :integer, default: 10) + end - it 'removes the added column whenever updating the rows fails' do - expect(model).to receive(:update_column_in_batches). - with(:projects, :foo, 10). - and_raise(RuntimeError) + it 'removes the added column whenever updating the rows fails' do + expect(model).to receive(:update_column_in_batches). + with(:projects, :foo, 10). + and_raise(RuntimeError) - expect(model).to receive(:remove_column). - with(:projects, :foo) + expect(model).to receive(:remove_column). + with(:projects, :foo) - expect do - model.add_column_with_default(:projects, :foo, :integer, default: 10) - end.to raise_error(RuntimeError) + expect do + model.add_column_with_default(:projects, :foo, :integer, default: 10) + end.to raise_error(RuntimeError) + end + + it 'removes the added column whenever changing a column NULL constraint fails' do + expect(model).to receive(:change_column_null). + with(:projects, :foo, false). + and_raise(RuntimeError) + + expect(model).to receive(:remove_column). + with(:projects, :foo) + + expect do + model.add_column_with_default(:projects, :foo, :integer, default: 10) + end.to raise_error(RuntimeError) + end end - it 'removes the added column whenever changing a column NULL constraint fails' do - expect(model).to receive(:change_column_null). - with(:projects, :foo, false). - and_raise(RuntimeError) + context 'when a column limit is set' do + it 'adds the column with a limit' do + allow(model).to receive(:transaction_open?).and_return(false) + allow(model).to receive(:transaction).and_yield + allow(model).to receive(:update_column_in_batches).with(:projects, :foo, 10) + allow(model).to receive(:change_column_null).with(:projects, :foo, false) + allow(model).to receive(:change_column_default).with(:projects, :foo, 10) - expect(model).to receive(:remove_column). - with(:projects, :foo) + expect(model).to receive(:add_column). + with(:projects, :foo, :integer, default: nil, limit: 8) - expect do - model.add_column_with_default(:projects, :foo, :integer, default: 10) - end.to raise_error(RuntimeError) + model.add_column_with_default(:projects, :foo, :integer, default: 10, limit: 8) + end end end diff --git a/spec/models/ci/pipeline_spec.rb b/spec/models/ci/pipeline_spec.rb index fbf945c757c..f1857f846dc 100644 --- a/spec/models/ci/pipeline_spec.rb +++ b/spec/models/ci/pipeline_spec.rb @@ -373,8 +373,8 @@ describe Ci::Pipeline, models: true do end describe '#execute_hooks' do - let!(:build_a) { create_build('a') } - let!(:build_b) { create_build('b') } + let!(:build_a) { create_build('a', 0) } + let!(:build_b) { create_build('b', 1) } let!(:hook) do create(:project_hook, project: project, pipeline_events: enabled) @@ -398,7 +398,7 @@ describe Ci::Pipeline, models: true do build_b.enqueue end - it 'receive a pending event once' do + it 'receives a pending event once' do expect(WebMock).to have_requested_pipeline_hook('pending').once end end @@ -411,7 +411,7 @@ describe Ci::Pipeline, models: true do build_b.run end - it 'receive a running event once' do + it 'receives a running event once' do expect(WebMock).to have_requested_pipeline_hook('running').once end end @@ -422,11 +422,21 @@ describe Ci::Pipeline, models: true do build_b.success end - it 'receive a success event once' do + it 'receives a success event once' do expect(WebMock).to have_requested_pipeline_hook('success').once end end + context 'when stage one failed' do + before do + build_a.drop + end + + it 'receives a failed event once' do + expect(WebMock).to have_requested_pipeline_hook('failed').once + end + end + def have_requested_pipeline_hook(status) have_requested(:post, hook.url).with do |req| json_body = JSON.parse(req.body) @@ -450,8 +460,12 @@ describe Ci::Pipeline, models: true do end end - def create_build(name) - create(:ci_build, :created, pipeline: pipeline, name: name) + def create_build(name, stage_idx) + create(:ci_build, + :created, + pipeline: pipeline, + name: name, + stage_idx: stage_idx) end end end diff --git a/spec/models/commit_status_spec.rb b/spec/models/commit_status_spec.rb index fcfa3138ce5..2f1baff5d66 100644 --- a/spec/models/commit_status_spec.rb +++ b/spec/models/commit_status_spec.rb @@ -40,7 +40,7 @@ describe CommitStatus, models: true do it { is_expected.to be_falsey } end - %w(running success failed).each do |status| + %w[running success failed].each do |status| context "if commit status is #{status}" do before { commit_status.status = status } @@ -48,7 +48,7 @@ describe CommitStatus, models: true do end end - %w(pending canceled).each do |status| + %w[pending canceled].each do |status| context "if commit status is #{status}" do before { commit_status.status = status } @@ -60,7 +60,7 @@ describe CommitStatus, models: true do describe '#active?' do subject { commit_status.active? } - %w(pending running).each do |state| + %w[pending running].each do |state| context "if commit_status.status is #{state}" do before { commit_status.status = state } @@ -68,7 +68,7 @@ describe CommitStatus, models: true do end end - %w(success failed canceled).each do |state| + %w[success failed canceled].each do |state| context "if commit_status.status is #{state}" do before { commit_status.status = state } @@ -80,7 +80,7 @@ describe CommitStatus, models: true do describe '#complete?' do subject { commit_status.complete? } - %w(success failed canceled).each do |state| + %w[success failed canceled].each do |state| context "if commit_status.status is #{state}" do before { commit_status.status = state } @@ -88,7 +88,7 @@ describe CommitStatus, models: true do end end - %w(pending running).each do |state| + %w[pending running].each do |state| context "if commit_status.status is #{state}" do before { commit_status.status = state } @@ -187,7 +187,7 @@ describe CommitStatus, models: true do subject { CommitStatus.where(pipeline: pipeline).stages } it 'returns ordered list of stages' do - is_expected.to eq(%w(build test deploy)) + is_expected.to eq(%w[build test deploy]) end end @@ -223,4 +223,33 @@ describe CommitStatus, models: true do expect(commit_status.commit).to eq project.commit end end + + describe '#group_name' do + subject { commit_status.group_name } + + tests = { + 'rspec:windows' => 'rspec:windows', + 'rspec:windows 0' => 'rspec:windows 0', + 'rspec:windows 0 test' => 'rspec:windows 0 test', + 'rspec:windows 0 1' => 'rspec:windows', + 'rspec:windows 0 1 name' => 'rspec:windows name', + 'rspec:windows 0/1' => 'rspec:windows', + 'rspec:windows 0/1 name' => 'rspec:windows name', + 'rspec:windows 0:1' => 'rspec:windows', + 'rspec:windows 0:1 name' => 'rspec:windows name', + 'rspec:windows 10000 20000' => 'rspec:windows', + 'rspec:windows 0 : / 1' => 'rspec:windows', + 'rspec:windows 0 : / 1 name' => 'rspec:windows name', + '0 1 name ruby' => 'name ruby', + '0 :/ 1 name ruby' => 'name ruby' + } + + tests.each do |name, group_name| + it "'#{name}' puts in '#{group_name}'" do + commit_status.name = name + + is_expected.to eq(group_name) + end + end + end end diff --git a/spec/models/group_spec.rb b/spec/models/group_spec.rb index ea4b59c26b1..0b3ef9b98fd 100644 --- a/spec/models/group_spec.rb +++ b/spec/models/group_spec.rb @@ -187,6 +187,52 @@ describe Group, models: true do it { expect(group.has_master?(@members[:requester])).to be_falsey } end + describe '#lfs_enabled?' do + context 'LFS enabled globally' do + before do + allow(Gitlab.config.lfs).to receive(:enabled).and_return(true) + end + + it 'returns true when nothing is set' do + expect(group.lfs_enabled?).to be_truthy + end + + it 'returns false when set to false' do + group.update_attribute(:lfs_enabled, false) + + expect(group.lfs_enabled?).to be_falsey + end + + it 'returns true when set to true' do + group.update_attribute(:lfs_enabled, true) + + expect(group.lfs_enabled?).to be_truthy + end + end + + context 'LFS disabled globally' do + before do + allow(Gitlab.config.lfs).to receive(:enabled).and_return(false) + end + + it 'returns false when nothing is set' do + expect(group.lfs_enabled?).to be_falsey + end + + it 'returns false when set to false' do + group.update_attribute(:lfs_enabled, false) + + expect(group.lfs_enabled?).to be_falsey + end + + it 'returns false when set to true' do + group.update_attribute(:lfs_enabled, true) + + expect(group.lfs_enabled?).to be_falsey + end + end + end + describe '#owners' do let(:owner) { create(:user) } let(:developer) { create(:user) } diff --git a/spec/models/hooks/project_hook_spec.rb b/spec/models/hooks/project_hook_spec.rb index 4a457997a4f..474ae62ccec 100644 --- a/spec/models/hooks/project_hook_spec.rb +++ b/spec/models/hooks/project_hook_spec.rb @@ -1,21 +1,3 @@ -# == Schema Information -# -# Table name: web_hooks -# -# id :integer not null, primary key -# url :string(255) -# project_id :integer -# created_at :datetime -# updated_at :datetime -# type :string(255) default("ProjectHook") -# service_id :integer -# push_events :boolean default(TRUE), not null -# issues_events :boolean default(FALSE), not null -# merge_requests_events :boolean default(FALSE), not null -# tag_push_events :boolean default(FALSE) -# note_events :boolean default(FALSE), not null -# - require 'spec_helper' describe ProjectHook, models: true do diff --git a/spec/models/hooks/service_hook_spec.rb b/spec/models/hooks/service_hook_spec.rb index 534e1b4f128..1a83c836652 100644 --- a/spec/models/hooks/service_hook_spec.rb +++ b/spec/models/hooks/service_hook_spec.rb @@ -1,21 +1,3 @@ -# == Schema Information -# -# Table name: web_hooks -# -# id :integer not null, primary key -# url :string(255) -# project_id :integer -# created_at :datetime -# updated_at :datetime -# type :string(255) default("ProjectHook") -# service_id :integer -# push_events :boolean default(TRUE), not null -# issues_events :boolean default(FALSE), not null -# merge_requests_events :boolean default(FALSE), not null -# tag_push_events :boolean default(FALSE) -# note_events :boolean default(FALSE), not null -# - require "spec_helper" describe ServiceHook, models: true do diff --git a/spec/models/hooks/system_hook_spec.rb b/spec/models/hooks/system_hook_spec.rb index cbdf7eec082..ad2b710041a 100644 --- a/spec/models/hooks/system_hook_spec.rb +++ b/spec/models/hooks/system_hook_spec.rb @@ -1,21 +1,3 @@ -# == Schema Information -# -# Table name: web_hooks -# -# id :integer not null, primary key -# url :string(255) -# project_id :integer -# created_at :datetime -# updated_at :datetime -# type :string(255) default("ProjectHook") -# service_id :integer -# push_events :boolean default(TRUE), not null -# issues_events :boolean default(FALSE), not null -# merge_requests_events :boolean default(FALSE), not null -# tag_push_events :boolean default(FALSE) -# note_events :boolean default(FALSE), not null -# - require "spec_helper" describe SystemHook, models: true do @@ -48,7 +30,7 @@ describe SystemHook, models: true do it "user_create hook" do create(:user) - + expect(WebMock).to have_requested(:post, system_hook.url).with( body: /user_create/, headers: { 'Content-Type' => 'application/json', 'X-Gitlab-Event' => 'System Hook' } diff --git a/spec/models/hooks/web_hook_spec.rb b/spec/models/hooks/web_hook_spec.rb index f9bab487b96..e52b9d75cef 100644 --- a/spec/models/hooks/web_hook_spec.rb +++ b/spec/models/hooks/web_hook_spec.rb @@ -1,21 +1,3 @@ -# == Schema Information -# -# Table name: web_hooks -# -# id :integer not null, primary key -# url :string(255) -# project_id :integer -# created_at :datetime -# updated_at :datetime -# type :string(255) default("ProjectHook") -# service_id :integer -# push_events :boolean default(TRUE), not null -# issues_events :boolean default(FALSE), not null -# merge_requests_events :boolean default(FALSE), not null -# tag_push_events :boolean default(FALSE) -# note_events :boolean default(FALSE), not null -# - require 'spec_helper' describe WebHook, models: true do 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/members/group_member_spec.rb b/spec/models/members/group_member_spec.rb index 4f875fd257a..56fa7fa6134 100644 --- a/spec/models/members/group_member_spec.rb +++ b/spec/models/members/group_member_spec.rb @@ -1,22 +1,3 @@ -# == Schema Information -# -# Table name: members -# -# id :integer not null, primary key -# access_level :integer not null -# source_id :integer not null -# source_type :string(255) not null -# user_id :integer -# notification_level :integer not null -# type :string(255) -# created_at :datetime -# updated_at :datetime -# created_by_id :integer -# invite_email :string(255) -# invite_token :string(255) -# invite_accepted_at :datetime -# - require 'spec_helper' describe GroupMember, models: true do diff --git a/spec/models/members/project_member_spec.rb b/spec/models/members/project_member_spec.rb index be57957b569..805c15a4e5e 100644 --- a/spec/models/members/project_member_spec.rb +++ b/spec/models/members/project_member_spec.rb @@ -1,22 +1,3 @@ -# == Schema Information -# -# Table name: members -# -# id :integer not null, primary key -# access_level :integer not null -# source_id :integer not null -# source_type :string(255) not null -# user_id :integer -# notification_level :integer not null -# type :string(255) -# created_at :datetime -# updated_at :datetime -# created_by_id :integer -# invite_email :string(255) -# invite_token :string(255) -# invite_accepted_at :datetime -# - require 'spec_helper' describe ProjectMember, models: true do diff --git a/spec/models/merge_request_spec.rb b/spec/models/merge_request_spec.rb index 3b815ded2d3..06feeb1bbba 100644 --- a/spec/models/merge_request_spec.rb +++ b/spec/models/merge_request_spec.rb @@ -703,16 +703,24 @@ describe MergeRequest, models: true do describe "#environments" do let(:project) { create(:project) } - let!(:environment) { create(:environment, project: project) } - let!(:environment1) { create(:environment, project: project) } - let!(:environment2) { create(:environment, project: project) } let(:merge_request) { create(:merge_request, source_project: project) } it 'selects deployed environments' do - create(:deployment, environment: environment, sha: project.commit('master').id) - create(:deployment, environment: environment1, sha: project.commit('feature').id) + environments = create_list(:environment, 3, project: project) + create(:deployment, environment: environments.first, sha: project.commit('master').id) + create(:deployment, environment: environments.second, sha: project.commit('feature').id) - expect(merge_request.environments).to eq [environment] + expect(merge_request.environments).to eq [environments.first] + end + + context 'without a diff_head_commit' do + before do + expect(merge_request).to receive(:diff_head_commit).and_return(nil) + end + + it 'returns an empty array' do + expect(merge_request.environments).to be_empty + end end end diff --git a/spec/models/project_services/asana_service_spec.rb b/spec/models/project_services/asana_service_spec.rb index dc702cfc42c..8e5145e824b 100644 --- a/spec/models/project_services/asana_service_spec.rb +++ b/spec/models/project_services/asana_service_spec.rb @@ -1,23 +1,3 @@ -# == Schema Information -# -# Table name: services -# -# id :integer not null, primary key -# type :string(255) -# title :string(255) -# project_id :integer -# created_at :datetime -# updated_at :datetime -# active :boolean default(FALSE), not null -# properties :text -# template :boolean default(FALSE) -# push_events :boolean default(TRUE) -# issues_events :boolean default(TRUE) -# merge_requests_events :boolean default(TRUE) -# tag_push_events :boolean default(TRUE) -# note_events :boolean default(TRUE), not null -# - require 'spec_helper' describe AsanaService, models: true do diff --git a/spec/models/project_services/assembla_service_spec.rb b/spec/models/project_services/assembla_service_spec.rb index d672d80156c..4c5acb7990b 100644 --- a/spec/models/project_services/assembla_service_spec.rb +++ b/spec/models/project_services/assembla_service_spec.rb @@ -1,23 +1,3 @@ -# == Schema Information -# -# Table name: services -# -# id :integer not null, primary key -# type :string(255) -# title :string(255) -# project_id :integer -# created_at :datetime -# updated_at :datetime -# active :boolean default(FALSE), not null -# properties :text -# template :boolean default(FALSE) -# push_events :boolean default(TRUE) -# issues_events :boolean default(TRUE) -# merge_requests_events :boolean default(TRUE) -# tag_push_events :boolean default(TRUE) -# note_events :boolean default(TRUE), not null -# - require 'spec_helper' describe AssemblaService, models: true do diff --git a/spec/models/project_services/bamboo_service_spec.rb b/spec/models/project_services/bamboo_service_spec.rb index 9ae461f8c2d..d7e1a4e3b6c 100644 --- a/spec/models/project_services/bamboo_service_spec.rb +++ b/spec/models/project_services/bamboo_service_spec.rb @@ -1,23 +1,3 @@ -# == Schema Information -# -# Table name: services -# -# id :integer not null, primary key -# type :string(255) -# title :string(255) -# project_id :integer -# created_at :datetime -# updated_at :datetime -# active :boolean default(FALSE), not null -# properties :text -# template :boolean default(FALSE) -# push_events :boolean default(TRUE) -# issues_events :boolean default(TRUE) -# merge_requests_events :boolean default(TRUE) -# tag_push_events :boolean default(TRUE) -# note_events :boolean default(TRUE), not null -# - require 'spec_helper' describe BambooService, models: true do diff --git a/spec/models/project_services/bugzilla_service_spec.rb b/spec/models/project_services/bugzilla_service_spec.rb index a6d9717ccb5..739cc72b2ff 100644 --- a/spec/models/project_services/bugzilla_service_spec.rb +++ b/spec/models/project_services/bugzilla_service_spec.rb @@ -1,23 +1,3 @@ -# == Schema Information -# -# Table name: services -# -# id :integer not null, primary key -# type :string(255) -# title :string(255) -# project_id :integer -# created_at :datetime -# updated_at :datetime -# active :boolean default(FALSE), not null -# properties :text -# template :boolean default(FALSE) -# push_events :boolean default(TRUE) -# issues_events :boolean default(TRUE) -# merge_requests_events :boolean default(TRUE) -# tag_push_events :boolean default(TRUE) -# note_events :boolean default(TRUE), not null -# - require 'spec_helper' describe BugzillaService, models: true do diff --git a/spec/models/project_services/buildkite_service_spec.rb b/spec/models/project_services/buildkite_service_spec.rb index 0866e1532dd..6f65beb79d0 100644 --- a/spec/models/project_services/buildkite_service_spec.rb +++ b/spec/models/project_services/buildkite_service_spec.rb @@ -1,23 +1,3 @@ -# == Schema Information -# -# Table name: services -# -# id :integer not null, primary key -# type :string(255) -# title :string(255) -# project_id :integer -# created_at :datetime -# updated_at :datetime -# active :boolean default(FALSE), not null -# properties :text -# template :boolean default(FALSE) -# push_events :boolean default(TRUE) -# issues_events :boolean default(TRUE) -# merge_requests_events :boolean default(TRUE) -# tag_push_events :boolean default(TRUE) -# note_events :boolean default(TRUE), not null -# - require 'spec_helper' describe BuildkiteService, models: true do diff --git a/spec/models/project_services/campfire_service_spec.rb b/spec/models/project_services/campfire_service_spec.rb index c76ae21421b..a3b9d084a75 100644 --- a/spec/models/project_services/campfire_service_spec.rb +++ b/spec/models/project_services/campfire_service_spec.rb @@ -1,23 +1,3 @@ -# == Schema Information -# -# Table name: services -# -# id :integer not null, primary key -# type :string(255) -# title :string(255) -# project_id :integer -# created_at :datetime -# updated_at :datetime -# active :boolean default(FALSE), not null -# properties :text -# template :boolean default(FALSE) -# push_events :boolean default(TRUE) -# issues_events :boolean default(TRUE) -# merge_requests_events :boolean default(TRUE) -# tag_push_events :boolean default(TRUE) -# note_events :boolean default(TRUE), not null -# - require 'spec_helper' describe CampfireService, models: true do diff --git a/spec/models/project_services/custom_issue_tracker_service_spec.rb b/spec/models/project_services/custom_issue_tracker_service_spec.rb index ff976f8ec59..7020667ea58 100644 --- a/spec/models/project_services/custom_issue_tracker_service_spec.rb +++ b/spec/models/project_services/custom_issue_tracker_service_spec.rb @@ -1,23 +1,3 @@ -# == Schema Information -# -# Table name: services -# -# id :integer not null, primary key -# type :string(255) -# title :string(255) -# project_id :integer -# created_at :datetime -# updated_at :datetime -# active :boolean default(FALSE), not null -# properties :text -# template :boolean default(FALSE) -# push_events :boolean default(TRUE) -# issues_events :boolean default(TRUE) -# merge_requests_events :boolean default(TRUE) -# tag_push_events :boolean default(TRUE) -# note_events :boolean default(TRUE), not null -# - require 'spec_helper' describe CustomIssueTrackerService, models: true do diff --git a/spec/models/project_services/drone_ci_service_spec.rb b/spec/models/project_services/drone_ci_service_spec.rb index 8ef892259f2..f13bb1e8adf 100644 --- a/spec/models/project_services/drone_ci_service_spec.rb +++ b/spec/models/project_services/drone_ci_service_spec.rb @@ -1,23 +1,3 @@ -# == Schema Information -# -# Table name: services -# -# id :integer not null, primary key -# type :string(255) -# title :string(255) -# project_id :integer -# created_at :datetime -# updated_at :datetime -# active :boolean default(FALSE), not null -# properties :text -# template :boolean default(FALSE) -# push_events :boolean default(TRUE) -# issues_events :boolean default(TRUE) -# merge_requests_events :boolean default(TRUE) -# tag_push_events :boolean default(TRUE) -# note_events :boolean default(TRUE), not null -# - require 'spec_helper' describe DroneCiService, models: true do diff --git a/spec/models/project_services/external_wiki_service_spec.rb b/spec/models/project_services/external_wiki_service_spec.rb index d7c5ea95d71..342d86aeca9 100644 --- a/spec/models/project_services/external_wiki_service_spec.rb +++ b/spec/models/project_services/external_wiki_service_spec.rb @@ -1,24 +1,3 @@ -# == Schema Information -# -# Table name: services -# -# id :integer not null, primary key -# type :string(255) -# title :string(255) -# project_id :integer -# created_at :datetime -# updated_at :datetime -# active :boolean default(FALSE), not null -# properties :text -# template :boolean default(FALSE) -# push_events :boolean default(TRUE) -# issues_events :boolean default(TRUE) -# merge_requests_events :boolean default(TRUE) -# tag_push_events :boolean default(TRUE) -# note_events :boolean default(TRUE), not null -# build_events :boolean default(FALSE), not null -# - require 'spec_helper' describe ExternalWikiService, models: true do diff --git a/spec/models/project_services/flowdock_service_spec.rb b/spec/models/project_services/flowdock_service_spec.rb index d2557019756..d6db02d6e76 100644 --- a/spec/models/project_services/flowdock_service_spec.rb +++ b/spec/models/project_services/flowdock_service_spec.rb @@ -1,23 +1,3 @@ -# == Schema Information -# -# Table name: services -# -# id :integer not null, primary key -# type :string(255) -# title :string(255) -# project_id :integer -# created_at :datetime -# updated_at :datetime -# active :boolean default(FALSE), not null -# properties :text -# template :boolean default(FALSE) -# push_events :boolean default(TRUE) -# issues_events :boolean default(TRUE) -# merge_requests_events :boolean default(TRUE) -# tag_push_events :boolean default(TRUE) -# note_events :boolean default(TRUE), not null -# - require 'spec_helper' describe FlowdockService, models: true do diff --git a/spec/models/project_services/gemnasium_service_spec.rb b/spec/models/project_services/gemnasium_service_spec.rb index 3d0b6c9816b..529044d1d8b 100644 --- a/spec/models/project_services/gemnasium_service_spec.rb +++ b/spec/models/project_services/gemnasium_service_spec.rb @@ -1,23 +1,3 @@ -# == Schema Information -# -# Table name: services -# -# id :integer not null, primary key -# type :string(255) -# title :string(255) -# project_id :integer -# created_at :datetime -# updated_at :datetime -# active :boolean default(FALSE), not null -# properties :text -# template :boolean default(FALSE) -# push_events :boolean default(TRUE) -# issues_events :boolean default(TRUE) -# merge_requests_events :boolean default(TRUE) -# tag_push_events :boolean default(TRUE) -# note_events :boolean default(TRUE), not null -# - require 'spec_helper' describe GemnasiumService, models: true do diff --git a/spec/models/project_services/gitlab_issue_tracker_service_spec.rb b/spec/models/project_services/gitlab_issue_tracker_service_spec.rb index 8ef79a17d50..652804fb444 100644 --- a/spec/models/project_services/gitlab_issue_tracker_service_spec.rb +++ b/spec/models/project_services/gitlab_issue_tracker_service_spec.rb @@ -1,23 +1,3 @@ -# == Schema Information -# -# Table name: services -# -# id :integer not null, primary key -# type :string(255) -# title :string(255) -# project_id :integer -# created_at :datetime -# updated_at :datetime -# active :boolean default(FALSE), not null -# properties :text -# template :boolean default(FALSE) -# push_events :boolean default(TRUE) -# issues_events :boolean default(TRUE) -# merge_requests_events :boolean default(TRUE) -# tag_push_events :boolean default(TRUE) -# note_events :boolean default(TRUE), not null -# - require 'spec_helper' describe GitlabIssueTrackerService, models: true do diff --git a/spec/models/project_services/hipchat_service_spec.rb b/spec/models/project_services/hipchat_service_spec.rb index 34eafbe555d..cf713684463 100644 --- a/spec/models/project_services/hipchat_service_spec.rb +++ b/spec/models/project_services/hipchat_service_spec.rb @@ -1,23 +1,3 @@ -# == Schema Information -# -# Table name: services -# -# id :integer not null, primary key -# type :string(255) -# title :string(255) -# project_id :integer -# created_at :datetime -# updated_at :datetime -# active :boolean default(FALSE), not null -# properties :text -# template :boolean default(FALSE) -# push_events :boolean default(TRUE) -# issues_events :boolean default(TRUE) -# merge_requests_events :boolean default(TRUE) -# tag_push_events :boolean default(TRUE) -# note_events :boolean default(TRUE), not null -# - require 'spec_helper' describe HipchatService, models: true do diff --git a/spec/models/project_services/irker_service_spec.rb b/spec/models/project_services/irker_service_spec.rb index ffb17fd3259..f8c45b37561 100644 --- a/spec/models/project_services/irker_service_spec.rb +++ b/spec/models/project_services/irker_service_spec.rb @@ -1,23 +1,3 @@ -# == Schema Information -# -# Table name: services -# -# id :integer not null, primary key -# type :string(255) -# title :string(255) -# project_id :integer -# created_at :datetime -# updated_at :datetime -# active :boolean default(FALSE), not null -# properties :text -# template :boolean default(FALSE) -# push_events :boolean default(TRUE) -# issues_events :boolean default(TRUE) -# merge_requests_events :boolean default(TRUE) -# tag_push_events :boolean default(TRUE) -# note_events :boolean default(TRUE), not null -# - require 'spec_helper' require 'socket' require 'json' diff --git a/spec/models/project_services/jira_service_spec.rb b/spec/models/project_services/jira_service_spec.rb index 9037ca5cc20..b48a3176007 100644 --- a/spec/models/project_services/jira_service_spec.rb +++ b/spec/models/project_services/jira_service_spec.rb @@ -1,23 +1,3 @@ -# == Schema Information -# -# Table name: services -# -# id :integer not null, primary key -# type :string(255) -# title :string(255) -# project_id :integer -# created_at :datetime -# updated_at :datetime -# active :boolean default(FALSE), not null -# properties :text -# template :boolean default(FALSE) -# push_events :boolean default(TRUE) -# issues_events :boolean default(TRUE) -# merge_requests_events :boolean default(TRUE) -# tag_push_events :boolean default(TRUE) -# note_events :boolean default(TRUE), not null -# - require 'spec_helper' describe JiraService, models: true do diff --git a/spec/models/project_services/pivotaltracker_service_spec.rb b/spec/models/project_services/pivotaltracker_service_spec.rb index d098d988521..45b2f1068bf 100644 --- a/spec/models/project_services/pivotaltracker_service_spec.rb +++ b/spec/models/project_services/pivotaltracker_service_spec.rb @@ -1,23 +1,3 @@ -# == Schema Information -# -# Table name: services -# -# id :integer not null, primary key -# type :string(255) -# title :string(255) -# project_id :integer -# created_at :datetime -# updated_at :datetime -# active :boolean default(FALSE), not null -# properties :text -# template :boolean default(FALSE) -# push_events :boolean default(TRUE) -# issues_events :boolean default(TRUE) -# merge_requests_events :boolean default(TRUE) -# tag_push_events :boolean default(TRUE) -# note_events :boolean default(TRUE), not null -# - require 'spec_helper' describe PivotaltrackerService, models: true do diff --git a/spec/models/project_services/pushover_service_spec.rb b/spec/models/project_services/pushover_service_spec.rb index 5959c81577d..8fc92a9ab51 100644 --- a/spec/models/project_services/pushover_service_spec.rb +++ b/spec/models/project_services/pushover_service_spec.rb @@ -1,23 +1,3 @@ -# == Schema Information -# -# Table name: services -# -# id :integer not null, primary key -# type :string(255) -# title :string(255) -# project_id :integer -# created_at :datetime -# updated_at :datetime -# active :boolean default(FALSE), not null -# properties :text -# template :boolean default(FALSE) -# push_events :boolean default(TRUE) -# issues_events :boolean default(TRUE) -# merge_requests_events :boolean default(TRUE) -# tag_push_events :boolean default(TRUE) -# note_events :boolean default(TRUE), not null -# - require 'spec_helper' describe PushoverService, models: true do diff --git a/spec/models/project_services/redmine_service_spec.rb b/spec/models/project_services/redmine_service_spec.rb index 7d14f6e8280..b8679cd2563 100644 --- a/spec/models/project_services/redmine_service_spec.rb +++ b/spec/models/project_services/redmine_service_spec.rb @@ -1,23 +1,3 @@ -# == Schema Information -# -# Table name: services -# -# id :integer not null, primary key -# type :string(255) -# title :string(255) -# project_id :integer -# created_at :datetime -# updated_at :datetime -# active :boolean default(FALSE), not null -# properties :text -# template :boolean default(FALSE) -# push_events :boolean default(TRUE) -# issues_events :boolean default(TRUE) -# merge_requests_events :boolean default(TRUE) -# tag_push_events :boolean default(TRUE) -# note_events :boolean default(TRUE), not null -# - require 'spec_helper' describe RedmineService, models: true do diff --git a/spec/models/project_services/slack_service_spec.rb b/spec/models/project_services/slack_service_spec.rb index 5afdc4b2f7b..c07a70a8069 100644 --- a/spec/models/project_services/slack_service_spec.rb +++ b/spec/models/project_services/slack_service_spec.rb @@ -1,23 +1,3 @@ -# == Schema Information -# -# Table name: services -# -# id :integer not null, primary key -# type :string(255) -# title :string(255) -# project_id :integer -# created_at :datetime -# updated_at :datetime -# active :boolean default(FALSE), not null -# properties :text -# template :boolean default(FALSE) -# push_events :boolean default(TRUE) -# issues_events :boolean default(TRUE) -# merge_requests_events :boolean default(TRUE) -# tag_push_events :boolean default(TRUE) -# note_events :boolean default(TRUE), not null -# - require 'spec_helper' describe SlackService, models: true do diff --git a/spec/models/project_services/teamcity_service_spec.rb b/spec/models/project_services/teamcity_service_spec.rb index 474715d24c3..f7e878844dc 100644 --- a/spec/models/project_services/teamcity_service_spec.rb +++ b/spec/models/project_services/teamcity_service_spec.rb @@ -1,23 +1,3 @@ -# == Schema Information -# -# Table name: services -# -# id :integer not null, primary key -# type :string(255) -# title :string(255) -# project_id :integer -# created_at :datetime -# updated_at :datetime -# active :boolean default(FALSE), not null -# properties :text -# template :boolean default(FALSE) -# push_events :boolean default(TRUE) -# issues_events :boolean default(TRUE) -# merge_requests_events :boolean default(TRUE) -# tag_push_events :boolean default(TRUE) -# note_events :boolean default(TRUE), not null -# - require 'spec_helper' describe TeamcityService, models: true do diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb index f6e811828fc..7ca1bd1e5c9 100644 --- a/spec/models/project_spec.rb +++ b/spec/models/project_spec.rb @@ -1417,6 +1417,68 @@ describe Project, models: true do end end + describe '#lfs_enabled?' do + let(:project) { create(:project) } + + shared_examples 'project overrides group' do + it 'returns true when enabled in project' do + project.update_attribute(:lfs_enabled, true) + + expect(project.lfs_enabled?).to be_truthy + end + + it 'returns false when disabled in project' do + project.update_attribute(:lfs_enabled, false) + + expect(project.lfs_enabled?).to be_falsey + end + + it 'returns the value from the namespace, when no value is set in project' do + expect(project.lfs_enabled?).to eq(project.namespace.lfs_enabled?) + end + end + + context 'LFS disabled in group' do + before do + project.namespace.update_attribute(:lfs_enabled, false) + enable_lfs + end + + it_behaves_like 'project overrides group' + end + + context 'LFS enabled in group' do + before do + project.namespace.update_attribute(:lfs_enabled, true) + enable_lfs + end + + it_behaves_like 'project overrides group' + end + + describe 'LFS disabled globally' do + shared_examples 'it always returns false' do + it do + expect(project.lfs_enabled?).to be_falsey + expect(project.namespace.lfs_enabled?).to be_falsey + end + end + + context 'when no values are set' do + it_behaves_like 'it always returns false' + end + + context 'when all values are set to true' do + before do + project.namespace.update_attribute(:lfs_enabled, true) + project.update_attribute(:lfs_enabled, true) + end + + it_behaves_like 'it always returns false' + end + end + end + describe '.where_paths_in' do context 'without any paths' do it 'returns an empty relation' do @@ -1581,4 +1643,8 @@ describe Project, models: true do expect(project.pushes_since_gc).to eq(0) end end + + def enable_lfs + allow(Gitlab.config.lfs).to receive(:enabled).and_return(true) + end end diff --git a/spec/support/wait_for_vue_resource.rb b/spec/support/wait_for_vue_resource.rb new file mode 100644 index 00000000000..1029f84716f --- /dev/null +++ b/spec/support/wait_for_vue_resource.rb @@ -0,0 +1,7 @@ +module WaitForVueResource + def wait_for_vue_resource(spinner: true) + Timeout.timeout(Capybara.default_max_wait_time) do + loop until page.evaluate_script('Vue.activeResources').zero? + end + end +end diff --git a/spec/views/projects/pipelines/show.html.haml_spec.rb b/spec/views/projects/pipelines/show.html.haml_spec.rb new file mode 100644 index 00000000000..c5b16c1c304 --- /dev/null +++ b/spec/views/projects/pipelines/show.html.haml_spec.rb @@ -0,0 +1,50 @@ +require 'spec_helper' + +describe 'projects/pipelines/show' do + include Devise::TestHelpers + + let(:project) { create(:project) } + let(:pipeline) { create(:ci_empty_pipeline, project: project, sha: project.commit.id) } + + before do + controller.prepend_view_path('app/views/projects') + + create_build('build', 0, 'build') + create_build('test', 1, 'rspec 0:2') + create_build('test', 1, 'rspec 1:2') + create_build('test', 1, 'audit') + create_build('deploy', 2, 'production') + + create(:generic_commit_status, pipeline: pipeline, stage: 'external', name: 'jenkins', stage_idx: 3) + + assign(:project, project) + assign(:pipeline, pipeline) + + allow(view).to receive(:can?).and_return(true) + end + + it 'shows a graph with grouped stages' do + render + + expect(rendered).to have_css('.pipeline-graph') + expect(rendered).to have_css('.grouped-pipeline-dropdown') + + # stages + expect(rendered).to have_text('Build') + expect(rendered).to have_text('Test') + expect(rendered).to have_text('Deploy') + expect(rendered).to have_text('External') + + # builds + expect(rendered).to have_text('rspec') + expect(rendered).to have_text('rspec 0:2') + expect(rendered).to have_text('production') + expect(rendered).to have_text('jenkins') + end + + private + + def create_build(stage, stage_idx, name) + create(:ci_build, pipeline: pipeline, stage: stage, stage_idx: stage_idx, name: name) + end +end |