diff options
28 files changed, 1174 insertions, 300 deletions
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index cb6f691058e..441f77740a8 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -19,8 +19,6 @@ variables: before_script: - source ./scripts/prepare_build.sh - cp config/gitlab.yml.example config/gitlab.yml - - mkdir -p tmp/tests - - mount -t tmpfs tmpfs tmp/tests || echo "tmpfs mount failed, falling back to disc" - bundle --version - '[ "$USE_BUNDLE_INSTALL" != "true" ] || retry bundle install --without postgres production --jobs $(nproc) "${FLAGS[@]}"' - retry gem install knapsack @@ -257,6 +255,12 @@ lint-doc: script: - scripts/lint-doc.sh +bundler:check: + stage: test + <<: *ruby-static-analysis + script: + - bundle check + bundler:audit: stage: test <<: *ruby-static-analysis diff --git a/CHANGELOG b/CHANGELOG index edbd7454548..adada3b0d02 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -19,6 +19,7 @@ v 8.13.0 (unreleased) - Replaced the check sign to arrow in the show build view. !6501 - Add a /wip slash command to toggle the Work In Progress status of a merge request. !6259 (tbalthazar) - Fix Error 500 when viewing old merge requests with bad diff data + - Create a new /templates namespace for the /licenses, /gitignores and /gitlab_ci_ymls API endpoints. !5717 (tbalthazar) - Speed-up group milestones show page - Fix inconsistent options dropdown caret on mobile viewports (ClemMakesApps) - Don't include archived projects when creating group milestones. !4940 (Jeroen Jacobs) @@ -31,6 +32,7 @@ v 8.13.0 (unreleased) - Cache rendered markdown in the database, rather than Redis - Avoid database queries on Banzai::ReferenceParser::BaseParser for nodes without references - Simplify Mentionable concern instance methods + - API: Ability to retrieve version information (Robert Schilling) - Fix permission for setting an issue's due date - API: Multi-file commit !6096 (mahcsig) - Revert "Label list shows all issues (opened or closed) with that label" @@ -128,6 +130,7 @@ v 8.12.4 - Fix failed project deletion when feature visibility set to private. !6688 - Prevent claiming associated model IDs via import. - Set GitLab project exported file permissions to owner only + - Improve the way merge request versions are compared with each other v 8.12.3 - Update Gitlab Shell to support low IO priority for storage moves @@ -51,7 +51,7 @@ gem 'browser', '~> 2.2' # Extracting information from a git repository # Provide access to Gitlab::Git library -gem 'gitlab_git', '~> 10.6.7' +gem 'gitlab_git', '~> 10.6.8' # LDAP Auth # GitLab fork with several improvements to original library. For full list of changes @@ -343,7 +343,7 @@ gem 'oauth2', '~> 1.2.0' gem 'paranoia', '~> 2.0' # Health check -gem 'health_check', '~> 2.1.0' +gem 'health_check', '~> 2.2.0' # System information gem 'vmstat', '~> 2.2' diff --git a/Gemfile.lock b/Gemfile.lock index 69804c8c533..067908af3fb 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -282,7 +282,7 @@ GEM diff-lcs (~> 1.1) mime-types (>= 1.16, < 3) posix-spawn (~> 0.3) - gitlab_git (10.6.7) + gitlab_git (10.6.8) activesupport (~> 4.0) charlock_holmes (~> 0.7.3) github-linguist (~> 4.7.0) @@ -336,7 +336,7 @@ GEM thor tilt hashie (3.4.4) - health_check (2.1.0) + health_check (2.2.1) rails (>= 4.0) hipchat (1.5.2) httparty @@ -866,7 +866,7 @@ DEPENDENCIES github-linguist (~> 4.7.0) github-markup (~> 1.4) gitlab-flowdock-git-hook (~> 1.0.1) - gitlab_git (~> 10.6.7) + gitlab_git (~> 10.6.8) gitlab_omniauth-ldap (~> 1.2.1) gollum-lib (~> 4.2) gollum-rugged_adapter (~> 0.4.2) @@ -875,7 +875,7 @@ DEPENDENCIES grape-entity (~> 0.4.2) haml_lint (~> 0.18.2) hamlit (~> 2.6.1) - health_check (~> 2.1.0) + health_check (~> 2.2.0) hipchat (~> 1.5.0) html-pipeline (~> 1.11.0) httparty (~> 0.13.3) diff --git a/app/assets/javascripts/api.js b/app/assets/javascripts/api.js index 599331df3f5..56ec1489f89 100644 --- a/app/assets/javascripts/api.js +++ b/app/assets/javascripts/api.js @@ -6,11 +6,10 @@ groupProjectsPath: "/api/:version/groups/:id/projects.json", projectsPath: "/api/:version/projects.json?simple=true", labelsPath: "/:namespace_path/:project_path/labels", - licensePath: "/api/:version/licenses/:key", - gitignorePath: "/api/:version/gitignores/:key", - gitlabCiYmlPath: "/api/:version/gitlab_ci_ymls/:key", + licensePath: "/api/:version/templates/licenses/:key", + gitignorePath: "/api/:version/templates/gitignores/:key", + gitlabCiYmlPath: "/api/:version/templates/gitlab_ci_ymls/:key", issuableTemplatePath: "/:namespace_path/:project_path/templates/:type/:key", - group: function(group_id, callback) { var url = Api.buildUrl(Api.groupPath) .replace(':id', group_id); diff --git a/app/assets/stylesheets/pages/merge_requests.scss b/app/assets/stylesheets/pages/merge_requests.scss index 1006b3e62e8..7cf69c56d15 100644 --- a/app/assets/stylesheets/pages/merge_requests.scss +++ b/app/assets/stylesheets/pages/merge_requests.scss @@ -401,8 +401,12 @@ padding: 16px; } + .content-block { + border-top: 1px solid $border-color; + padding: $gl-padding-top $gl-padding; + } + .comments-disabled-notif { - padding: 10px 16px; .btn { margin-left: 5px; } @@ -413,10 +417,6 @@ margin: 0 7px; } - .comments-disabled-notif { - border-top: 1px solid $border-color; - } - .dropdown-title { color: $gl-text-color; } diff --git a/app/helpers/merge_requests_helper.rb b/app/helpers/merge_requests_helper.rb index b0a76765d97..249cb44e9d5 100644 --- a/app/helpers/merge_requests_helper.rb +++ b/app/helpers/merge_requests_helper.rb @@ -123,4 +123,8 @@ module MergeRequestsHelper def version_index(merge_request_diff) @merge_request_diffs.size - @merge_request_diffs.index(merge_request_diff) end + + def different_base?(version1, version2) + version1 && version2 && version1.base_commit_sha != version2.base_commit_sha + end end diff --git a/app/models/compare.rb b/app/models/compare.rb index 4856510f526..3a8bbcb1acd 100644 --- a/app/models/compare.rb +++ b/app/models/compare.rb @@ -11,9 +11,10 @@ class Compare end end - def initialize(compare, project) + def initialize(compare, project, straight: false) @compare = compare @project = project + @straight = straight end def commits @@ -45,6 +46,18 @@ class Compare end end + def start_commit_sha + start_commit.try(:sha) + end + + def base_commit_sha + base_commit.try(:sha) + end + + def head_commit_sha + commit.try(:sha) + end + def raw_diffs(*args) @compare.diffs(*args) end @@ -58,9 +71,9 @@ class Compare def diff_refs Gitlab::Diff::DiffRefs.new( - base_sha: base_commit.try(:sha), - start_sha: start_commit.try(:sha), - head_sha: commit.try(:sha) + base_sha: @straight ? start_commit_sha : base_commit_sha, + start_sha: start_commit_sha, + head_sha: head_commit_sha ) end end diff --git a/app/models/merge_request_diff.rb b/app/models/merge_request_diff.rb index 3f7e96186a1..b8a10b7968e 100644 --- a/app/models/merge_request_diff.rb +++ b/app/models/merge_request_diff.rb @@ -167,8 +167,11 @@ class MergeRequestDiff < ActiveRecord::Base self == merge_request.merge_request_diff end - def compare_with(sha) - CompareService.new.execute(project, head_commit_sha, project, sha) + def compare_with(sha, straight: true) + # When compare merge request versions we want diff A..B instead of A...B + # so we handle cases when user does squash and rebase of the commits between versions. + # For this reason we set straight to true by default. + CompareService.new.execute(project, head_commit_sha, project, sha, straight: straight) end private diff --git a/app/services/compare_service.rb b/app/services/compare_service.rb index 6d6075628af..5e8fafca98c 100644 --- a/app/services/compare_service.rb +++ b/app/services/compare_service.rb @@ -3,7 +3,7 @@ require 'securerandom' # Compare 2 branches for one repo or between repositories # and return Gitlab::Git::Compare object that responds to commits and diffs class CompareService - def execute(source_project, source_branch, target_project, target_branch) + def execute(source_project, source_branch, target_project, target_branch, straight: false) source_commit = source_project.commit(source_branch) return unless source_commit @@ -23,9 +23,10 @@ class CompareService raw_compare = Gitlab::Git::Compare.new( target_project.repository.raw_repository, target_branch, - source_sha + source_sha, + straight ) - Compare.new(raw_compare, target_project) + Compare.new(raw_compare, target_project, straight: straight) end end diff --git a/app/views/projects/merge_requests/show/_versions.html.haml b/app/views/projects/merge_requests/show/_versions.html.haml index 988ac0feae1..eab48b78cb3 100644 --- a/app/views/projects/merge_requests/show/_versions.html.haml +++ b/app/views/projects/merge_requests/show/_versions.html.haml @@ -64,6 +64,16 @@ #{@merge_request.target_branch} (base) .monospace #{short_sha(@merge_request_diff.base_commit_sha)} + - if different_base?(@start_version, @merge_request_diff) + .content-block + = icon('info-circle') + Selected versions have different base commits. + Changes will include + = link_to namespace_project_compare_path(@project.namespace, @project, from: @start_version.base_commit_sha, to: @merge_request_diff.base_commit_sha) do + new commits + from + %code #{@merge_request.target_branch} + - unless @merge_request_diff.latest? && !@start_sha .comments-disabled-notif.content-block = icon('info-circle') diff --git a/doc/administration/troubleshooting/debug.md b/doc/administration/troubleshooting/debug.md index d127d7b85e5..d8dce4388e1 100644 --- a/doc/administration/troubleshooting/debug.md +++ b/doc/administration/troubleshooting/debug.md @@ -144,14 +144,14 @@ separate Rails process to debug the issue: 1. Obtain the private token for your user (Profile Settings -> Account). 1. Bring up the GitLab Rails console. For omnibus users, run: - ```` + ``` sudo gitlab-rails console ``` 1. At the Rails console, run: ```ruby - [1] pry(main)> app.get '<URL FROM STEP 1>/private_token?<TOKEN FROM STEP 2>' + [1] pry(main)> app.get '<URL FROM STEP 2>/?private_token=<TOKEN FROM STEP 3>' ``` For example: diff --git a/doc/api/README.md b/doc/api/README.md index 9e907689c80..3fbe5197a21 100644 --- a/doc/api/README.md +++ b/doc/api/README.md @@ -17,6 +17,8 @@ following locations: - [Commits](commits.md) - [Deployments](deployments.md) - [Deploy Keys](deploy_keys.md) +- [Gitignores templates](templates/gitignores.md) +- [GitLab CI Config templates](templates/gitlab_ci_ymls.md) - [Groups](groups.md) - [Group Access Requests](access_requests.md) - [Group Members](members.md) @@ -25,7 +27,7 @@ following locations: - [Labels](labels.md) - [Merge Requests](merge_requests.md) - [Milestones](milestones.md) -- [Open source license templates](licenses.md) +- [Open source license templates](templates/licenses.md) - [Namespaces](namespaces.md) - [Notes](notes.md) (comments) - [Notification settings](notification_settings.md) @@ -46,6 +48,7 @@ following locations: - [Todos](todos.md) - [Users](users.md) - [Validate CI configuration](ci/lint.md) +- [Version](version.md) ### Internal CI API diff --git a/doc/api/templates/gitignores.md b/doc/api/templates/gitignores.md new file mode 100644 index 00000000000..8235be92b12 --- /dev/null +++ b/doc/api/templates/gitignores.md @@ -0,0 +1,579 @@ +# Gitignores + +## List gitignore templates + +Get all gitignore templates. + +``` +GET /templates/gitignores +``` + +```bash +curl https://gitlab.example.com/api/v3/templates/gitignores +``` + +Example response: + +```json +[ + { + "name": "AppEngine" + }, + { + "name": "Laravel" + }, + { + "name": "Elisp" + }, + { + "name": "SketchUp" + }, + { + "name": "Ada" + }, + { + "name": "Ruby" + }, + { + "name": "Kohana" + }, + { + "name": "Nanoc" + }, + { + "name": "Erlang" + }, + { + "name": "OCaml" + }, + { + "name": "Lithium" + }, + { + "name": "Fortran" + }, + { + "name": "Scala" + }, + { + "name": "Node" + }, + { + "name": "Fancy" + }, + { + "name": "Perl" + }, + { + "name": "Zephir" + }, + { + "name": "WordPress" + }, + { + "name": "Symfony" + }, + { + "name": "FuelPHP" + }, + { + "name": "DM" + }, + { + "name": "Sdcc" + }, + { + "name": "Rust" + }, + { + "name": "C" + }, + { + "name": "Umbraco" + }, + { + "name": "Actionscript" + }, + { + "name": "Android" + }, + { + "name": "Grails" + }, + { + "name": "Composer" + }, + { + "name": "ExpressionEngine" + }, + { + "name": "Gcov" + }, + { + "name": "Qt" + }, + { + "name": "Phalcon" + }, + { + "name": "ArchLinuxPackages" + }, + { + "name": "TeX" + }, + { + "name": "SCons" + }, + { + "name": "Lilypond" + }, + { + "name": "CommonLisp" + }, + { + "name": "Rails" + }, + { + "name": "Mercury" + }, + { + "name": "Magento" + }, + { + "name": "ChefCookbook" + }, + { + "name": "GitBook" + }, + { + "name": "C++" + }, + { + "name": "Eagle" + }, + { + "name": "Go" + }, + { + "name": "OpenCart" + }, + { + "name": "Scheme" + }, + { + "name": "Typo3" + }, + { + "name": "SeamGen" + }, + { + "name": "Swift" + }, + { + "name": "Elm" + }, + { + "name": "Unity" + }, + { + "name": "Agda" + }, + { + "name": "CUDA" + }, + { + "name": "VVVV" + }, + { + "name": "Finale" + }, + { + "name": "LemonStand" + }, + { + "name": "Textpattern" + }, + { + "name": "Julia" + }, + { + "name": "Packer" + }, + { + "name": "Scrivener" + }, + { + "name": "Dart" + }, + { + "name": "Plone" + }, + { + "name": "Jekyll" + }, + { + "name": "Xojo" + }, + { + "name": "LabVIEW" + }, + { + "name": "Autotools" + }, + { + "name": "KiCad" + }, + { + "name": "Prestashop" + }, + { + "name": "ROS" + }, + { + "name": "Smalltalk" + }, + { + "name": "GWT" + }, + { + "name": "OracleForms" + }, + { + "name": "SugarCRM" + }, + { + "name": "Nim" + }, + { + "name": "SymphonyCMS" + }, + { + "name": "Maven" + }, + { + "name": "CFWheels" + }, + { + "name": "Python" + }, + { + "name": "ZendFramework" + }, + { + "name": "CakePHP" + }, + { + "name": "Concrete5" + }, + { + "name": "PlayFramework" + }, + { + "name": "Terraform" + }, + { + "name": "Elixir" + }, + { + "name": "CMake" + }, + { + "name": "Joomla" + }, + { + "name": "Coq" + }, + { + "name": "Delphi" + }, + { + "name": "Haskell" + }, + { + "name": "Yii" + }, + { + "name": "Java" + }, + { + "name": "UnrealEngine" + }, + { + "name": "AppceleratorTitanium" + }, + { + "name": "CraftCMS" + }, + { + "name": "ForceDotCom" + }, + { + "name": "ExtJs" + }, + { + "name": "MetaProgrammingSystem" + }, + { + "name": "D" + }, + { + "name": "Objective-C" + }, + { + "name": "RhodesRhomobile" + }, + { + "name": "R" + }, + { + "name": "EPiServer" + }, + { + "name": "Yeoman" + }, + { + "name": "VisualStudio" + }, + { + "name": "Processing" + }, + { + "name": "Leiningen" + }, + { + "name": "Stella" + }, + { + "name": "Opa" + }, + { + "name": "Drupal" + }, + { + "name": "TurboGears2" + }, + { + "name": "Idris" + }, + { + "name": "Jboss" + }, + { + "name": "CodeIgniter" + }, + { + "name": "Qooxdoo" + }, + { + "name": "Waf" + }, + { + "name": "Sass" + }, + { + "name": "Lua" + }, + { + "name": "Clojure" + }, + { + "name": "IGORPro" + }, + { + "name": "Gradle" + }, + { + "name": "Archives" + }, + { + "name": "SynopsysVCS" + }, + { + "name": "Ninja" + }, + { + "name": "Tags" + }, + { + "name": "OSX" + }, + { + "name": "Dreamweaver" + }, + { + "name": "CodeKit" + }, + { + "name": "NotepadPP" + }, + { + "name": "VisualStudioCode" + }, + { + "name": "Mercurial" + }, + { + "name": "BricxCC" + }, + { + "name": "DartEditor" + }, + { + "name": "Eclipse" + }, + { + "name": "Cloud9" + }, + { + "name": "TortoiseGit" + }, + { + "name": "NetBeans" + }, + { + "name": "GPG" + }, + { + "name": "Espresso" + }, + { + "name": "Redcar" + }, + { + "name": "Xcode" + }, + { + "name": "Matlab" + }, + { + "name": "LyX" + }, + { + "name": "SlickEdit" + }, + { + "name": "Dropbox" + }, + { + "name": "CVS" + }, + { + "name": "Calabash" + }, + { + "name": "JDeveloper" + }, + { + "name": "Vagrant" + }, + { + "name": "IPythonNotebook" + }, + { + "name": "TextMate" + }, + { + "name": "Ensime" + }, + { + "name": "WebMethods" + }, + { + "name": "VirtualEnv" + }, + { + "name": "Emacs" + }, + { + "name": "Momentics" + }, + { + "name": "JetBrains" + }, + { + "name": "SublimeText" + }, + { + "name": "Kate" + }, + { + "name": "ModelSim" + }, + { + "name": "Redis" + }, + { + "name": "KDevelop4" + }, + { + "name": "Bazaar" + }, + { + "name": "Linux" + }, + { + "name": "Windows" + }, + { + "name": "XilinxISE" + }, + { + "name": "Lazarus" + }, + { + "name": "EiffelStudio" + }, + { + "name": "Anjuta" + }, + { + "name": "Vim" + }, + { + "name": "Otto" + }, + { + "name": "MicrosoftOffice" + }, + { + "name": "LibreOffice" + }, + { + "name": "SBT" + }, + { + "name": "MonoDevelop" + }, + { + "name": "SVN" + }, + { + "name": "FlexBuilder" + } +] +``` + +## Single gitignore template + +Get a single gitignore template. + +``` +GET /templates/gitignores/:key +``` + +| Attribute | Type | Required | Description | +| ---------- | ------ | -------- | ----------- | +| `key` | string | yes | The key of the gitignore template | + +```bash +curl https://gitlab.example.com/api/v3/templates/gitignores/Ruby +``` + +Example response: + +```json +{ + "name": "Ruby", + "content": "*.gem\n*.rbc\n/.config\n/coverage/\n/InstalledFiles\n/pkg/\n/spec/reports/\n/spec/examples.txt\n/test/tmp/\n/test/version_tmp/\n/tmp/\n\n# Used by dotenv library to load environment variables.\n# .env\n\n## Specific to RubyMotion:\n.dat*\n.repl_history\nbuild/\n*.bridgesupport\nbuild-iPhoneOS/\nbuild-iPhoneSimulator/\n\n## Specific to RubyMotion (use of CocoaPods):\n#\n# We recommend against adding the Pods directory to your .gitignore. However\n# you should judge for yourself, the pros and cons are mentioned at:\n# https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control\n#\n# vendor/Pods/\n\n## Documentation cache and generated files:\n/.yardoc/\n/_yardoc/\n/doc/\n/rdoc/\n\n## Environment normalization:\n/.bundle/\n/vendor/bundle\n/lib/bundler/man/\n\n# for a library or gem, you might want to ignore these files since the code is\n# intended to run in multiple environments; otherwise, check them in:\n# Gemfile.lock\n# .ruby-version\n# .ruby-gemset\n\n# unless supporting rvm < 1.11.0 or doing something fancy, ignore this:\n.rvmrc\n" +} +``` diff --git a/doc/api/templates/gitlab_ci_ymls.md b/doc/api/templates/gitlab_ci_ymls.md new file mode 100644 index 00000000000..e120016fbe6 --- /dev/null +++ b/doc/api/templates/gitlab_ci_ymls.md @@ -0,0 +1,120 @@ +# GitLab CI YMLs + +## List GitLab CI YML templates + +Get all GitLab CI YML templates. + +``` +GET /templates/gitlab_ci_ymls +``` + +```bash +curl https://gitlab.example.com/api/v3/templates/gitlab_ci_ymls +``` + +Example response: + +```json +[ + { + "name": "C++" + }, + { + "name": "Docker" + }, + { + "name": "Elixir" + }, + { + "name": "LaTeX" + }, + { + "name": "Grails" + }, + { + "name": "Rust" + }, + { + "name": "Nodejs" + }, + { + "name": "Ruby" + }, + { + "name": "Scala" + }, + { + "name": "Maven" + }, + { + "name": "Harp" + }, + { + "name": "Pelican" + }, + { + "name": "Hyde" + }, + { + "name": "Nanoc" + }, + { + "name": "Octopress" + }, + { + "name": "JBake" + }, + { + "name": "HTML" + }, + { + "name": "Hugo" + }, + { + "name": "Metalsmith" + }, + { + "name": "Hexo" + }, + { + "name": "Lektor" + }, + { + "name": "Doxygen" + }, + { + "name": "Brunch" + }, + { + "name": "Jekyll" + }, + { + "name": "Middleman" + } +] +``` + +## Single GitLab CI YML template + +Get a single GitLab CI YML template. + +``` +GET /templates/gitlab_ci_ymls/:key +``` + +| Attribute | Type | Required | Description | +| ---------- | ------ | -------- | ----------- | +| `key` | string | yes | The key of the GitLab CI YML template | + +```bash +curl https://gitlab.example.com/api/v3/templates/gitlab_ci_ymls/Ruby +``` + +Example response: + +```json +{ + "name": "Ruby", + "content": "# This file is a template, and might need editing before it works on your project.\n# Official language image. Look for the different tagged releases at:\n# https://hub.docker.com/r/library/ruby/tags/\nimage: \"ruby:2.3\"\n\n# Pick zero or more services to be used on all builds.\n# Only needed when using a docker container to run your tests in.\n# Check out: http://docs.gitlab.com/ce/ci/docker/using_docker_images.html#what-is-service\nservices:\n - mysql:latest\n - redis:latest\n - postgres:latest\n\nvariables:\n POSTGRES_DB: database_name\n\n# Cache gems in between builds\ncache:\n paths:\n - vendor/ruby\n\n# This is a basic example for a gem or script which doesn't use\n# services such as redis or postgres\nbefore_script:\n - ruby -v # Print out ruby version for debugging\n # Uncomment next line if your rails app needs a JS runtime:\n # - apt-get update -q && apt-get install nodejs -yqq\n - gem install bundler --no-ri --no-rdoc # Bundler is not installed with the image\n - bundle install -j $(nproc) --path vendor # Install dependencies into ./vendor/ruby\n\n# Optional - Delete if not using `rubocop`\nrubocop:\n script:\n - rubocop\n\nrspec:\n script:\n - rspec spec\n\nrails:\n variables:\n DATABASE_URL: \"postgresql://postgres:postgres@postgres:5432/$POSTGRES_DB\"\n script:\n - bundle exec rake db:migrate\n - bundle exec rake db:seed\n - bundle exec rake test\n" +} +``` diff --git a/doc/api/licenses.md b/doc/api/templates/licenses.md index ed26d1fb7fb..ae7218cf1bd 100644 --- a/doc/api/licenses.md +++ b/doc/api/templates/licenses.md @@ -5,7 +5,7 @@ Get all license templates. ``` -GET /licenses +GET /templates/licenses ``` | Attribute | Type | Required | Description | @@ -13,7 +13,7 @@ GET /licenses | `popular` | boolean | no | If passed, returns only popular licenses | ```bash -curl https://gitlab.example.com/api/v3/licenses?popular=1 +curl https://gitlab.example.com/api/v3/templates/licenses?popular=1 ``` Example response: @@ -102,7 +102,7 @@ Get a single license template. You can pass parameters to replace the license placeholder. ``` -GET /licenses/:key +GET /templates/licenses/:key ``` | Attribute | Type | Required | Description | @@ -116,7 +116,7 @@ If you omit the `fullname` parameter but authenticate your request, the name of the authenticated user will be used to replace the copyright holder placeholder. ```bash -curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v3/licenses/mit?project=My+Cool+Project +curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v3/templates/licenses/mit?project=My+Cool+Project ``` Example response: diff --git a/doc/api/version.md b/doc/api/version.md new file mode 100644 index 00000000000..287d17cf97f --- /dev/null +++ b/doc/api/version.md @@ -0,0 +1,23 @@ +# Version API + +>**Note:** This feature was introduced in GitLab 8.13 + +Retrieve version information for this GitLab instance. Responds `200 OK` for +authenticated users. + +``` +GET /version +``` + +```bash +curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v3/version +``` + +Example response: + +```json +{ + "version": "8.13.0-pre", + "revision": "4e963fe" +} +``` diff --git a/doc/development/frontend.md b/doc/development/frontend.md index f879cd57e25..56c8516508e 100644 --- a/doc/development/frontend.md +++ b/doc/development/frontend.md @@ -223,3 +223,14 @@ For our currently-supported browsers, see our [requirements][requirements]. [xss]: https://en.wikipedia.org/wiki/Cross-site_scripting [scss-style-guide]: scss_styleguide.md [requirements]: ../install/requirements.md#supported-web-browsers + +## Common Errors + +### Rspec (Capybara/Poltergeist) chokes on general JavaScript errors + +If you see very generic JavaScript errors (e.g. `jQuery is undefined`) being thrown in tests, but +can't reproduce them manually, you may have included `ES6`-style JavaScript in files that don't +have the `.js.es6` file extension. Either use ES5-friendly JavaScript or rename the file you're +working in (`git mv <file>.js> <file.js.es6>`). + + diff --git a/lib/api/api.rb b/lib/api/api.rb index 99722a0a65c..920d098bb24 100644 --- a/lib/api/api.rb +++ b/lib/api/api.rb @@ -46,7 +46,6 @@ module API mount ::API::Boards mount ::API::Keys mount ::API::Labels - mount ::API::LicenseTemplates mount ::API::Lint mount ::API::Members mount ::API::MergeRequests @@ -73,6 +72,7 @@ module API mount ::API::Triggers mount ::API::Users mount ::API::Variables + mount ::API::Version route :any, '*path' do error!('404 Not Found', 404) diff --git a/lib/api/license_templates.rb b/lib/api/license_templates.rb deleted file mode 100644 index d0552299ed0..00000000000 --- a/lib/api/license_templates.rb +++ /dev/null @@ -1,58 +0,0 @@ -module API - # License Templates API - class LicenseTemplates < Grape::API - PROJECT_TEMPLATE_REGEX = - /[\<\{\[] - (project|description| - one\sline\s.+\swhat\sit\sdoes\.) # matching the start and end is enough here - [\>\}\]]/xi.freeze - YEAR_TEMPLATE_REGEX = /[<{\[](year|yyyy)[>}\]]/i.freeze - FULLNAME_TEMPLATE_REGEX = - /[\<\{\[] - (fullname|name\sof\s(author|copyright\sowner)) - [\>\}\]]/xi.freeze - - # Get the list of the available license templates - # - # Parameters: - # popular - Filter licenses to only the popular ones - # - # Example Request: - # GET /licenses - # GET /licenses?popular=1 - get 'licenses' do - options = { - featured: params[:popular].present? ? true : nil - } - present Licensee::License.all(options), with: Entities::RepoLicense - end - - # Get text for specific license - # - # Parameters: - # key (required) - The key of a license - # project - Copyrighted project name - # fullname - Full name of copyright holder - # - # Example Request: - # GET /licenses/mit - # - get 'licenses/:key', requirements: { key: /[\w\.-]+/ } do - required_attributes! [:key] - - not_found!('License') unless Licensee::License.find(params[:key]) - - # We create a fresh Licensee::License object since we'll modify its - # content in place below. - license = Licensee::License.new(params[:key]) - - license.content.gsub!(YEAR_TEMPLATE_REGEX, Time.now.year.to_s) - license.content.gsub!(PROJECT_TEMPLATE_REGEX, params[:project]) if params[:project].present? - - fullname = params[:fullname].presence || current_user.try(:name) - license.content.gsub!(FULLNAME_TEMPLATE_REGEX, fullname) if fullname - - present license, with: Entities::RepoLicense - end - end -end diff --git a/lib/api/templates.rb b/lib/api/templates.rb index b9e718147e1..8a53d9c0095 100644 --- a/lib/api/templates.rb +++ b/lib/api/templates.rb @@ -1,39 +1,115 @@ module API class Templates < Grape::API GLOBAL_TEMPLATE_TYPES = { - gitignores: Gitlab::Template::GitignoreTemplate, - gitlab_ci_ymls: Gitlab::Template::GitlabCiYmlTemplate + gitignores: { + klass: Gitlab::Template::GitignoreTemplate, + gitlab_version: 8.8 + }, + gitlab_ci_ymls: { + klass: Gitlab::Template::GitlabCiYmlTemplate, + gitlab_version: 8.9 + } }.freeze + PROJECT_TEMPLATE_REGEX = + /[\<\{\[] + (project|description| + one\sline\s.+\swhat\sit\sdoes\.) # matching the start and end is enough here + [\>\}\]]/xi.freeze + YEAR_TEMPLATE_REGEX = /[<{\[](year|yyyy)[>}\]]/i.freeze + FULLNAME_TEMPLATE_REGEX = + /[\<\{\[] + (fullname|name\sof\s(author|copyright\sowner)) + [\>\}\]]/xi.freeze + DEPRECATION_MESSAGE = ' This endpoint is deprecated and will be removed in GitLab 9.0.'.freeze helpers do + def parsed_license_template + # We create a fresh Licensee::License object since we'll modify its + # content in place below. + template = Licensee::License.new(params[:name]) + + template.content.gsub!(YEAR_TEMPLATE_REGEX, Time.now.year.to_s) + template.content.gsub!(PROJECT_TEMPLATE_REGEX, params[:project]) if params[:project].present? + + fullname = params[:fullname].presence || current_user.try(:name) + template.content.gsub!(FULLNAME_TEMPLATE_REGEX, fullname) if fullname + template + end + def render_response(template_type, template) not_found!(template_type.to_s.singularize) unless template present template, with: Entities::Template end end - GLOBAL_TEMPLATE_TYPES.each do |template_type, klass| - # Get the list of the available template - # - # Example Request: - # GET /gitignores - # GET /gitlab_ci_ymls - get template_type.to_s do - present klass.all, with: Entities::TemplatesList - end - - # Get the text for a specific template present in local filesystem - # - # Parameters: - # name (required) - The name of a template - # - # Example Request: - # GET /gitignores/Elixir - # GET /gitlab_ci_ymls/Ruby - get "#{template_type}/:name" do - required_attributes! [:name] - new_template = klass.find(params[:name]) - render_response(template_type, new_template) + { "licenses" => :deprecated, "templates/licenses" => :ok }.each do |route, status| + desc 'Get the list of the available license template' do + detailed_desc = 'This feature was introduced in GitLab 8.7.' + detailed_desc << DEPRECATION_MESSAGE unless status == :ok + detail detailed_desc + success Entities::RepoLicense + end + params do + optional :popular, type: Boolean, desc: 'If passed, returns only popular licenses' + end + get route do + options = { + featured: declared(params).popular.present? ? true : nil + } + present Licensee::License.all(options), with: Entities::RepoLicense + end + end + + { "licenses/:name" => :deprecated, "templates/licenses/:name" => :ok }.each do |route, status| + desc 'Get the text for a specific license' do + detailed_desc = 'This feature was introduced in GitLab 8.7.' + detailed_desc << DEPRECATION_MESSAGE unless status == :ok + detail detailed_desc + success Entities::RepoLicense + end + params do + requires :name, type: String, desc: 'The name of the template' + end + get route, requirements: { name: /[\w\.-]+/ } do + not_found!('License') unless Licensee::License.find(declared(params).name) + + template = parsed_license_template + + present template, with: Entities::RepoLicense + end + end + + GLOBAL_TEMPLATE_TYPES.each do |template_type, properties| + klass = properties[:klass] + gitlab_version = properties[:gitlab_version] + + { template_type => :deprecated, "templates/#{template_type}" => :ok }.each do |route, status| + desc 'Get the list of the available template' do + detailed_desc = "This feature was introduced in GitLab #{gitlab_version}." + detailed_desc << DEPRECATION_MESSAGE unless status == :ok + detail detailed_desc + success Entities::TemplatesList + end + get route do + present klass.all, with: Entities::TemplatesList + end + end + + { "#{template_type}/:name" => :deprecated, "templates/#{template_type}/:name" => :ok }.each do |route, status| + desc 'Get the text for a specific template present in local filesystem' do + detailed_desc = "This feature was introduced in GitLab #{gitlab_version}." + detailed_desc << DEPRECATION_MESSAGE unless status == :ok + detail detailed_desc + success Entities::Template + end + params do + requires :name, type: String, desc: 'The name of the template' + end + get route do + new_template = klass.find(declared(params).name) + + render_response(template_type, new_template) + end end end end diff --git a/lib/api/version.rb b/lib/api/version.rb new file mode 100644 index 00000000000..9ba576bd828 --- /dev/null +++ b/lib/api/version.rb @@ -0,0 +1,12 @@ +module API + class Version < Grape::API + before { authenticate! } + + desc 'Get the version information of the GitLab instance.' do + detail 'This feature was introduced in GitLab 8.13.' + end + get '/version' do + { version: Gitlab::VERSION, revision: Gitlab::REVISION } + end + end +end diff --git a/spec/models/merge_request_diff_spec.rb b/spec/models/merge_request_diff_spec.rb index f27de0948ee..e5007424041 100644 --- a/spec/models/merge_request_diff_spec.rb +++ b/spec/models/merge_request_diff_spec.rb @@ -74,27 +74,43 @@ describe MergeRequestDiff, models: true do end end end + end - describe '#commits_sha' do - shared_examples 'returning all commits SHA' do - it 'returns all commits SHA' do - commits_sha = subject.commits_sha + describe '#commits_sha' do + shared_examples 'returning all commits SHA' do + it 'returns all commits SHA' do + commits_sha = subject.commits_sha - expect(commits_sha).to eq(subject.commits.map(&:sha)) - end + expect(commits_sha).to eq(subject.commits.map(&:sha)) end + end - context 'when commits were loaded' do - before do - subject.commits - end - - it_behaves_like 'returning all commits SHA' + context 'when commits were loaded' do + before do + subject.commits end - context 'when commits were not loaded' do - it_behaves_like 'returning all commits SHA' - end + it_behaves_like 'returning all commits SHA' + end + + context 'when commits were not loaded' do + it_behaves_like 'returning all commits SHA' + end + end + + describe '#compare_with' do + subject { create(:merge_request, source_branch: 'fix').merge_request_diff } + + it 'delegates compare to the service' do + expect(CompareService).to receive(:new).and_call_original + + subject.compare_with(nil) + end + + it 'uses git diff A..B approach by default' do + diffs = subject.compare_with('0b4bc9a49b562e85de7cc9e834518ea6828729b9').diffs + + expect(diffs.size).to eq(3) end end end diff --git a/spec/requests/api/license_templates_spec.rb b/spec/requests/api/license_templates_spec.rb deleted file mode 100644 index 9a1894d63a2..00000000000 --- a/spec/requests/api/license_templates_spec.rb +++ /dev/null @@ -1,136 +0,0 @@ -require 'spec_helper' - -describe API::API, api: true do - include ApiHelpers - - describe 'Entity' do - before { get api('/licenses/mit') } - - it { expect(json_response['key']).to eq('mit') } - it { expect(json_response['name']).to eq('MIT License') } - it { expect(json_response['nickname']).to be_nil } - it { expect(json_response['popular']).to be true } - it { expect(json_response['html_url']).to eq('http://choosealicense.com/licenses/mit/') } - it { expect(json_response['source_url']).to eq('https://opensource.org/licenses/MIT') } - it { expect(json_response['description']).to include('A permissive license that is short and to the point.') } - it { expect(json_response['conditions']).to eq(%w[include-copyright]) } - it { expect(json_response['permissions']).to eq(%w[commercial-use modifications distribution private-use]) } - it { expect(json_response['limitations']).to eq(%w[no-liability]) } - it { expect(json_response['content']).to include('The MIT License (MIT)') } - end - - describe 'GET /licenses' do - it 'returns a list of available license templates' do - get api('/licenses') - - expect(response).to have_http_status(200) - expect(json_response).to be_an Array - expect(json_response.size).to eq(15) - expect(json_response.map { |l| l['key'] }).to include('agpl-3.0') - end - - describe 'the popular parameter' do - context 'with popular=1' do - it 'returns a list of available popular license templates' do - get api('/licenses?popular=1') - - expect(response).to have_http_status(200) - expect(json_response).to be_an Array - expect(json_response.size).to eq(3) - expect(json_response.map { |l| l['key'] }).to include('apache-2.0') - end - end - end - end - - describe 'GET /licenses/:key' do - context 'with :project and :fullname given' do - before do - get api("/licenses/#{license_type}?project=My+Awesome+Project&fullname=Anton+#{license_type.upcase}") - end - - context 'for the mit license' do - let(:license_type) { 'mit' } - - it 'returns the license text' do - expect(json_response['content']).to include('The MIT License (MIT)') - end - - it 'replaces placeholder values' do - expect(json_response['content']).to include("Copyright (c) #{Time.now.year} Anton") - end - end - - context 'for the agpl-3.0 license' do - let(:license_type) { 'agpl-3.0' } - - it 'returns the license text' do - expect(json_response['content']).to include('GNU AFFERO GENERAL PUBLIC LICENSE') - end - - it 'replaces placeholder values' do - expect(json_response['content']).to include('My Awesome Project') - expect(json_response['content']).to include("Copyright (C) #{Time.now.year} Anton") - end - end - - context 'for the gpl-3.0 license' do - let(:license_type) { 'gpl-3.0' } - - it 'returns the license text' do - expect(json_response['content']).to include('GNU GENERAL PUBLIC LICENSE') - end - - it 'replaces placeholder values' do - expect(json_response['content']).to include('My Awesome Project') - expect(json_response['content']).to include("Copyright (C) #{Time.now.year} Anton") - end - end - - context 'for the gpl-2.0 license' do - let(:license_type) { 'gpl-2.0' } - - it 'returns the license text' do - expect(json_response['content']).to include('GNU GENERAL PUBLIC LICENSE') - end - - it 'replaces placeholder values' do - expect(json_response['content']).to include('My Awesome Project') - expect(json_response['content']).to include("Copyright (C) #{Time.now.year} Anton") - end - end - - context 'for the apache-2.0 license' do - let(:license_type) { 'apache-2.0' } - - it 'returns the license text' do - expect(json_response['content']).to include('Apache License') - end - - it 'replaces placeholder values' do - expect(json_response['content']).to include("Copyright #{Time.now.year} Anton") - end - end - - context 'for an uknown license' do - let(:license_type) { 'muth-over9000' } - - it 'returns a 404' do - expect(response).to have_http_status(404) - end - end - end - - context 'with no :fullname given' do - context 'with an authenticated user' do - let(:user) { create(:user) } - - it 'replaces the copyright owner placeholder with the name of the current user' do - get api('/licenses/mit', user) - - expect(json_response['content']).to include("Copyright (c) #{Time.now.year} #{user.name}") - end - end - end - end -end diff --git a/spec/requests/api/templates_spec.rb b/spec/requests/api/templates_spec.rb index 5bd5b861792..d32ba60fc4c 100644 --- a/spec/requests/api/templates_spec.rb +++ b/spec/requests/api/templates_spec.rb @@ -3,53 +3,201 @@ require 'spec_helper' describe API::Templates, api: true do include ApiHelpers - context 'global templates' do - describe 'the Template Entity' do - before { get api('/gitignores/Ruby') } + shared_examples_for 'the Template Entity' do |path| + before { get api(path) } - it { expect(json_response['name']).to eq('Ruby') } - it { expect(json_response['content']).to include('*.gem') } + it { expect(json_response['name']).to eq('Ruby') } + it { expect(json_response['content']).to include('*.gem') } + end + + shared_examples_for 'the TemplateList Entity' do |path| + before { get api(path) } + + it { expect(json_response.first['name']).not_to be_nil } + it { expect(json_response.first['content']).to be_nil } + end + + shared_examples_for 'requesting gitignores' do |path| + it 'returns a list of available gitignore templates' do + get api(path) + + expect(response).to have_http_status(200) + expect(json_response).to be_an Array + expect(json_response.size).to be > 15 end + end - describe 'the TemplateList Entity' do - before { get api('/gitignores') } + shared_examples_for 'requesting gitlab-ci-ymls' do |path| + it 'returns a list of available gitlab_ci_ymls' do + get api(path) - it { expect(json_response.first['name']).not_to be_nil } - it { expect(json_response.first['content']).to be_nil } + expect(response).to have_http_status(200) + expect(json_response).to be_an Array + expect(json_response.first['name']).not_to be_nil end + end + + shared_examples_for 'requesting gitlab-ci-yml for Ruby' do |path| + it 'adds a disclaimer on the top' do + get api(path) + + expect(response).to have_http_status(200) + expect(json_response['content']).to start_with("# This file is a template,") + end + end + + shared_examples_for 'the License Template Entity' do |path| + before { get api(path) } + + it 'returns a license template' do + expect(json_response['key']).to eq('mit') + expect(json_response['name']).to eq('MIT License') + expect(json_response['nickname']).to be_nil + expect(json_response['popular']).to be true + expect(json_response['html_url']).to eq('http://choosealicense.com/licenses/mit/') + expect(json_response['source_url']).to eq('https://opensource.org/licenses/MIT') + expect(json_response['description']).to include('A permissive license that is short and to the point.') + expect(json_response['conditions']).to eq(%w[include-copyright]) + expect(json_response['permissions']).to eq(%w[commercial-use modifications distribution private-use]) + expect(json_response['limitations']).to eq(%w[no-liability]) + expect(json_response['content']).to include('The MIT License (MIT)') + end + end - context 'requesting gitignores' do - describe 'GET /gitignores' do - it 'returns a list of available gitignore templates' do - get api('/gitignores') + shared_examples_for 'GET licenses' do |path| + it 'returns a list of available license templates' do + get api(path) - expect(response.status).to eq(200) + expect(response).to have_http_status(200) + expect(json_response).to be_an Array + expect(json_response.size).to eq(15) + expect(json_response.map { |l| l['key'] }).to include('agpl-3.0') + end + + describe 'the popular parameter' do + context 'with popular=1' do + it 'returns a list of available popular license templates' do + get api("#{path}?popular=1") + + expect(response).to have_http_status(200) expect(json_response).to be_an Array - expect(json_response.size).to be > 15 + expect(json_response.size).to eq(3) + expect(json_response.map { |l| l['key'] }).to include('apache-2.0') end end end + end - context 'requesting gitlab-ci-ymls' do - describe 'GET /gitlab_ci_ymls' do - it 'returns a list of available gitlab_ci_ymls' do - get api('/gitlab_ci_ymls') + shared_examples_for 'GET licenses/:name' do |path| + context 'with :project and :fullname given' do + before do + get api("#{path}/#{license_type}?project=My+Awesome+Project&fullname=Anton+#{license_type.upcase}") + end - expect(response.status).to eq(200) - expect(json_response).to be_an Array - expect(json_response.first['name']).not_to be_nil + context 'for the mit license' do + let(:license_type) { 'mit' } + + it 'returns the license text' do + expect(json_response['content']).to include('The MIT License (MIT)') + end + + it 'replaces placeholder values' do + expect(json_response['content']).to include("Copyright (c) #{Time.now.year} Anton") + end + end + + context 'for the agpl-3.0 license' do + let(:license_type) { 'agpl-3.0' } + + it 'returns the license text' do + expect(json_response['content']).to include('GNU AFFERO GENERAL PUBLIC LICENSE') + end + + it 'replaces placeholder values' do + expect(json_response['content']).to include('My Awesome Project') + expect(json_response['content']).to include("Copyright (C) #{Time.now.year} Anton") + end + end + + context 'for the gpl-3.0 license' do + let(:license_type) { 'gpl-3.0' } + + it 'returns the license text' do + expect(json_response['content']).to include('GNU GENERAL PUBLIC LICENSE') + end + + it 'replaces placeholder values' do + expect(json_response['content']).to include('My Awesome Project') + expect(json_response['content']).to include("Copyright (C) #{Time.now.year} Anton") + end + end + + context 'for the gpl-2.0 license' do + let(:license_type) { 'gpl-2.0' } + + it 'returns the license text' do + expect(json_response['content']).to include('GNU GENERAL PUBLIC LICENSE') + end + + it 'replaces placeholder values' do + expect(json_response['content']).to include('My Awesome Project') + expect(json_response['content']).to include("Copyright (C) #{Time.now.year} Anton") + end + end + + context 'for the apache-2.0 license' do + let(:license_type) { 'apache-2.0' } + + it 'returns the license text' do + expect(json_response['content']).to include('Apache License') + end + + it 'replaces placeholder values' do + expect(json_response['content']).to include("Copyright #{Time.now.year} Anton") + end + end + + context 'for an uknown license' do + let(:license_type) { 'muth-over9000' } + + it 'returns a 404' do + expect(response).to have_http_status(404) end end end - describe 'GET /gitlab_ci_ymls/Ruby' do - it 'adds a disclaimer on the top' do - get api('/gitlab_ci_ymls/Ruby') + context 'with no :fullname given' do + context 'with an authenticated user' do + let(:user) { create(:user) } + + it 'replaces the copyright owner placeholder with the name of the current user' do + get api('/templates/licenses/mit', user) - expect(response).to have_http_status(200) - expect(json_response['name']).not_to be_nil - expect(json_response['content']).to start_with("# This file is a template,") + expect(json_response['content']).to include("Copyright (c) #{Time.now.year} #{user.name}") + end end end end + + describe 'with /templates namespace' do + it_behaves_like 'the Template Entity', '/templates/gitignores/Ruby' + it_behaves_like 'the TemplateList Entity', '/templates/gitignores' + it_behaves_like 'requesting gitignores', '/templates/gitignores' + it_behaves_like 'requesting gitlab-ci-ymls', '/templates/gitlab_ci_ymls' + it_behaves_like 'requesting gitlab-ci-yml for Ruby', '/templates/gitlab_ci_ymls/Ruby' + it_behaves_like 'the License Template Entity', '/templates/licenses/mit' + it_behaves_like 'GET licenses', '/templates/licenses' + it_behaves_like 'GET licenses/:name', '/templates/licenses' + end + + describe 'without /templates namespace' do + it_behaves_like 'the Template Entity', '/gitignores/Ruby' + it_behaves_like 'the TemplateList Entity', '/gitignores' + it_behaves_like 'requesting gitignores', '/gitignores' + it_behaves_like 'requesting gitlab-ci-ymls', '/gitlab_ci_ymls' + it_behaves_like 'requesting gitlab-ci-yml for Ruby', '/gitlab_ci_ymls/Ruby' + it_behaves_like 'the License Template Entity', '/licenses/mit' + it_behaves_like 'GET licenses', '/licenses' + it_behaves_like 'GET licenses/:name', '/licenses' + end end diff --git a/spec/requests/api/version_spec.rb b/spec/requests/api/version_spec.rb new file mode 100644 index 00000000000..54b69a0cae7 --- /dev/null +++ b/spec/requests/api/version_spec.rb @@ -0,0 +1,27 @@ +require 'spec_helper' + +describe API::API, api: true do + include ApiHelpers + + describe 'GET /version' do + context 'when unauthenticated' do + it 'returns authentication error' do + get api('/version') + + expect(response).to have_http_status(401) + end + end + + context 'when authenticated' do + let(:user) { create(:user) } + + it 'returns the version information' do + get api('/version', user) + + expect(response).to have_http_status(200) + expect(json_response['version']).to eq(Gitlab::VERSION) + expect(json_response['revision']).to eq(Gitlab::REVISION) + end + end + end +end diff --git a/spec/services/compare_service_spec.rb b/spec/services/compare_service_spec.rb new file mode 100644 index 00000000000..3760f19aaa2 --- /dev/null +++ b/spec/services/compare_service_spec.rb @@ -0,0 +1,21 @@ +require 'spec_helper' + +describe CompareService, services: true do + let(:project) { create(:project) } + let(:user) { create(:user) } + let(:service) { described_class.new } + + describe '#execute' do + context 'compare with base, like feature...fix' do + subject { service.execute(project, 'feature', project, 'fix', straight: false) } + + it { expect(subject.diffs.size).to eq(1) } + end + + context 'straight compare, like feature..fix' do + subject { service.execute(project, 'feature', project, 'fix', straight: true) } + + it { expect(subject.diffs.size).to eq(3) } + end + end +end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index f313bd4f249..b19f5824236 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -50,11 +50,6 @@ RSpec.configure do |config| example.run Rails.cache = caching_store end - - config.after(:each) do - FileUtils.rm_rf("tmp/tests/repositories") - FileUtils.mkdir_p("tmp/tests/repositories") - end end FactoryGirl::SyntaxRunner.class_eval do |