summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJames Lopez <james@jameslopez.es>2016-05-23 09:09:02 +0200
committerJames Lopez <james@jameslopez.es>2016-05-23 09:09:02 +0200
commit6e3df42ca33e7fb6b8d79647fe99c5a6e8159484 (patch)
treed1998e8abab98b096ebbbea79f5a34a9c9a2167e
parentf2f345e6048f80e4d6510db102cd046fca43d4e4 (diff)
parent53ad33e4ba1b079e4f2aebceb42a7301c5ce2e4a (diff)
downloadgitlab-ce-6e3df42ca33e7fb6b8d79647fe99c5a6e8159484.tar.gz
fix merge conflicts
-rw-r--r--.rubocop.yml1
-rw-r--r--CHANGELOG46
-rw-r--r--Gemfile2
-rw-r--r--Gemfile.lock12
-rw-r--r--app/assets/images/ci/arch.jpgbin25222 -> 0 bytes
-rw-r--r--app/assets/images/ci/favicon.icobin5430 -> 0 bytes
-rw-r--r--app/assets/images/ci/loader.gifbin4405 -> 0 bytes
-rw-r--r--app/assets/images/ci/no_avatar.pngbin1337 -> 0 bytes
-rw-r--r--app/assets/images/ci/rails.pngbin6646 -> 0 bytes
-rw-r--r--app/assets/images/ci/service_sample.pngbin76024 -> 0 bytes
-rw-r--r--app/assets/javascripts/api.js.coffee35
-rw-r--r--app/assets/javascripts/blob/blob_gitignore_selector.js.coffee58
-rw-r--r--app/assets/javascripts/blob/edit_blob.js.coffee1
-rw-r--r--app/assets/javascripts/gfm_auto_complete.js.coffee19
-rw-r--r--app/assets/javascripts/gl_dropdown.js.coffee82
-rw-r--r--app/assets/javascripts/issuable_form.js.coffee9
-rw-r--r--app/assets/javascripts/lib/type_utility.js.coffee9
-rw-r--r--app/assets/javascripts/merge_request_widget.js.coffee4
-rw-r--r--app/assets/stylesheets/application.scss1
-rw-r--r--app/assets/stylesheets/framework.scss1
-rw-r--r--app/assets/stylesheets/framework/animations.scss72
-rw-r--r--app/assets/stylesheets/framework/files.scss16
-rw-r--r--app/assets/stylesheets/framework/forms.scss8
-rw-r--r--app/assets/stylesheets/framework/typography.scss8
-rw-r--r--app/assets/stylesheets/framework/variables.scss3
-rw-r--r--app/assets/stylesheets/framework/zen.scss2
-rw-r--r--app/assets/stylesheets/mailers/repository_push_email.scss43
-rw-r--r--app/assets/stylesheets/pages/editor.scss21
-rw-r--r--app/assets/stylesheets/pages/pipelines.scss4
-rw-r--r--app/assets/stylesheets/pages/projects.scss8
-rw-r--r--app/controllers/admin/abuse_reports_controller.rb2
-rw-r--r--app/controllers/admin/broadcast_messages_controller.rb2
-rw-r--r--app/controllers/admin/keys_controller.rb2
-rw-r--r--app/controllers/admin/runners_controller.rb35
-rw-r--r--app/controllers/admin/spam_logs_controller.rb2
-rw-r--r--app/controllers/admin/users_controller.rb2
-rw-r--r--app/controllers/concerns/toggle_subscription_action.rb2
-rw-r--r--app/controllers/dashboard/todos_controller.rb4
-rw-r--r--app/controllers/groups/group_members_controller.rb2
-rw-r--r--app/controllers/jwt_controller.rb2
-rw-r--r--app/controllers/profiles/emails_controller.rb2
-rw-r--r--app/controllers/profiles/keys_controller.rb2
-rw-r--r--app/controllers/projects/container_registry_controller.rb34
-rw-r--r--app/controllers/projects/imports_controller.rb1
-rw-r--r--app/controllers/projects/merge_requests_controller.rb3
-rw-r--r--app/controllers/projects/milestones_controller.rb2
-rw-r--r--app/controllers/projects/notes_controller.rb4
-rw-r--r--app/controllers/projects/pipelines_controller.rb59
-rw-r--r--app/controllers/projects/project_members_controller.rb4
-rw-r--r--app/controllers/projects/protected_branches_controller.rb2
-rw-r--r--app/controllers/projects/runners_controller.rb2
-rw-r--r--app/controllers/projects/variables_controller.rb30
-rw-r--r--app/controllers/projects_controller.rb9
-rw-r--r--app/controllers/registrations_controller.rb2
-rw-r--r--app/finders/pipelines_finder.rb38
-rw-r--r--app/finders/todos_finder.rb2
-rw-r--r--app/helpers/blob_helper.rb10
-rw-r--r--app/helpers/ci_status_helper.rb29
-rw-r--r--app/helpers/diff_helper.rb4
-rw-r--r--app/helpers/emails_helper.rb6
-rw-r--r--app/helpers/gitlab_routing_helper.rb4
-rw-r--r--app/helpers/projects_helper.rb14
-rw-r--r--app/helpers/todos_helper.rb8
-rw-r--r--app/mailers/emails/projects.rb3
-rw-r--r--app/mailers/notify.rb2
-rw-r--r--app/models/ability.rb6
-rw-r--r--app/models/application_setting.rb2
-rw-r--r--app/models/ci/build.rb7
-rw-r--r--app/models/ci/commit.rb24
-rw-r--r--app/models/ci/runner.rb17
-rw-r--r--app/models/commit_status.rb17
-rw-r--r--app/models/merge_request.rb17
-rw-r--r--app/models/merge_request_diff.rb4
-rw-r--r--app/models/milestone.rb58
-rw-r--r--app/models/namespace.rb8
-rw-r--r--app/models/project.rb79
-rw-r--r--app/models/project_services/slack_service/issue_message.rb19
-rw-r--r--app/models/repository.rb40
-rw-r--r--app/models/todo.rb9
-rw-r--r--app/models/user.rb9
-rw-r--r--app/services/auth/container_registry_authentication_service.rb13
-rw-r--r--app/services/ci/create_pipeline_service.rb50
-rw-r--r--app/services/create_commit_builds_service.rb17
-rw-r--r--app/services/issues/update_service.rb10
-rw-r--r--app/services/merge_requests/add_todo_when_build_fails_service.rb17
-rw-r--r--app/services/merge_requests/base_service.rb25
-rw-r--r--app/services/merge_requests/create_service.rb7
-rw-r--r--app/services/merge_requests/merge_service.rb8
-rw-r--r--app/services/merge_requests/merge_when_build_succeeds_service.rb23
-rw-r--r--app/services/merge_requests/refresh_service.rb7
-rw-r--r--app/services/merge_requests/update_service.rb2
-rw-r--r--app/services/projects/autocomplete_service.rb4
-rw-r--r--app/services/projects/create_service.rb21
-rw-r--r--app/services/projects/destroy_service.rb10
-rw-r--r--app/services/projects/transfer_service.rb5
-rw-r--r--app/services/system_note_service.rb25
-rw-r--r--app/services/todo_service.rb30
-rw-r--r--app/views/admin/runners/show.html.haml2
-rw-r--r--app/views/dashboard/todos/_todo.html.haml12
-rw-r--r--app/views/groups/_activities.html.haml2
-rw-r--r--app/views/groups/issues.atom.builder8
-rw-r--r--app/views/layouts/nav/_project.html.haml15
-rw-r--r--app/views/layouts/notify.html.haml1
-rw-r--r--app/views/notify/repository_push_email.html.haml59
-rw-r--r--app/views/notify/repository_push_email.text.haml38
-rw-r--r--app/views/projects/_md_preview.html.haml2
-rw-r--r--app/views/projects/_zen.html.haml2
-rw-r--r--app/views/projects/blob/_editor.html.haml3
-rw-r--r--app/views/projects/buttons/_fork.html.haml5
-rw-r--r--app/views/projects/ci/builds/_build.html.haml38
-rw-r--r--app/views/projects/ci/commits/_commit.html.haml77
-rw-r--r--app/views/projects/commit/_builds.html.haml2
-rw-r--r--app/views/projects/commit/_ci_commit.html.haml70
-rw-r--r--app/views/projects/commit/_ci_stage.html.haml14
-rw-r--r--app/views/projects/commit/_commit_box.html.haml18
-rw-r--r--app/views/projects/commits/_commit.html.haml2
-rw-r--r--app/views/projects/commits/_commits.html.haml2
-rw-r--r--app/views/projects/container_registry/_header_title.html.haml1
-rw-r--r--app/views/projects/container_registry/_tag.html.haml21
-rw-r--r--app/views/projects/container_registry/index.html.haml40
-rw-r--r--app/views/projects/deploy_keys/index.html.haml4
-rw-r--r--app/views/projects/diffs/_file.html.haml8
-rw-r--r--app/views/projects/empty.html.haml10
-rw-r--r--app/views/projects/generic_commit_statuses/_generic_commit_status.html.haml9
-rw-r--r--app/views/projects/hooks/index.html.haml2
-rw-r--r--app/views/projects/issues/_merge_requests.html.haml2
-rw-r--r--app/views/projects/issues/_related_branches.html.haml2
-rw-r--r--app/views/projects/merge_requests/_merge_request.html.haml2
-rw-r--r--app/views/projects/merge_requests/widget/open/_accept.html.haml5
-rw-r--r--app/views/projects/merge_requests/widget/open/_merge_when_build_succeeds.html.haml5
-rw-r--r--app/views/projects/merge_requests/widget/open/_not_allowed.html.haml4
-rw-r--r--app/views/projects/pipelines/_header_title.html.haml1
-rw-r--r--app/views/projects/pipelines/_info.html.haml37
-rw-r--r--app/views/projects/pipelines/index.html.haml66
-rw-r--r--app/views/projects/pipelines/new.html.haml22
-rw-r--r--app/views/projects/pipelines/show.html.haml9
-rw-r--r--app/views/projects/protected_branches/_branches_list.html.haml2
-rw-r--r--app/views/projects/runners/_form.html.haml7
-rw-r--r--app/views/projects/runners/_runner.html.haml2
-rw-r--r--app/views/projects/runners/edit.html.haml1
-rw-r--r--app/views/projects/runners/show.html.haml51
-rw-r--r--app/views/projects/triggers/index.html.haml2
-rw-r--r--app/views/projects/variables/_content.html.haml8
-rw-r--r--app/views/projects/variables/_form.html.haml10
-rw-r--r--app/views/projects/variables/_table.html.haml25
-rw-r--r--app/views/projects/variables/index.html.haml17
-rw-r--r--app/views/projects/variables/show.html.haml41
-rw-r--r--app/views/shared/groups/_list.html.haml2
-rw-r--r--app/views/shared/issuable/_form.html.haml89
-rw-r--r--app/views/shared/milestones/_participants_tab.html.haml2
-rw-r--r--app/views/shared/projects/_project.html.haml2
-rw-r--r--app/workers/emails_on_push_worker.rb18
-rw-r--r--app/workers/repository_import_worker.rb2
-rw-r--r--config/application.rb5
-rw-r--r--config/gitlab.yml.example9
-rw-r--r--config/initializers/1_settings.rb3
-rw-r--r--config/routes.rb11
-rw-r--r--db/migrate/20160302152808_remove_wrong_import_url_from_projects.rb2
-rw-r--r--db/migrate/20160308212903_add_default_group_visibility_to_application_settings.rb4
-rw-r--r--db/migrate/20160504112519_add_run_untagged_to_ci_runner.rb13
-rw-r--r--db/schema.rb8
-rw-r--r--doc/README.md2
-rw-r--r--doc/administration/container_registry.md375
-rw-r--r--doc/api/README.md2
-rw-r--r--doc/api/groups.md2
-rw-r--r--doc/api/runners.md4
-rw-r--r--doc/ci/examples/deployment/README.md (renamed from doc/ci/deployment/README.md)0
-rw-r--r--doc/ci/quick_start/README.md4
-rw-r--r--doc/ci/runners/README.md8
-rw-r--r--doc/ci/triggers/README.md2
-rw-r--r--doc/ci/yaml/README.md2
-rw-r--r--doc/development/migration_style_guide.md46
-rw-r--r--doc/markdown/markdown.md49
-rw-r--r--doc/monitoring/health_check.md66
-rw-r--r--doc/monitoring/img/health_check_token.pngbin0 -> 10884 bytes
-rw-r--r--doc/permissions/permissions.md1
-rw-r--r--doc/workflow/lfs/manage_large_binaries_with_git_lfs.md2
-rw-r--r--doc/workflow/notifications.md2
-rw-r--r--features/steps/dashboard/dashboard.rb2
-rw-r--r--features/steps/project/commits/commits.rb4
-rw-r--r--features/steps/project/merge_requests.rb2
-rw-r--r--generator_templates/active_record/migration/create_table_migration.rb35
-rw-r--r--generator_templates/active_record/migration/migration.rb55
-rw-r--r--lib/api/api.rb1
-rw-r--r--lib/api/entities.rb9
-rw-r--r--lib/api/gitignores.rb29
-rw-r--r--lib/api/notes.rb47
-rw-r--r--lib/api/runners.rb2
-rw-r--r--lib/backup/manager.rb2
-rw-r--r--lib/backup/registry.rb13
-rw-r--r--lib/banzai/filter/inline_diff_filter.rb22
-rw-r--r--lib/banzai/filter/milestone_reference_filter.rb44
-rw-r--r--lib/banzai/pipeline/gfm_pipeline.rb3
-rw-r--r--lib/ci/api/runners.rb18
-rw-r--r--lib/container_registry/blob.rb48
-rw-r--r--lib/container_registry/client.rb61
-rw-r--r--lib/container_registry/config.rb16
-rw-r--r--lib/container_registry/registry.rb21
-rw-r--r--lib/container_registry/repository.rb48
-rw-r--r--lib/container_registry/tag.rb77
-rw-r--r--lib/gitlab/bitbucket_import/project_creator.rb7
-rw-r--r--lib/gitlab/database/migration_helpers.rb142
-rw-r--r--lib/gitlab/diff/inline_diff_marker.rb36
-rw-r--r--lib/gitlab/email/message/repository_push.rb7
-rw-r--r--lib/gitlab/fogbugz_import/project_creator.rb9
-rw-r--r--lib/gitlab/gitignore.rb56
-rw-r--r--lib/gitlab/gitlab_import/importer.rb2
-rw-r--r--lib/gitlab/google_code_import/project_creator.rb9
-rw-r--r--lib/gitlab/regex.rb4
-rw-r--r--lib/gitlab/sanitizers/svg.rb8
-rw-r--r--lib/gitlab/sanitizers/svg/whitelist.rb170
-rw-r--r--lib/gitlab/url_sanitizer.rb (renamed from lib/gitlab/import_url.rb)17
-rw-r--r--lib/support/nginx/registry-ssl53
-rw-r--r--lib/tasks/gitlab/backup.rake21
-rw-r--r--lib/tasks/gitlab/check.rake2
-rw-r--r--lib/tasks/gitlab/update_gitignore.rake46
-rw-r--r--shared/registry/.gitkeep0
-rw-r--r--spec/controllers/projects/notification_settings_controller_spec.rb14
-rw-r--r--spec/controllers/projects/raw_controller_spec.rb2
-rw-r--r--spec/controllers/projects_controller_spec.rb34
-rw-r--r--spec/factories/todos.rb4
-rw-r--r--spec/features/container_registry_spec.rb44
-rw-r--r--spec/features/issues_spec.rb60
-rw-r--r--spec/features/markdown_spec.rb4
-rw-r--r--spec/features/pipelines_spec.rb159
-rw-r--r--spec/features/projects/files/gitignore_dropdown_spec.rb30
-rw-r--r--spec/features/projects/files/project_owner_creates_license_file_spec.rb8
-rw-r--r--spec/features/projects/files/project_owner_sees_link_to_create_license_file_in_empty_project_spec.rb4
-rw-r--r--spec/features/runners_spec.rb33
-rw-r--r--spec/features/variables_spec.rb61
-rw-r--r--spec/fixtures/container_registry/config_blob.json1
-rw-r--r--spec/fixtures/container_registry/tag_manifest.json1
-rw-r--r--spec/fixtures/markdown.md.erb23
-rw-r--r--spec/helpers/diff_helper_spec.rb4
-rw-r--r--spec/javascripts/project_title_spec.js.coffee1
-rw-r--r--spec/lib/banzai/filter/inline_diff_filter_spec.rb68
-rw-r--r--spec/lib/banzai/filter/milestone_reference_filter_spec.rb151
-rw-r--r--spec/lib/container_registry/blob_spec.rb61
-rw-r--r--spec/lib/container_registry/registry_spec.rb28
-rw-r--r--spec/lib/container_registry/repository_spec.rb65
-rw-r--r--spec/lib/container_registry/tag_spec.rb89
-rw-r--r--spec/lib/gitlab/database/migration_helpers_spec.rb128
-rw-r--r--spec/lib/gitlab/email/message/repository_push_spec.rb2
-rw-r--r--spec/lib/gitlab/gitignore_spec.rb40
-rw-r--r--spec/lib/gitlab/import_url_spec.rb22
-rw-r--r--spec/lib/gitlab/url_sanitizer_spec.rb68
-rw-r--r--spec/mailers/notify_spec.rb16
-rw-r--r--spec/models/build_spec.rb50
-rw-r--r--spec/models/ci/commit_spec.rb1
-rw-r--r--spec/models/ci/runner_spec.rb32
-rw-r--r--spec/models/merge_request_spec.rb7
-rw-r--r--spec/models/namespace_spec.rb14
-rw-r--r--spec/models/project_services/slack_service/issue_message_spec.rb11
-rw-r--r--spec/models/project_spec.rb82
-rw-r--r--spec/models/repository_spec.rb24
-rw-r--r--spec/requests/api/gitignores_spec.rb29
-rw-r--r--spec/requests/api/licenses_spec.rb12
-rw-r--r--spec/requests/api/notes_spec.rb67
-rw-r--r--spec/requests/api/runners_spec.rb15
-rw-r--r--spec/requests/ci/api/builds_spec.rb32
-rw-r--r--spec/requests/ci/api/runners_spec.rb83
-rw-r--r--spec/requests/jwt_controller_spec.rb2
-rw-r--r--spec/services/auth/container_registry_authentication_service_spec.rb45
-rw-r--r--spec/services/issues/update_service_spec.rb24
-rw-r--r--spec/services/merge_requests/add_todo_when_build_fails_service_spec.rb81
-rw-r--r--spec/services/merge_requests/create_service_spec.rb4
-rw-r--r--spec/services/merge_requests/merge_service_spec.rb15
-rw-r--r--spec/services/merge_requests/refresh_service_spec.rb28
-rw-r--r--spec/services/merge_requests/update_service_spec.rb8
-rw-r--r--spec/services/notification_service_spec.rb30
-rw-r--r--spec/services/projects/destroy_service_spec.rb23
-rw-r--r--spec/services/projects/transfer_service_spec.rb11
-rw-r--r--spec/services/system_note_service_spec.rb14
-rw-r--r--spec/services/todo_service_spec.rb19
-rw-r--r--spec/support/markdown_feature.rb6
-rw-r--r--spec/support/matchers/markdown_matchers.rb12
-rw-r--r--spec/support/stub_gitlab_calls.rb17
-rw-r--r--spec/tasks/gitlab/backup_rake_spec.rb14
-rw-r--r--spec/workers/post_receive_spec.rb16
-rw-r--r--spec/workers/repository_import_worker_spec.rb26
-rw-r--r--vendor/assets/stylesheets/animate.css11
-rw-r--r--vendor/gitignore/Actionscript.gitignore19
-rw-r--r--vendor/gitignore/Ada.gitignore5
-rw-r--r--vendor/gitignore/Agda.gitignore1
-rw-r--r--vendor/gitignore/Android.gitignore39
-rw-r--r--vendor/gitignore/AppEngine.gitignore2
-rw-r--r--vendor/gitignore/AppceleratorTitanium.gitignore3
-rw-r--r--vendor/gitignore/ArchLinuxPackages.gitignore13
-rw-r--r--vendor/gitignore/Autotools.gitignore18
-rw-r--r--vendor/gitignore/C++.gitignore28
-rw-r--r--vendor/gitignore/C.gitignore33
-rw-r--r--vendor/gitignore/CFWheels.gitignore12
-rw-r--r--vendor/gitignore/CMake.gitignore6
-rw-r--r--vendor/gitignore/CUDA.gitignore6
-rw-r--r--vendor/gitignore/CakePHP.gitignore25
-rw-r--r--vendor/gitignore/ChefCookbook.gitignore9
l---------vendor/gitignore/Clojure.gitignore1
-rw-r--r--vendor/gitignore/CodeIgniter.gitignore6
-rw-r--r--vendor/gitignore/CommonLisp.gitignore3
-rw-r--r--vendor/gitignore/Composer.gitignore6
-rw-r--r--vendor/gitignore/Concrete5.gitignore4
-rw-r--r--vendor/gitignore/Coq.gitignore3
-rw-r--r--vendor/gitignore/CraftCMS.gitignore3
-rw-r--r--vendor/gitignore/D.gitignore20
-rw-r--r--vendor/gitignore/DM.gitignore5
-rw-r--r--vendor/gitignore/Dart.gitignore27
-rw-r--r--vendor/gitignore/Delphi.gitignore66
-rw-r--r--vendor/gitignore/Drupal.gitignore36
-rw-r--r--vendor/gitignore/EPiServer.gitignore4
-rw-r--r--vendor/gitignore/Eagle.gitignore44
-rw-r--r--vendor/gitignore/Elisp.gitignore5
-rw-r--r--vendor/gitignore/Elixir.gitignore5
-rw-r--r--vendor/gitignore/Elm.gitignore4
-rw-r--r--vendor/gitignore/Erlang.gitignore10
-rw-r--r--vendor/gitignore/ExpressionEngine.gitignore19
-rw-r--r--vendor/gitignore/ExtJs.gitignore4
-rw-r--r--vendor/gitignore/Fancy.gitignore2
-rw-r--r--vendor/gitignore/Finale.gitignore13
-rw-r--r--vendor/gitignore/ForceDotCom.gitignore4
l---------vendor/gitignore/Fortran.gitignore1
-rw-r--r--vendor/gitignore/FuelPHP.gitignore21
-rw-r--r--vendor/gitignore/GWT.gitignore28
-rw-r--r--vendor/gitignore/Gcov.gitignore5
-rw-r--r--vendor/gitignore/GitBook.gitignore16
-rw-r--r--vendor/gitignore/Global/Anjuta.gitignore3
-rw-r--r--vendor/gitignore/Global/Archives.gitignore27
-rw-r--r--vendor/gitignore/Global/BricxCC.gitignore4
-rw-r--r--vendor/gitignore/Global/CVS.gitignore4
-rw-r--r--vendor/gitignore/Global/Calabash.gitignore10
-rw-r--r--vendor/gitignore/Global/Cloud9.gitignore3
-rw-r--r--vendor/gitignore/Global/CodeKit.gitignore3
-rw-r--r--vendor/gitignore/Global/DartEditor.gitignore2
-rw-r--r--vendor/gitignore/Global/Dreamweaver.gitignore7
-rw-r--r--vendor/gitignore/Global/Dropbox.gitignore4
-rw-r--r--vendor/gitignore/Global/Eclipse.gitignore51
-rw-r--r--vendor/gitignore/Global/EiffelStudio.gitignore2
-rw-r--r--vendor/gitignore/Global/Emacs.gitignore42
-rw-r--r--vendor/gitignore/Global/Ensime.gitignore4
-rw-r--r--vendor/gitignore/Global/Espresso.gitignore1
-rw-r--r--vendor/gitignore/Global/FlexBuilder.gitignore3
-rw-r--r--vendor/gitignore/Global/GPG.gitignore2
-rw-r--r--vendor/gitignore/Global/IPythonNotebook.gitignore2
-rw-r--r--vendor/gitignore/Global/JDeveloper.gitignore13
-rw-r--r--vendor/gitignore/Global/JetBrains.gitignore44
-rw-r--r--vendor/gitignore/Global/KDevelop4.gitignore2
-rw-r--r--vendor/gitignore/Global/Kate.gitignore3
-rw-r--r--vendor/gitignore/Global/Lazarus.gitignore30
-rw-r--r--vendor/gitignore/Global/LibreOffice.gitignore2
-rw-r--r--vendor/gitignore/Global/Linux.gitignore10
-rw-r--r--vendor/gitignore/Global/LyX.gitignore4
-rw-r--r--vendor/gitignore/Global/Matlab.gitignore19
-rw-r--r--vendor/gitignore/Global/Mercurial.gitignore6
-rw-r--r--vendor/gitignore/Global/MicrosoftOffice.gitignore16
-rw-r--r--vendor/gitignore/Global/ModelSim.gitignore23
-rw-r--r--vendor/gitignore/Global/Momentics.gitignore8
-rw-r--r--vendor/gitignore/Global/MonoDevelop.gitignore8
-rw-r--r--vendor/gitignore/Global/NetBeans.gitignore7
-rw-r--r--vendor/gitignore/Global/Ninja.gitignore2
-rw-r--r--vendor/gitignore/Global/NotepadPP.gitignore2
-rw-r--r--vendor/gitignore/Global/OSX.gitignore24
-rw-r--r--vendor/gitignore/Global/Otto.gitignore1
-rw-r--r--vendor/gitignore/Global/Redcar.gitignore1
-rw-r--r--vendor/gitignore/Global/Redis.gitignore3
-rw-r--r--vendor/gitignore/Global/SBT.gitignore9
-rw-r--r--vendor/gitignore/Global/SVN.gitignore1
-rw-r--r--vendor/gitignore/Global/SlickEdit.gitignore11
-rw-r--r--vendor/gitignore/Global/SublimeText.gitignore14
-rw-r--r--vendor/gitignore/Global/SynopsysVCS.gitignore36
-rw-r--r--vendor/gitignore/Global/Tags.gitignore16
-rw-r--r--vendor/gitignore/Global/TextMate.gitignore3
-rw-r--r--vendor/gitignore/Global/TortoiseGit.gitignore2
-rw-r--r--vendor/gitignore/Global/Vagrant.gitignore1
-rw-r--r--vendor/gitignore/Global/Vim.gitignore10
-rw-r--r--vendor/gitignore/Global/VirtualEnv.gitignore12
-rw-r--r--vendor/gitignore/Global/VisualStudioCode.gitignore2
-rw-r--r--vendor/gitignore/Global/WebMethods.gitignore14
-rw-r--r--vendor/gitignore/Global/Windows.gitignore18
-rw-r--r--vendor/gitignore/Global/Xcode.gitignore23
-rw-r--r--vendor/gitignore/Global/XilinxISE.gitignore67
-rw-r--r--vendor/gitignore/Go.gitignore24
-rw-r--r--vendor/gitignore/Gradle.gitignore14
-rw-r--r--vendor/gitignore/Grails.gitignore33
-rw-r--r--vendor/gitignore/Haskell.gitignore18
-rw-r--r--vendor/gitignore/IGORPro.gitignore5
-rw-r--r--vendor/gitignore/Idris.gitignore2
-rw-r--r--vendor/gitignore/Java.gitignore12
-rw-r--r--vendor/gitignore/Jboss.gitignore19
-rw-r--r--vendor/gitignore/Jekyll.gitignore3
-rw-r--r--vendor/gitignore/Joomla.gitignore546
-rw-r--r--vendor/gitignore/KiCad.gitignore20
-rw-r--r--vendor/gitignore/Kohana.gitignore2
-rw-r--r--vendor/gitignore/LabVIEW.gitignore16
-rw-r--r--vendor/gitignore/Laravel.gitignore16
-rw-r--r--vendor/gitignore/Leiningen.gitignore12
-rw-r--r--vendor/gitignore/LemonStand.gitignore21
-rw-r--r--vendor/gitignore/Lilypond.gitignore6
-rw-r--r--vendor/gitignore/Lithium.gitignore2
-rw-r--r--vendor/gitignore/Lua.gitignore41
-rw-r--r--vendor/gitignore/Magento.gitignore104
-rw-r--r--vendor/gitignore/Maven.gitignore9
-rw-r--r--vendor/gitignore/Mercury.gitignore13
-rw-r--r--vendor/gitignore/MetaProgrammingSystem.gitignore16
-rw-r--r--vendor/gitignore/Nanoc.gitignore10
-rw-r--r--vendor/gitignore/Nim.gitignore1
-rw-r--r--vendor/gitignore/Node.gitignore37
-rw-r--r--vendor/gitignore/OCaml.gitignore20
-rw-r--r--vendor/gitignore/Objective-C.gitignore51
-rw-r--r--vendor/gitignore/Opa.gitignore13
-rw-r--r--vendor/gitignore/OpenCart.gitignore13
-rw-r--r--vendor/gitignore/OracleForms.gitignore8
-rw-r--r--vendor/gitignore/Packer.gitignore5
-rw-r--r--vendor/gitignore/Perl.gitignore20
-rw-r--r--vendor/gitignore/Phalcon.gitignore2
-rw-r--r--vendor/gitignore/PlayFramework.gitignore15
-rw-r--r--vendor/gitignore/Plone.gitignore18
-rw-r--r--vendor/gitignore/Prestashop.gitignore32
-rw-r--r--vendor/gitignore/Processing.gitignore7
-rw-r--r--vendor/gitignore/Python.gitignore89
-rw-r--r--vendor/gitignore/Qooxdoo.gitignore5
-rw-r--r--vendor/gitignore/Qt.gitignore38
-rw-r--r--vendor/gitignore/R.gitignore33
-rw-r--r--vendor/gitignore/README.md14
-rw-r--r--vendor/gitignore/ROS.gitignore47
-rw-r--r--vendor/gitignore/Rails.gitignore38
-rw-r--r--vendor/gitignore/RhodesRhomobile.gitignore9
-rw-r--r--vendor/gitignore/Ruby.gitignore50
-rw-r--r--vendor/gitignore/Rust.gitignore7
-rw-r--r--vendor/gitignore/SCons.gitignore2
-rw-r--r--vendor/gitignore/Sass.gitignore2
-rw-r--r--vendor/gitignore/Scala.gitignore17
-rw-r--r--vendor/gitignore/Scheme.gitignore7
-rw-r--r--vendor/gitignore/Scrivener.gitignore7
-rw-r--r--vendor/gitignore/Sdcc.gitignore8
-rw-r--r--vendor/gitignore/SeamGen.gitignore26
-rw-r--r--vendor/gitignore/SketchUp.gitignore1
-rw-r--r--vendor/gitignore/Smalltalk.gitignore18
-rw-r--r--vendor/gitignore/Stella.gitignore12
-rw-r--r--vendor/gitignore/SugarCRM.gitignore25
-rw-r--r--vendor/gitignore/Swift.gitignore63
-rw-r--r--vendor/gitignore/Symfony.gitignore48
-rw-r--r--vendor/gitignore/SymphonyCMS.gitignore6
-rw-r--r--vendor/gitignore/TeX.gitignore180
-rw-r--r--vendor/gitignore/Terraform.gitignore3
-rw-r--r--vendor/gitignore/Textpattern.gitignore11
-rw-r--r--vendor/gitignore/TurboGears2.gitignore20
-rw-r--r--vendor/gitignore/Typo3.gitignore20
-rw-r--r--vendor/gitignore/Umbraco.gitignore19
-rw-r--r--vendor/gitignore/Unity.gitignore30
-rw-r--r--vendor/gitignore/UnrealEngine.gitignore62
-rw-r--r--vendor/gitignore/VVVV.gitignore6
-rw-r--r--vendor/gitignore/VisualStudio.gitignore252
-rw-r--r--vendor/gitignore/Waf.gitignore4
-rw-r--r--vendor/gitignore/WordPress.gitignore18
-rw-r--r--vendor/gitignore/Xojo.gitignore11
-rw-r--r--vendor/gitignore/Yeoman.gitignore6
-rw-r--r--vendor/gitignore/Yii.gitignore6
-rw-r--r--vendor/gitignore/ZendFramework.gitignore25
-rw-r--r--vendor/gitignore/Zephir.gitignore26
458 files changed, 8922 insertions, 929 deletions
diff --git a/.rubocop.yml b/.rubocop.yml
index 562197300b4..0946ef5d848 100644
--- a/.rubocop.yml
+++ b/.rubocop.yml
@@ -21,6 +21,7 @@ AllCops:
- 'lib/email_validator.rb'
- 'lib/gitlab/upgrader.rb'
- 'lib/gitlab/seeder.rb'
+ - 'generator_templates/**/*'
##################### Style ##################################
diff --git a/CHANGELOG b/CHANGELOG
index bcf44b9a8d3..1c26692f3ab 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,15 +1,32 @@
Please view this file on the master branch, on stable branches it's out of date.
-v 8.8.0 (unreleased)
+v 8.8.2 (unreleased)
+ - Fix Error 500 when accessing application settings due to nil disabled OAuth sign-in sources
+
+v 8.8.1
+ - Add documentation for the "Health Check" feature
+ - Allow anonymous users to access a public project's pipelines
+ - Fix MySQL compatibility in zero downtime migrations helpers
+ - Fix the CI login to Container Registry (the gitlab-ci-token user)
+
+v 8.8.0
+ - Implement GFM references for milestones (Alejandro Rodríguez)
- Snippets tab under user profile. !4001 (Long Nguyen)
- Fix error when using link to uploads in global snippets
+ - Fix Error 500 when attempting to retrieve project license when HEAD points to non-existent ref
- Assign labels and milestone to target project when moving issue. !3934 (Long Nguyen)
- Use a case-insensitive comparison in sanitizing URI schemes
- Toggle sign-up confirmation emails in application settings
+ - Make it possible to prevent tagged runner from picking untagged jobs
+ - Added `InlineDiffFilter` to the markdown parser. (Adam Butler)
+ - Added inline diff styling for `change_title` system notes. (Adam Butler)
- Project#open_branches has been cleaned up and no longer loads entire records into memory.
- Escape HTML in commit titles in system note messages
+ - Fix scope used when accessing container registry
+ - Fix creation of Ci::Commit object which can lead to pending, failed in some scenarios
- Improve multiple branch push performance by memoizing permission checking
- Log to application.log when an admin starts and stops impersonating a user
+ - Changing the confidentiality of an issue now creates a new system note (Alex Moore-Niemi)
- Updated gitlab_git to 10.1.0
- GitAccess#protected_tag? no longer loads all tags just to check if a single one exists
- Reduce delay in destroying a project from 1-minute to immediately
@@ -21,6 +38,7 @@ v 8.8.0 (unreleased)
- Bump mail_room to 0.7.0 to fix stuck IDLE connections
- Remove future dates from contribution calendar graph.
- Support e-mail notifications for comments on project snippets
+ - Fix API leak of notes of unauthorized issues, snippets and merge requests
- Use ActionDispatch Remote IP for Akismet checking
- Fix error when visiting commit builds page before build was updated
- Add 'l' shortcut to open Label dropdown on issuables and 'i' to create new issue on a project
@@ -36,13 +54,15 @@ v 8.8.0 (unreleased)
- Added button to toggle whitespaces changes on diff view
- Backport GitHub Enterprise import support from EE
- Create tags using Rugged for performance reasons. !3745
+ - Allow guests to set notification level in projects
- API: Expose Issue#user_notes_count. !3126 (Anton Popov)
- Don't show forks button when user can't view forks
+ - Fix atom feed links and rendering
- Files over 5MB can only be viewed in their raw form, files over 1MB without highlighting !3718
- Add support for supressing text diffs using .gitattributes on the default branch (Matt Oakes)
- Add eager load paths to help prevent dependency load issues in Sidekiq workers. !3724
- Added multiple colors for labels in dropdowns when dups happen.
- - Always group commits by server timezone, not commit timestamp
+ - Show commits in the same order as `git log`
- Improve description for the Two-factor Authentication sign-in screen. (Connor Shea)
- API support for the 'since' and 'until' operators on commit requests (Paco Guzman)
- Fix Gravatar hint in user profile when Gravatar is disabled. !3988 (Artem Sidorenko)
@@ -58,10 +78,16 @@ v 8.8.0 (unreleased)
- Add counter metrics for rails cache
- Import pull requests from GitHub where the source or target branches were removed
- All Grape API helpers are now instrumented
+ - Improve Issue formatting for the Slack Service (Jeroen van Baarsen)
+ - Fixed advice on invalid permissions on upload path !2948 (Ludovic Perrine)
+ - Allows MR authors to have the source branch removed when merging the MR. !2801 (Jeroen Jacobs)
+ - When creating a .gitignore file a dropdown with templates will be provided
v 8.7.6
- Fix links on wiki pages for relative url setups. !4131 (Artem Sidorenko)
- Fix import by `Any Git URL` broken if the URL contains a space
+ - Fix import from GitLab.com to a private instance failure. !4181
+ - Fix external imports not finding the import data. !4106
v 8.7.5
- Fix relative links in wiki pages. !4050
@@ -83,6 +109,7 @@ v 8.7.3
- Merge request widget displays TeamCity build state and code coverage correctly again.
- Fix the line code when importing PR review comments from GitHub. !4010
- Wikis are now initialized on legacy projects when checking repositories
+ - Remove animate.css in favor of a smaller subset of animations. !3937 (Connor Shea)
v 8.7.2
- The "New Branch" button is now loaded asynchronously
@@ -891,7 +918,7 @@ v 8.1.3
- Use issue editor as cross reference comment author when issue is edited with a new mention
- Add Facebook authentication
-v 8.1.2
+v 8.1.1
- Fix cloning Wiki repositories via HTTP (Stan Hu)
- Add migration to remove satellites directory
- Fix specific runners visibility
@@ -1516,20 +1543,17 @@ v 7.10.0
- Fix stuck Merge Request merging events from old installations (Ben Bodenmiller)
- Fix merge request comments on files with multiple commits
- Fix Resource Owner Password Authentication Flow
-
-v 7.9.4
- - Security: Fix project import URL regex to prevent arbitary local repos from being imported
- - Fixed issue where only 25 commits would load in file listings
- - Fix LDAP identities after config update
-
-v 7.9.3
- - Contains no changes
- Add icons to Add dropdown items.
- Allow admin to create public deploy keys that are accessible to any project.
- Warn when gitlab-shell version doesn't match requirement.
- Skip email confirmation when set by admin or via LDAP.
- Only allow users to reference groups, projects, issues, MRs, commits they have access to.
+v 7.9.4
+ - Security: Fix project import URL regex to prevent arbitary local repos from being imported
+ - Fixed issue where only 25 commits would load in file listings
+ - Fix LDAP identities after config update
+
v 7.9.3
- Contains no changes
diff --git a/Gemfile b/Gemfile
index 91ad1706a07..832c5a3ca89 100644
--- a/Gemfile
+++ b/Gemfile
@@ -325,7 +325,7 @@ gem "mail_room", "~> 0.7"
gem 'email_reply_parser', '~> 0.5.8'
## CI
-gem 'activerecord-session_store', '~> 0.1.0'
+gem 'activerecord-session_store', '~> 1.0.0'
gem "nested_form", '~> 0.3.2'
# OAuth
diff --git a/Gemfile.lock b/Gemfile.lock
index b55764504c6..e1c5b9630d3 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -33,10 +33,12 @@ GEM
activemodel (= 4.2.6)
activesupport (= 4.2.6)
arel (~> 6.0)
- activerecord-session_store (0.1.2)
- actionpack (>= 4.0.0, < 5)
- activerecord (>= 4.0.0, < 5)
- railties (>= 4.0.0, < 5)
+ activerecord-session_store (1.0.0)
+ actionpack (>= 4.0, < 5.1)
+ activerecord (>= 4.0, < 5.1)
+ multi_json (~> 1.11, >= 1.11.2)
+ rack (>= 1.5.2, < 3)
+ railties (>= 4.0, < 5.1)
activesupport (4.2.6)
i18n (~> 0.7)
json (~> 1.7, >= 1.7.7)
@@ -883,7 +885,7 @@ PLATFORMS
DEPENDENCIES
RedCloth (~> 4.2.9)
ace-rails-ap (~> 4.0.2)
- activerecord-session_store (~> 0.1.0)
+ activerecord-session_store (~> 1.0.0)
acts-as-taggable-on (~> 3.4)
addressable (~> 2.3.8)
after_commit_queue
diff --git a/app/assets/images/ci/arch.jpg b/app/assets/images/ci/arch.jpg
deleted file mode 100644
index 0e05674e840..00000000000
--- a/app/assets/images/ci/arch.jpg
+++ /dev/null
Binary files differ
diff --git a/app/assets/images/ci/favicon.ico b/app/assets/images/ci/favicon.ico
deleted file mode 100644
index 9663d4d00b9..00000000000
--- a/app/assets/images/ci/favicon.ico
+++ /dev/null
Binary files differ
diff --git a/app/assets/images/ci/loader.gif b/app/assets/images/ci/loader.gif
deleted file mode 100644
index 2fcb8f2da0d..00000000000
--- a/app/assets/images/ci/loader.gif
+++ /dev/null
Binary files differ
diff --git a/app/assets/images/ci/no_avatar.png b/app/assets/images/ci/no_avatar.png
deleted file mode 100644
index 752d26adba7..00000000000
--- a/app/assets/images/ci/no_avatar.png
+++ /dev/null
Binary files differ
diff --git a/app/assets/images/ci/rails.png b/app/assets/images/ci/rails.png
deleted file mode 100644
index d5edc04e65f..00000000000
--- a/app/assets/images/ci/rails.png
+++ /dev/null
Binary files differ
diff --git a/app/assets/images/ci/service_sample.png b/app/assets/images/ci/service_sample.png
deleted file mode 100644
index 65d29e3fd89..00000000000
--- a/app/assets/images/ci/service_sample.png
+++ /dev/null
Binary files differ
diff --git a/app/assets/javascripts/api.js.coffee b/app/assets/javascripts/api.js.coffee
index dd1bbb37551..3f61ea1eaf4 100644
--- a/app/assets/javascripts/api.js.coffee
+++ b/app/assets/javascripts/api.js.coffee
@@ -1,14 +1,15 @@
@Api =
- groups_path: "/api/:version/groups.json"
- group_path: "/api/:version/groups/:id.json"
- namespaces_path: "/api/:version/namespaces.json"
- group_projects_path: "/api/:version/groups/:id/projects.json"
- projects_path: "/api/:version/projects.json"
- labels_path: "/api/:version/projects/:id/labels"
- license_path: "/api/:version/licenses/:key"
+ groupsPath: "/api/:version/groups.json"
+ groupPath: "/api/:version/groups/:id.json"
+ namespacesPath: "/api/:version/namespaces.json"
+ groupProjectsPath: "/api/:version/groups/:id/projects.json"
+ projectsPath: "/api/:version/projects.json"
+ labelsPath: "/api/:version/projects/:id/labels"
+ licensePath: "/api/:version/licenses/:key"
+ gitignorePath: "/api/:version/gitignores/:key"
group: (group_id, callback) ->
- url = Api.buildUrl(Api.group_path)
+ url = Api.buildUrl(Api.groupPath)
url = url.replace(':id', group_id)
$.ajax(
@@ -22,7 +23,7 @@
# Return groups list. Filtered by query
# Only active groups retrieved
groups: (query, skip_ldap, callback) ->
- url = Api.buildUrl(Api.groups_path)
+ url = Api.buildUrl(Api.groupsPath)
$.ajax(
url: url
@@ -36,7 +37,7 @@
# Return namespaces list. Filtered by query
namespaces: (query, callback) ->
- url = Api.buildUrl(Api.namespaces_path)
+ url = Api.buildUrl(Api.namespacesPath)
$.ajax(
url: url
@@ -50,7 +51,7 @@
# Return projects list. Filtered by query
projects: (query, order, callback) ->
- url = Api.buildUrl(Api.projects_path)
+ url = Api.buildUrl(Api.projectsPath)
$.ajax(
url: url
@@ -64,7 +65,7 @@
callback(projects)
newLabel: (project_id, data, callback) ->
- url = Api.buildUrl(Api.labels_path)
+ url = Api.buildUrl(Api.labelsPath)
url = url.replace(':id', project_id)
data.private_token = gon.api_token
@@ -80,7 +81,7 @@
# Return group projects list. Filtered by query
groupProjects: (group_id, query, callback) ->
- url = Api.buildUrl(Api.group_projects_path)
+ url = Api.buildUrl(Api.groupProjectsPath)
url = url.replace(':id', group_id)
$.ajax(
@@ -95,7 +96,7 @@
# Return text for a specific license
licenseText: (key, data, callback) ->
- url = Api.buildUrl(Api.license_path).replace(':key', key)
+ url = Api.buildUrl(Api.licensePath).replace(':key', key)
$.ajax(
url: url
@@ -103,6 +104,12 @@
).done (license) ->
callback(license)
+ gitignoreText: (key, callback) ->
+ url = Api.buildUrl(Api.gitignorePath).replace(':key', key)
+
+ $.get url, (gitignore) ->
+ callback(gitignore)
+
buildUrl: (url) ->
url = gon.relative_url_root + url if gon.relative_url_root?
return url.replace(':version', gon.api_version)
diff --git a/app/assets/javascripts/blob/blob_gitignore_selector.js.coffee b/app/assets/javascripts/blob/blob_gitignore_selector.js.coffee
new file mode 100644
index 00000000000..cc8a497d081
--- /dev/null
+++ b/app/assets/javascripts/blob/blob_gitignore_selector.js.coffee
@@ -0,0 +1,58 @@
+class @BlobGitignoreSelector
+ constructor: (opts) ->
+ {
+ @dropdown
+ @editor
+ @$wrapper = @dropdown.closest('.gitignore-selector')
+ @$filenameInput = $('#file_name')
+ @data = @dropdown.data('filenames')
+ } = opts
+
+ @dropdown.glDropdown(
+ data: @data,
+ filterable: true,
+ selectable: true,
+ search:
+ fields: ['name']
+ clicked: @onClick
+ text: (gitignore) ->
+ gitignore.name
+ )
+
+ @toggleGitignoreSelector()
+ @bindEvents()
+
+ bindEvents: ->
+ @$filenameInput
+ .on 'keyup blur', (e) =>
+ @toggleGitignoreSelector()
+
+ toggleGitignoreSelector: ->
+ filename = @$filenameInput.val() or $('.editor-file-name').text().trim()
+ @$wrapper.toggleClass 'hidden', filename isnt '.gitignore'
+
+ onClick: (item, el, e) =>
+ e.preventDefault()
+ @requestIgnoreFile(item.name)
+
+ requestIgnoreFile: (name) ->
+ Api.gitignoreText name, @requestIgnoreFileSuccess.bind(@)
+
+ requestIgnoreFileSuccess: (gitignore) ->
+ @editor.setValue(gitignore.content, 1)
+ @editor.focus()
+
+class @BlobGitignoreSelectors
+ constructor: (opts) ->
+ {
+ @$dropdowns = $('.js-gitignore-selector')
+ @editor
+ } = opts
+
+ @$dropdowns.each (i, dropdown) =>
+ $dropdown = $(dropdown)
+
+ new BlobGitignoreSelector(
+ dropdown: $dropdown,
+ editor: @editor
+ )
diff --git a/app/assets/javascripts/blob/edit_blob.js.coffee b/app/assets/javascripts/blob/edit_blob.js.coffee
index eea9aa972ee..79141e768b8 100644
--- a/app/assets/javascripts/blob/edit_blob.js.coffee
+++ b/app/assets/javascripts/blob/edit_blob.js.coffee
@@ -13,6 +13,7 @@ class @EditBlob
@initModePanesAndLinks()
new BlobLicenseSelector(@editor)
+ new BlobGitignoreSelectors(editor: @editor)
initModePanesAndLinks: ->
@$editModePanes = $(".js-edit-mode-pane")
diff --git a/app/assets/javascripts/gfm_auto_complete.js.coffee b/app/assets/javascripts/gfm_auto_complete.js.coffee
index 61e3f811e73..41dba342107 100644
--- a/app/assets/javascripts/gfm_auto_complete.js.coffee
+++ b/app/assets/javascripts/gfm_auto_complete.js.coffee
@@ -18,6 +18,10 @@ GitLab.GfmAutoComplete =
Issues:
template: '<li><small>${id}</small> ${title}</li>'
+ # Milestones
+ Milestones:
+ template: '<li>${title}</li>'
+
# Add GFM auto-completion to all input fields, that accept GFM input.
setup: (wrap) ->
@input = $('.js-gfm-input')
@@ -82,6 +86,19 @@ GitLab.GfmAutoComplete =
search: "#{i.iid} #{i.title}"
@input.atwho
+ at: '%'
+ alias: 'milestones'
+ searchKey: 'search'
+ displayTpl: @Milestones.template
+ insertTpl: '${atwho-at}"${title}"'
+ callbacks:
+ beforeSave: (milestones) ->
+ $.map milestones, (m) ->
+ id: m.iid
+ title: sanitize(m.title)
+ search: "#{m.title}"
+
+ @input.atwho
at: '!'
alias: 'mergerequests'
searchKey: 'search'
@@ -105,6 +122,8 @@ GitLab.GfmAutoComplete =
@input.atwho 'load', '@', data.members
# load issues
@input.atwho 'load', 'issues', data.issues
+ # load milestones
+ @input.atwho 'load', 'milestones', data.milestones
# load merge requests
@input.atwho 'load', 'mergerequests', data.mergerequests
# load emojis
diff --git a/app/assets/javascripts/gl_dropdown.js.coffee b/app/assets/javascripts/gl_dropdown.js.coffee
index 1d1bfeb2e77..b3f1dc969b8 100644
--- a/app/assets/javascripts/gl_dropdown.js.coffee
+++ b/app/assets/javascripts/gl_dropdown.js.coffee
@@ -60,9 +60,36 @@ class GitLabDropdownFilter
results = data
if search_text isnt ''
- results = fuzzaldrinPlus.filter(data, search_text,
- key: @options.keys
- )
+ # When data is an array of objects therefore [object Array] e.g.
+ # [
+ # { prop: 'foo' },
+ # { prop: 'baz' }
+ # ]
+ if _.isArray(data)
+ results = fuzzaldrinPlus.filter(data, search_text,
+ key: @options.keys
+ )
+ else
+ # If data is grouped therefore an [object Object]. e.g.
+ # {
+ # groupName1: [
+ # { prop: 'foo' },
+ # { prop: 'baz' }
+ # ],
+ # groupName2: [
+ # { prop: 'abc' },
+ # { prop: 'def' }
+ # ]
+ # }
+ if gl.utils.isObject data
+ results = {}
+ for key, group of data
+ tmp = fuzzaldrinPlus.filter(group, search_text,
+ key: @options.keys
+ )
+
+ if tmp.length
+ results[key] = tmp.map (item) -> item
@options.callback results
else
@@ -141,8 +168,9 @@ class GitLabDropdown
searchFields = if @options.search then @options.search.fields else [];
if @options.data
- # If data is an array
- if _.isArray @options.data
+ # If we provided data
+ # data could be an array of objects or a group of arrays
+ if _.isObject(@options.data) and not _.isFunction(@options.data)
@fullData = @options.data
@parseData @options.data
else
@@ -230,19 +258,33 @@ class GitLabDropdown
parseData: (data) ->
@renderedData = data
- # Render each row
- html = $.map data, (obj) =>
- return @renderItem(obj)
-
if @options.filterable and data.length is 0
# render no matching results
html = [@noResults()]
+ else
+ # Handle array groups
+ if gl.utils.isObject data
+ html = []
+ for name, groupData of data
+ # Add header for each group
+ html.push(@renderItem(header: name, name))
+
+ @renderData(groupData, name)
+ .map (item) ->
+ html.push item
+ else
+ # Render each row
+ html = @renderData(data)
# Render the full menu
full_html = @renderMenu(html.join(""))
@appendMenu(full_html)
+ renderData: (data, group = false) ->
+ data.map (obj, index) =>
+ return @renderItem(obj, group, index)
+
shouldPropagate: (e) =>
if @options.multiSelect
$target = $(e.target)
@@ -299,11 +341,10 @@ class GitLabDropdown
selector = '.dropdown-content'
if @dropdown.find(".dropdown-toggle-page").length
selector = ".dropdown-page-one .dropdown-content"
-
$(selector, @dropdown).html html
# Render the row
- renderItem: (data) ->
+ renderItem: (data, group = false, index = false) ->
html = ""
# Divider
@@ -346,8 +387,13 @@ class GitLabDropdown
if @highlight
text = @highlightTextMatches(text, @filterInput.val())
+ if group
+ groupAttrs = "data-group='#{group}' data-index='#{index}'"
+ else
+ groupAttrs = ''
+
html = "<li>
- <a href='#{url}' class='#{cssClass}'>
+ <a href='#{url}' #{groupAttrs} class='#{cssClass}'>
#{text}
</a>
</li>"
@@ -377,9 +423,15 @@ class GitLabDropdown
rowClicked: (el) ->
fieldName = @options.fieldName
- selectedIndex = el.parent().index()
if @renderedData
- selectedObject = @renderedData[selectedIndex]
+ groupName = el.data('group')
+ if groupName
+ selectedIndex = el.data('index')
+ selectedObject = @renderedData[groupName][selectedIndex]
+ else
+ selectedIndex = el.closest('li').index()
+ selectedObject = @renderedData[selectedIndex]
+
value = if @options.id then @options.id(selectedObject, el) else selectedObject.id
field = @dropdown.parent().find("input[name='#{fieldName}'][value='#{value}']")
if el.hasClass(ACTIVE_CLASS)
@@ -460,7 +512,7 @@ class GitLabDropdown
return false
if currentKeyCode is 13
- @selectRowAtIndex currentIndex
+ @selectRowAtIndex if currentIndex < 0 then 0 else currentIndex
removeArrayKeyEvent: ->
$('body').off 'keydown'
diff --git a/app/assets/javascripts/issuable_form.js.coffee b/app/assets/javascripts/issuable_form.js.coffee
index 7a788f761b7..72ae3bde81e 100644
--- a/app/assets/javascripts/issuable_form.js.coffee
+++ b/app/assets/javascripts/issuable_form.js.coffee
@@ -20,6 +20,15 @@ class @IssuableForm
@initWip()
+ $issuableDueDate = $('#issuable-due-date')
+
+ if $issuableDueDate.length
+ $('.datepicker').datepicker(
+ dateFormat: 'yy-mm-dd',
+ onSelect: (dateText, inst) ->
+ $issuableDueDate.val dateText
+ ).datepicker 'setDate', $.datepicker.parseDate('yy-mm-dd', $issuableDueDate.val())
+
initAutosave: ->
new Autosave @titleField, [
document.location.pathname,
diff --git a/app/assets/javascripts/lib/type_utility.js.coffee b/app/assets/javascripts/lib/type_utility.js.coffee
new file mode 100644
index 00000000000..957f0d86b36
--- /dev/null
+++ b/app/assets/javascripts/lib/type_utility.js.coffee
@@ -0,0 +1,9 @@
+((w) ->
+
+ w.gl ?= {}
+ w.gl.utils ?= {}
+
+ w.gl.utils.isObject = (obj) ->
+ obj? and (obj.constructor is Object)
+
+) window
diff --git a/app/assets/javascripts/merge_request_widget.js.coffee b/app/assets/javascripts/merge_request_widget.js.coffee
index f58647988a2..b6d590f681c 100644
--- a/app/assets/javascripts/merge_request_widget.js.coffee
+++ b/app/assets/javascripts/merge_request_widget.js.coffee
@@ -113,7 +113,7 @@ class @MergeRequestWidget
switch state
when "failed", "canceled", "not_found"
@setMergeButtonClass('btn-danger')
- when "running", "pending"
+ when "running"
@setMergeButtonClass('btn-warning')
when "success"
@setMergeButtonClass('btn-create')
@@ -126,6 +126,6 @@ class @MergeRequestWidget
$('.ci_widget:visible .ci-coverage').text(text)
setMergeButtonClass: (css_class) ->
- $('.accept_merge_request')
+ $('.js-merge-button')
.removeClass('btn-danger btn-warning btn-create')
.addClass(css_class)
diff --git a/app/assets/stylesheets/application.scss b/app/assets/stylesheets/application.scss
index 69b3b6586de..e2d590f4df4 100644
--- a/app/assets/stylesheets/application.scss
+++ b/app/assets/stylesheets/application.scss
@@ -10,7 +10,6 @@
*= require dropzone/basic
*= require cal-heatmap
*= require cropper.css
- *= require animate
*/
/*
diff --git a/app/assets/stylesheets/framework.scss b/app/assets/stylesheets/framework.scss
index 560de9fc0bd..3cbddc59f11 100644
--- a/app/assets/stylesheets/framework.scss
+++ b/app/assets/stylesheets/framework.scss
@@ -5,6 +5,7 @@
@import 'framework/tw_bootstrap';
@import "framework/layout";
+@import "framework/animations.scss";
@import "framework/avatar.scss";
@import "framework/blocks.scss";
@import "framework/buttons.scss";
diff --git a/app/assets/stylesheets/framework/animations.scss b/app/assets/stylesheets/framework/animations.scss
new file mode 100644
index 00000000000..1fec61bdba1
--- /dev/null
+++ b/app/assets/stylesheets/framework/animations.scss
@@ -0,0 +1,72 @@
+// This file is based off animate.css 3.5.1, available here:
+// https://github.com/daneden/animate.css/blob/3.5.1/animate.css
+//
+// animate.css - http://daneden.me/animate
+// Version - 3.5.1
+// Licensed under the MIT license - http://opensource.org/licenses/MIT
+//
+// Copyright (c) 2016 Daniel Eden
+
+.animated {
+ -webkit-animation-duration: 1s;
+ animation-duration: 1s;
+ -webkit-animation-fill-mode: both;
+ animation-fill-mode: both;
+}
+
+.animated.infinite {
+ -webkit-animation-iteration-count: infinite;
+ animation-iteration-count: infinite;
+}
+
+.animated.hinge {
+ -webkit-animation-duration: 2s;
+ animation-duration: 2s;
+}
+
+.animated.flipOutX,
+.animated.flipOutY,
+.animated.bounceIn,
+.animated.bounceOut {
+ -webkit-animation-duration: .75s;
+ animation-duration: .75s;
+}
+
+@-webkit-keyframes pulse {
+ from {
+ -webkit-transform: scale3d(1, 1, 1);
+ transform: scale3d(1, 1, 1);
+ }
+
+ 50% {
+ -webkit-transform: scale3d(1.05, 1.05, 1.05);
+ transform: scale3d(1.05, 1.05, 1.05);
+ }
+
+ to {
+ -webkit-transform: scale3d(1, 1, 1);
+ transform: scale3d(1, 1, 1);
+ }
+}
+
+@keyframes pulse {
+ from {
+ -webkit-transform: scale3d(1, 1, 1);
+ transform: scale3d(1, 1, 1);
+ }
+
+ 50% {
+ -webkit-transform: scale3d(1.05, 1.05, 1.05);
+ transform: scale3d(1.05, 1.05, 1.05);
+ }
+
+ to {
+ -webkit-transform: scale3d(1, 1, 1);
+ transform: scale3d(1, 1, 1);
+ }
+}
+
+.pulse {
+ -webkit-animation-name: pulse;
+ animation-name: pulse;
+}
diff --git a/app/assets/stylesheets/framework/files.scss b/app/assets/stylesheets/framework/files.scss
index 61d9954c6c8..8c96c7a9c31 100644
--- a/app/assets/stylesheets/framework/files.scss
+++ b/app/assets/stylesheets/framework/files.scss
@@ -36,22 +36,6 @@
}
}
- .filename {
- &.old {
- display: inline-block;
- span.idiff {
- background-color: #f8cbcb;
- }
- }
-
- &.new {
- display: inline-block;
- span.idiff {
- background-color: #a6f3a6;
- }
- }
- }
-
a:not(.btn) {
color: $gl-dark-link-color;
}
diff --git a/app/assets/stylesheets/framework/forms.scss b/app/assets/stylesheets/framework/forms.scss
index 558b133f593..46acc3b772f 100644
--- a/app/assets/stylesheets/framework/forms.scss
+++ b/app/assets/stylesheets/framework/forms.scss
@@ -28,10 +28,6 @@ input[type='text'].danger {
}
label {
- &.control-label {
- @extend .col-sm-2;
- }
-
&.inline-label {
margin: 0;
}
@@ -41,6 +37,10 @@ label {
}
}
+.control-label {
+ @extend .col-sm-2;
+}
+
.inline-input-group {
width: 250px;
}
diff --git a/app/assets/stylesheets/framework/typography.scss b/app/assets/stylesheets/framework/typography.scss
index 2779cd56788..3575984b229 100644
--- a/app/assets/stylesheets/framework/typography.scss
+++ b/app/assets/stylesheets/framework/typography.scss
@@ -269,3 +269,11 @@ h1, h2, h3, h4 {
text-align: right;
}
}
+
+.idiff.deletion {
+ background: $line-removed-dark;
+}
+
+.idiff.addition {
+ background: $line-added-dark;
+}
diff --git a/app/assets/stylesheets/framework/variables.scss b/app/assets/stylesheets/framework/variables.scss
index 5fa4c266607..c5a4dbe372c 100644
--- a/app/assets/stylesheets/framework/variables.scss
+++ b/app/assets/stylesheets/framework/variables.scss
@@ -12,7 +12,7 @@ $gutter_inner_width: 258px;
*/
$border-color: #e5e5e5;
$focus-border-color: #3aabf0;
-$table-border-color: #ececec;
+$table-border-color: #f0f0f0;
$background-color: #fafafa;
/*
@@ -178,6 +178,7 @@ $table-border-gray: #f0f0f0;
$line-target-blue: #eaf3fc;
$line-select-yellow: #fcf8e7;
$line-select-yellow-dark: #f0e2bd;
+
/*
* Fonts
*/
diff --git a/app/assets/stylesheets/framework/zen.scss b/app/assets/stylesheets/framework/zen.scss
index f870ea0d87f..ff02ebdd34c 100644
--- a/app/assets/stylesheets/framework/zen.scss
+++ b/app/assets/stylesheets/framework/zen.scss
@@ -32,7 +32,7 @@
}
}
-.zen-cotrol {
+.zen-control {
padding: 0;
color: #555;
background: none;
diff --git a/app/assets/stylesheets/mailers/repository_push_email.scss b/app/assets/stylesheets/mailers/repository_push_email.scss
new file mode 100644
index 00000000000..001994db97b
--- /dev/null
+++ b/app/assets/stylesheets/mailers/repository_push_email.scss
@@ -0,0 +1,43 @@
+@import "framework/variables";
+
+table.code {
+ width: 100%;
+ font-family: monospace;
+ border: none;
+ border-collapse: separate;
+ margin: 0;
+ padding: 0;
+ -premailer-cellpadding: 0;
+ -premailer-cellspacing: 0;
+ -premailer-width: 100%;
+
+ td {
+ line-height: $code_line_height;
+ font-family: monospace;
+ font-size: $code_font_size;
+ }
+
+ td.diff-line-num {
+ margin: 0;
+ padding: 0;
+ border: none;
+ background: $background-color;
+ color: rgba(0, 0, 0, 0.3);
+ padding: 0 5px;
+ border-right: 1px solid $border-color;
+ text-align: right;
+ min-width: 35px;
+ max-width: 50px;
+ width: 35px;
+ }
+
+ td.line_content {
+ display: block;
+ margin: 0;
+ padding: 0 0.5em;
+ border: none;
+ white-space: pre;
+ }
+}
+
+@import "highlight/white";
diff --git a/app/assets/stylesheets/pages/editor.scss b/app/assets/stylesheets/pages/editor.scss
index 8981f070a20..22679c764dc 100644
--- a/app/assets/stylesheets/pages/editor.scss
+++ b/app/assets/stylesheets/pages/editor.scss
@@ -23,7 +23,7 @@
.file-title {
@extend .monospace;
- line-height: 42px;
+ line-height: 35px;
padding-top: 7px;
padding-bottom: 7px;
@@ -43,7 +43,7 @@
.editor-file-name {
@extend .monospace;
-
+
float: left;
margin-right: 10px;
}
@@ -59,7 +59,22 @@
}
.encoding-selector,
- .license-selector {
+ .license-selector,
+ .gitignore-selector {
display: inline-block;
+ vertical-align: top;
+ font-family: $regular_font;
+ }
+
+ .gitignore-selector {
+
+ .dropdown {
+ line-height: 21px;
+ }
+
+ .dropdown-menu-toggle {
+ vertical-align: top;
+ width: 220px;
+ }
}
}
diff --git a/app/assets/stylesheets/pages/pipelines.scss b/app/assets/stylesheets/pages/pipelines.scss
new file mode 100644
index 00000000000..546176b65e4
--- /dev/null
+++ b/app/assets/stylesheets/pages/pipelines.scss
@@ -0,0 +1,4 @@
+.pipeline-stage {
+ overflow: hidden;
+ text-overflow: ellipsis;
+}
diff --git a/app/assets/stylesheets/pages/projects.scss b/app/assets/stylesheets/pages/projects.scss
index c20f04653fc..b4702b31182 100644
--- a/app/assets/stylesheets/pages/projects.scss
+++ b/app/assets/stylesheets/pages/projects.scss
@@ -7,7 +7,7 @@
}
.no-ssh-key-message, .project-limit-message {
background-color: #f28d35;
- margin-bottom: 16px;
+ margin-bottom: 0;
}
.new_project,
.edit_project {
@@ -149,6 +149,10 @@
white-space: nowrap;
margin: 0 11px 0 4px;
+ a {
+ color: inherit;
+ }
+
&:hover {
background: #fff;
}
@@ -161,7 +165,7 @@
display: inline-table;
margin-right: 12px;
- a {
+ > a {
margin: -1px;
}
}
diff --git a/app/controllers/admin/abuse_reports_controller.rb b/app/controllers/admin/abuse_reports_controller.rb
index e9b0972bdd8..5055c318a5f 100644
--- a/app/controllers/admin/abuse_reports_controller.rb
+++ b/app/controllers/admin/abuse_reports_controller.rb
@@ -9,6 +9,6 @@ class Admin::AbuseReportsController < Admin::ApplicationController
abuse_report.remove_user(deleted_by: current_user) if params[:remove_user]
abuse_report.destroy
- render nothing: true
+ head :ok
end
end
diff --git a/app/controllers/admin/broadcast_messages_controller.rb b/app/controllers/admin/broadcast_messages_controller.rb
index fc342924987..82055006ac0 100644
--- a/app/controllers/admin/broadcast_messages_controller.rb
+++ b/app/controllers/admin/broadcast_messages_controller.rb
@@ -32,7 +32,7 @@ class Admin::BroadcastMessagesController < Admin::ApplicationController
respond_to do |format|
format.html { redirect_back_or_default(default: { action: 'index' }) }
- format.js { render nothing: true }
+ format.js { head :ok }
end
end
diff --git a/app/controllers/admin/keys_controller.rb b/app/controllers/admin/keys_controller.rb
index cb33fdd9763..054bb52b696 100644
--- a/app/controllers/admin/keys_controller.rb
+++ b/app/controllers/admin/keys_controller.rb
@@ -6,7 +6,7 @@ class Admin::KeysController < Admin::ApplicationController
respond_to do |format|
format.html
- format.js { render nothing: true }
+ format.js { head :ok }
end
end
diff --git a/app/controllers/admin/runners_controller.rb b/app/controllers/admin/runners_controller.rb
index 8b8a7320072..7345c91f67d 100644
--- a/app/controllers/admin/runners_controller.rb
+++ b/app/controllers/admin/runners_controller.rb
@@ -9,23 +9,18 @@ class Admin::RunnersController < Admin::ApplicationController
end
def show
- @builds = @runner.builds.order('id DESC').first(30)
- @projects =
- if params[:search].present?
- ::Project.search(params[:search])
- else
- Project.all
- end
- @projects = @projects.where.not(id: @runner.projects.select(:id)) if @runner.projects.any?
- @projects = @projects.page(params[:page]).per(30)
+ assign_builds_and_projects
end
def update
- @runner.update_attributes(runner_params)
-
- respond_to do |format|
- format.js
- format.html { redirect_to admin_runner_path(@runner) }
+ if @runner.update_attributes(runner_params)
+ respond_to do |format|
+ format.js
+ format.html { redirect_to admin_runner_path(@runner) }
+ end
+ else
+ assign_builds_and_projects
+ render 'show'
end
end
@@ -60,4 +55,16 @@ class Admin::RunnersController < Admin::ApplicationController
def runner_params
params.require(:runner).permit(Ci::Runner::FORM_EDITABLE)
end
+
+ def assign_builds_and_projects
+ @builds = runner.builds.order('id DESC').first(30)
+ @projects =
+ if params[:search].present?
+ ::Project.search(params[:search])
+ else
+ Project.all
+ end
+ @projects = @projects.where.not(id: runner.projects.select(:id)) if runner.projects.any?
+ @projects = @projects.page(params[:page]).per(30)
+ end
end
diff --git a/app/controllers/admin/spam_logs_controller.rb b/app/controllers/admin/spam_logs_controller.rb
index 377e9741e5f..3a2f0185315 100644
--- a/app/controllers/admin/spam_logs_controller.rb
+++ b/app/controllers/admin/spam_logs_controller.rb
@@ -11,7 +11,7 @@ class Admin::SpamLogsController < Admin::ApplicationController
redirect_to admin_spam_logs_path, notice: "User #{spam_log.user.username} was successfully removed."
else
spam_log.destroy
- render nothing: true
+ head :ok
end
end
end
diff --git a/app/controllers/admin/users_controller.rb b/app/controllers/admin/users_controller.rb
index 6908a3bf946..f35f4a8c811 100644
--- a/app/controllers/admin/users_controller.rb
+++ b/app/controllers/admin/users_controller.rb
@@ -154,7 +154,7 @@ class Admin::UsersController < Admin::ApplicationController
respond_to do |format|
format.html { redirect_back_or_admin_user(notice: "Successfully removed email.") }
- format.js { render nothing: true }
+ format.js { head :ok }
end
end
diff --git a/app/controllers/concerns/toggle_subscription_action.rb b/app/controllers/concerns/toggle_subscription_action.rb
index 8a43c0b93c4..9e3b9be2ff4 100644
--- a/app/controllers/concerns/toggle_subscription_action.rb
+++ b/app/controllers/concerns/toggle_subscription_action.rb
@@ -6,7 +6,7 @@ module ToggleSubscriptionAction
subscribable_resource.toggle_subscription(current_user)
- render nothing: true
+ head :ok
end
private
diff --git a/app/controllers/dashboard/todos_controller.rb b/app/controllers/dashboard/todos_controller.rb
index 5abf97342c3..f9a1929c117 100644
--- a/app/controllers/dashboard/todos_controller.rb
+++ b/app/controllers/dashboard/todos_controller.rb
@@ -12,7 +12,7 @@ class Dashboard::TodosController < Dashboard::ApplicationController
respond_to do |format|
format.html { redirect_to dashboard_todos_path, notice: todo_notice }
- format.js { render nothing: true }
+ format.js { head :ok }
format.json do
render json: { count: @todos.size, done_count: current_user.todos.done.count }
end
@@ -24,7 +24,7 @@ class Dashboard::TodosController < Dashboard::ApplicationController
respond_to do |format|
format.html { redirect_to dashboard_todos_path, notice: 'All todos were marked as done.' }
- format.js { render nothing: true }
+ format.js { head :ok }
format.json do
find_todos
render json: { count: @todos.size, done_count: current_user.todos.done.count }
diff --git a/app/controllers/groups/group_members_controller.rb b/app/controllers/groups/group_members_controller.rb
index d5ef33888c6..48dbf656e84 100644
--- a/app/controllers/groups/group_members_controller.rb
+++ b/app/controllers/groups/group_members_controller.rb
@@ -40,7 +40,7 @@ class Groups::GroupMembersController < Groups::ApplicationController
respond_to do |format|
format.html { redirect_to group_group_members_path(@group), notice: 'User was successfully removed from group.' }
- format.js { render nothing: true }
+ format.js { head :ok }
end
end
diff --git a/app/controllers/jwt_controller.rb b/app/controllers/jwt_controller.rb
index f5aa5397ff1..156ab2811d6 100644
--- a/app/controllers/jwt_controller.rb
+++ b/app/controllers/jwt_controller.rb
@@ -36,7 +36,7 @@ class JwtController < ApplicationController
end
def authenticate_project(login, password)
- if login == 'gitlab_ci_token'
+ if login == 'gitlab-ci-token'
Project.find_by(builds_enabled: true, runners_token: password)
end
end
diff --git a/app/controllers/profiles/emails_controller.rb b/app/controllers/profiles/emails_controller.rb
index 0ede9b8e21b..1c24c4db993 100644
--- a/app/controllers/profiles/emails_controller.rb
+++ b/app/controllers/profiles/emails_controller.rb
@@ -24,7 +24,7 @@ class Profiles::EmailsController < Profiles::ApplicationController
respond_to do |format|
format.html { redirect_to profile_emails_url }
- format.js { render nothing: true }
+ format.js { head :ok }
end
end
diff --git a/app/controllers/profiles/keys_controller.rb b/app/controllers/profiles/keys_controller.rb
index a12549d6bcb..830e0b9591b 100644
--- a/app/controllers/profiles/keys_controller.rb
+++ b/app/controllers/profiles/keys_controller.rb
@@ -32,7 +32,7 @@ class Profiles::KeysController < Profiles::ApplicationController
respond_to do |format|
format.html { redirect_to profile_keys_url }
- format.js { render nothing: true }
+ format.js { head :ok }
end
end
diff --git a/app/controllers/projects/container_registry_controller.rb b/app/controllers/projects/container_registry_controller.rb
new file mode 100644
index 00000000000..d1f46497207
--- /dev/null
+++ b/app/controllers/projects/container_registry_controller.rb
@@ -0,0 +1,34 @@
+class Projects::ContainerRegistryController < Projects::ApplicationController
+ before_action :verify_registry_enabled
+ before_action :authorize_read_container_image!
+ before_action :authorize_update_container_image!, only: [:destroy]
+ layout 'project'
+
+ def index
+ @tags = container_registry_repository.tags
+ end
+
+ def destroy
+ url = namespace_project_container_registry_index_path(project.namespace, project)
+
+ if tag.delete
+ redirect_to url
+ else
+ redirect_to url, alert: 'Failed to remove tag'
+ end
+ end
+
+ private
+
+ def verify_registry_enabled
+ render_404 unless Gitlab.config.registry.enabled
+ end
+
+ def container_registry_repository
+ @container_registry_repository ||= project.container_registry_repository
+ end
+
+ def tag
+ @tag ||= container_registry_repository.tag(params[:id])
+ end
+end
diff --git a/app/controllers/projects/imports_controller.rb b/app/controllers/projects/imports_controller.rb
index 7756f0f0ed3..a1b84afcd91 100644
--- a/app/controllers/projects/imports_controller.rb
+++ b/app/controllers/projects/imports_controller.rb
@@ -20,6 +20,7 @@ class Projects::ImportsController < Projects::ApplicationController
@project.import_retry
else
@project.import_start
+ @project.add_import_job
end
end
diff --git a/app/controllers/projects/merge_requests_controller.rb b/app/controllers/projects/merge_requests_controller.rb
index c5757a24624..f137c12d215 100644
--- a/app/controllers/projects/merge_requests_controller.rb
+++ b/app/controllers/projects/merge_requests_controller.rb
@@ -334,7 +334,8 @@ class Projects::MergeRequestsController < Projects::ApplicationController
params.require(:merge_request).permit(
:title, :assignee_id, :source_project_id, :source_branch,
:target_project_id, :target_branch, :milestone_id,
- :state_event, :description, :task_num, label_ids: []
+ :state_event, :description, :task_num, :force_remove_source_branch,
+ label_ids: []
)
end
diff --git a/app/controllers/projects/milestones_controller.rb b/app/controllers/projects/milestones_controller.rb
index f7b6d137bde..da2892bfb3f 100644
--- a/app/controllers/projects/milestones_controller.rb
+++ b/app/controllers/projects/milestones_controller.rb
@@ -75,7 +75,7 @@ class Projects::MilestonesController < Projects::ApplicationController
respond_to do |format|
format.html { redirect_to namespace_project_milestones_path }
- format.js { render nothing: true }
+ format.js { head :ok }
end
end
diff --git a/app/controllers/projects/notes_controller.rb b/app/controllers/projects/notes_controller.rb
index 4a57cd29a20..40b24d550e0 100644
--- a/app/controllers/projects/notes_controller.rb
+++ b/app/controllers/projects/notes_controller.rb
@@ -43,7 +43,7 @@ class Projects::NotesController < Projects::ApplicationController
end
respond_to do |format|
- format.js { render nothing: true }
+ format.js { head :ok }
end
end
@@ -52,7 +52,7 @@ class Projects::NotesController < Projects::ApplicationController
note.update_attribute(:attachment, nil)
respond_to do |format|
- format.js { render nothing: true }
+ format.js { head :ok }
end
end
diff --git a/app/controllers/projects/pipelines_controller.rb b/app/controllers/projects/pipelines_controller.rb
new file mode 100644
index 00000000000..b36081205d8
--- /dev/null
+++ b/app/controllers/projects/pipelines_controller.rb
@@ -0,0 +1,59 @@
+class Projects::PipelinesController < Projects::ApplicationController
+ before_action :pipeline, except: [:index, :new, :create]
+ before_action :commit, only: [:show]
+ before_action :authorize_read_pipeline!
+ before_action :authorize_create_pipeline!, only: [:new, :create]
+ before_action :authorize_update_pipeline!, only: [:retry, :cancel]
+
+ def index
+ @scope = params[:scope]
+ all_pipelines = project.ci_commits
+ @pipelines_count = all_pipelines.count
+ @running_or_pending_count = all_pipelines.running_or_pending.count
+ @pipelines = PipelinesFinder.new(project).execute(all_pipelines, @scope)
+ @pipelines = @pipelines.order(id: :desc).page(params[:page]).per(30)
+ end
+
+ def new
+ @pipeline = project.ci_commits.new(ref: @project.default_branch)
+ end
+
+ def create
+ @pipeline = Ci::CreatePipelineService.new(project, current_user, create_params).execute
+ unless @pipeline.persisted?
+ render 'new'
+ return
+ end
+
+ redirect_to namespace_project_pipeline_path(project.namespace, project, @pipeline)
+ end
+
+ def show
+ end
+
+ def retry
+ pipeline.retry_failed
+
+ redirect_back_or_default default: namespace_project_pipelines_path(project.namespace, project)
+ end
+
+ def cancel
+ pipeline.cancel_running
+
+ redirect_back_or_default default: namespace_project_pipelines_path(project.namespace, project)
+ end
+
+ private
+
+ def create_params
+ params.require(:pipeline).permit(:ref)
+ end
+
+ def pipeline
+ @pipeline ||= project.ci_commits.find_by!(id: params[:id])
+ end
+
+ def commit
+ @commit ||= @pipeline.commit_data
+ end
+end
diff --git a/app/controllers/projects/project_members_controller.rb b/app/controllers/projects/project_members_controller.rb
index 33b2625c0ac..cdea5f0b776 100644
--- a/app/controllers/projects/project_members_controller.rb
+++ b/app/controllers/projects/project_members_controller.rb
@@ -55,7 +55,7 @@ class Projects::ProjectMembersController < Projects::ApplicationController
format.html do
redirect_to namespace_project_project_members_path(@project.namespace, @project)
end
- format.js { render nothing: true }
+ format.js { head :ok }
end
end
@@ -81,7 +81,7 @@ class Projects::ProjectMembersController < Projects::ApplicationController
respond_to do |format|
format.html { redirect_to dashboard_projects_path, notice: "You left the project." }
- format.js { render nothing: true }
+ format.js { head :ok }
end
else
if current_user == @project.owner
diff --git a/app/controllers/projects/protected_branches_controller.rb b/app/controllers/projects/protected_branches_controller.rb
index e49259c34b6..efa7bf14d0f 100644
--- a/app/controllers/projects/protected_branches_controller.rb
+++ b/app/controllers/projects/protected_branches_controller.rb
@@ -39,7 +39,7 @@ class Projects::ProtectedBranchesController < Projects::ApplicationController
respond_to do |format|
format.html { redirect_to namespace_project_protected_branches_path }
- format.js { render nothing: true }
+ format.js { head :ok }
end
end
diff --git a/app/controllers/projects/runners_controller.rb b/app/controllers/projects/runners_controller.rb
index 3a9d67aff64..0b4fa572501 100644
--- a/app/controllers/projects/runners_controller.rb
+++ b/app/controllers/projects/runners_controller.rb
@@ -20,7 +20,7 @@ class Projects::RunnersController < Projects::ApplicationController
if @runner.update_attributes(runner_params)
redirect_to runner_path(@runner), notice: 'Runner was successfully updated.'
else
- redirect_to runner_path(@runner), alert: 'Runner was not updated.'
+ render 'edit'
end
end
diff --git a/app/controllers/projects/variables_controller.rb b/app/controllers/projects/variables_controller.rb
index 00234654578..6f068729390 100644
--- a/app/controllers/projects/variables_controller.rb
+++ b/app/controllers/projects/variables_controller.rb
@@ -3,20 +3,44 @@ class Projects::VariablesController < Projects::ApplicationController
layout 'project_settings'
+ def index
+ @variable = Ci::Variable.new
+ end
+
def show
+ @variable = @project.variables.find(params[:id])
end
def update
- if project.update_attributes(project_params)
+ @variable = @project.variables.find(params[:id])
+
+ if @variable.update_attributes(project_params)
+ redirect_to namespace_project_variables_path(project.namespace, project), notice: 'Variable was successfully updated.'
+ else
+ render action: "show"
+ end
+ end
+
+ def create
+ @variable = Ci::Variable.new(project_params)
+
+ if @variable.valid? && @project.variables << @variable
redirect_to namespace_project_variables_path(project.namespace, project), notice: 'Variables were successfully updated.'
else
- render action: 'show'
+ render action: "index"
end
end
+ def destroy
+ @key = @project.variables.find(params[:id])
+ @key.destroy
+
+ redirect_to namespace_project_variables_path(project.namespace, project), notice: 'Variable was successfully removed.'
+ end
+
private
def project_params
- params.require(:project).permit({ variables_attributes: [:id, :key, :value, :_destroy] })
+ params.require(:variable).permit([:id, :key, :value, :_destroy])
end
end
diff --git a/app/controllers/projects_controller.rb b/app/controllers/projects_controller.rb
index f4ec60ad2c7..9697b88c032 100644
--- a/app/controllers/projects_controller.rb
+++ b/app/controllers/projects_controller.rb
@@ -101,13 +101,7 @@ class ProjectsController < Projects::ApplicationController
respond_to do |format|
format.html do
- if current_user
- @membership = @project.team.find_member(current_user.id)
-
- if @membership
- @notification_setting = current_user.notification_settings_for(@project)
- end
- end
+ @notification_setting = current_user.notification_settings_for(@project) if current_user
if @project.repository_exists?
if @project.empty_repo?
@@ -147,6 +141,7 @@ class ProjectsController < Projects::ApplicationController
@suggestions = {
emojis: AwardEmoji.urls,
issues: autocomplete.issues,
+ milestones: autocomplete.milestones,
mergerequests: autocomplete.merge_requests,
members: participants
}
diff --git a/app/controllers/registrations_controller.rb b/app/controllers/registrations_controller.rb
index 26eb15f49e4..75b78a49eab 100644
--- a/app/controllers/registrations_controller.rb
+++ b/app/controllers/registrations_controller.rb
@@ -38,7 +38,7 @@ class RegistrationsController < Devise::RegistrationsController
end
def after_sign_up_path_for(user)
- user.confirmed_at.present? ? dashboard_projects_path : users_almost_there_path
+ user.confirmed? ? dashboard_projects_path : users_almost_there_path
end
def after_inactive_sign_up_path_for(_resource)
diff --git a/app/finders/pipelines_finder.rb b/app/finders/pipelines_finder.rb
new file mode 100644
index 00000000000..c19a795d467
--- /dev/null
+++ b/app/finders/pipelines_finder.rb
@@ -0,0 +1,38 @@
+class PipelinesFinder
+ attr_reader :project
+
+ def initialize(project)
+ @project = project
+ end
+
+ def execute(pipelines, scope)
+ case scope
+ when 'running'
+ pipelines.running_or_pending
+ when 'branches'
+ from_ids(pipelines, ids_for_ref(pipelines, branches))
+ when 'tags'
+ from_ids(pipelines, ids_for_ref(pipelines, tags))
+ else
+ pipelines
+ end
+ end
+
+ private
+
+ def ids_for_ref(pipelines, refs)
+ pipelines.where(ref: refs).group(:ref).select('max(id)')
+ end
+
+ def from_ids(pipelines, ids)
+ pipelines.unscoped.where(id: ids)
+ end
+
+ def branches
+ project.repository.branches.map(&:name)
+ end
+
+ def tags
+ project.repository.tags.map(&:name)
+ end
+end
diff --git a/app/finders/todos_finder.rb b/app/finders/todos_finder.rb
index 3ba27c40504..4bd46a76087 100644
--- a/app/finders/todos_finder.rb
+++ b/app/finders/todos_finder.rb
@@ -36,7 +36,7 @@ class TodosFinder
private
def action_id?
- action_id.present? && [Todo::ASSIGNED, Todo::MENTIONED].include?(action_id.to_i)
+ action_id.present? && [Todo::ASSIGNED, Todo::MENTIONED, Todo::BUILD_FAILED].include?(action_id.to_i)
end
def action_id
diff --git a/app/helpers/blob_helper.rb b/app/helpers/blob_helper.rb
index 93241b3afb7..cec2dc753fe 100644
--- a/app/helpers/blob_helper.rb
+++ b/app/helpers/blob_helper.rb
@@ -184,4 +184,14 @@ module BlobHelper
Other: licenses.reject(&:featured).map { |license| [license.name, license.key] }
}
end
+
+ def gitignore_names
+ return @gitignore_names if defined?(@gitignore_names)
+
+ @gitignore_names = {
+ Global: Gitlab::Gitignore.global.map { |gitignore| { name: gitignore.name } },
+ # Note that the key here doesn't cover it really
+ Languages: Gitlab::Gitignore.languages_frameworks.map{ |gitignore| { name: gitignore.name } }
+ }
+ end
end
diff --git a/app/helpers/ci_status_helper.rb b/app/helpers/ci_status_helper.rb
index 417050b4132..cfad17dcacf 100644
--- a/app/helpers/ci_status_helper.rb
+++ b/app/helpers/ci_status_helper.rb
@@ -38,19 +38,30 @@ module CiStatusHelper
icon(icon_name + ' fw')
end
- def render_ci_status(ci_commit, tooltip_placement: 'auto left')
- # TODO: split this method into
- # - render_commit_status
- # - render_pipeline_status
- link_to ci_icon_for_status(ci_commit.status),
- ci_status_path(ci_commit),
- class: "ci-status-link ci-status-icon-#{ci_commit.status.dasherize}",
- title: "Build #{ci_label_for_status(ci_commit.status)}",
- data: { toggle: 'tooltip', placement: tooltip_placement }
+ def render_commit_status(commit, tooltip_placement: 'auto left')
+ project = commit.project
+ path = builds_namespace_project_commit_path(project.namespace, project, commit)
+ render_status_with_link('commit', commit.status, path, tooltip_placement)
+ end
+
+ def render_pipeline_status(pipeline, tooltip_placement: 'auto left')
+ project = pipeline.project
+ path = namespace_project_pipeline_path(project.namespace, project, pipeline)
+ render_status_with_link('pipeline', pipeline.status, path, tooltip_placement)
end
def no_runners_for_project?(project)
project.runners.blank? &&
Ci::Runner.shared.blank?
end
+
+ private
+
+ def render_status_with_link(type, status, path, tooltip_placement)
+ link_to ci_icon_for_status(status),
+ path,
+ class: "ci-status-link ci-status-icon-#{status.dasherize}",
+ title: "#{type.titleize}: #{ci_label_for_status(status)}",
+ data: { toggle: 'tooltip', placement: tooltip_placement }
+ end
end
diff --git a/app/helpers/diff_helper.rb b/app/helpers/diff_helper.rb
index 5f311f3780a..ea383f9b0f6 100644
--- a/app/helpers/diff_helper.rb
+++ b/app/helpers/diff_helper.rb
@@ -2,8 +2,8 @@ module DiffHelper
def mark_inline_diffs(old_line, new_line)
old_diffs, new_diffs = Gitlab::Diff::InlineDiff.new(old_line, new_line).inline_diffs
- marked_old_line = Gitlab::Diff::InlineDiffMarker.new(old_line).mark(old_diffs)
- marked_new_line = Gitlab::Diff::InlineDiffMarker.new(new_line).mark(new_diffs)
+ marked_old_line = Gitlab::Diff::InlineDiffMarker.new(old_line).mark(old_diffs, mode: :deletion)
+ marked_new_line = Gitlab::Diff::InlineDiffMarker.new(new_line).mark(new_diffs, mode: :addition)
[marked_old_line, marked_new_line]
end
diff --git a/app/helpers/emails_helper.rb b/app/helpers/emails_helper.rb
index 41b5bd7be90..8466d0aa0ba 100644
--- a/app/helpers/emails_helper.rb
+++ b/app/helpers/emails_helper.rb
@@ -32,12 +32,6 @@ module EmailsHelper
nil
end
- def color_email_diff(diffcontent)
- formatter = Rouge::Formatters::HTML.new(css_class: 'highlight', inline_theme: 'github')
- lexer = Rouge::Lexers::Diff
- raw formatter.format(lexer.lex(diffcontent))
- end
-
def password_reset_token_valid_time
valid_hours = Devise.reset_password_within / 60 / 60
if valid_hours >= 24
diff --git a/app/helpers/gitlab_routing_helper.rb b/app/helpers/gitlab_routing_helper.rb
index f07eff3fb57..2ce2d4e694f 100644
--- a/app/helpers/gitlab_routing_helper.rb
+++ b/app/helpers/gitlab_routing_helper.rb
@@ -33,6 +33,10 @@ module GitlabRoutingHelper
namespace_project_builds_path(project.namespace, project, *args)
end
+ def project_container_registry_path(project, *args)
+ namespace_project_container_registry_index_path(project.namespace, project, *args)
+ end
+
def activity_project_path(project, *args)
activity_namespace_project_path(project.namespace, project, *args)
end
diff --git a/app/helpers/projects_helper.rb b/app/helpers/projects_helper.rb
index e1ab78df69e..5e5d170a9f3 100644
--- a/app/helpers/projects_helper.rb
+++ b/app/helpers/projects_helper.rb
@@ -124,11 +124,7 @@ module ProjectsHelper
end
def license_short_name(project)
- no_license_key = project.repository.license_key.nil? ||
- # Back-compat if cache contains 'no-license', can be removed in a few weeks
- project.repository.license_key == 'no-license'
-
- return 'LICENSE' if no_license_key
+ return 'LICENSE' if project.repository.license_key.nil?
license = Licensee::License.new(project.repository.license_key)
@@ -148,10 +144,18 @@ module ProjectsHelper
nav_tabs << :merge_requests
end
+ if can?(current_user, :read_pipeline, project)
+ nav_tabs << :pipelines
+ end
+
if can?(current_user, :read_build, project)
nav_tabs << :builds
end
+ if Gitlab.config.registry.enabled && can?(current_user, :read_container_image, project)
+ nav_tabs << :container_registry
+ end
+
if can?(current_user, :admin_project, project)
nav_tabs << :settings
end
diff --git a/app/helpers/todos_helper.rb b/app/helpers/todos_helper.rb
index 2f066682180..81b9b5d7052 100644
--- a/app/helpers/todos_helper.rb
+++ b/app/helpers/todos_helper.rb
@@ -11,6 +11,7 @@ module TodosHelper
case todo.action
when Todo::ASSIGNED then 'assigned you'
when Todo::MENTIONED then 'mentioned you on'
+ when Todo::BUILD_FAILED then 'The build failed for your'
end
end
@@ -28,8 +29,11 @@ module TodosHelper
namespace_project_commit_path(todo.project.namespace.becomes(Namespace), todo.project,
todo.target, anchor: anchor)
else
- polymorphic_path([todo.project.namespace.becomes(Namespace),
- todo.project, todo.target], anchor: anchor)
+ path = [todo.project.namespace.becomes(Namespace), todo.project, todo.target]
+
+ path.unshift(:builds) if todo.build_failed?
+
+ polymorphic_path(path, anchor: anchor)
end
end
diff --git a/app/mailers/emails/projects.rb b/app/mailers/emails/projects.rb
index 5489283432b..fdf1e9f5afc 100644
--- a/app/mailers/emails/projects.rb
+++ b/app/mailers/emails/projects.rb
@@ -65,7 +65,8 @@ module Emails
# used in notify layout
@target_url = @message.target_url
- @project = Project.find project_id
+ @project = Project.find(project_id)
+ @diff_notes_disabled = true
add_project_headers
headers['X-GitLab-Author'] = @message.author_username
diff --git a/app/mailers/notify.rb b/app/mailers/notify.rb
index 826e5f96fa1..1c663bdd521 100644
--- a/app/mailers/notify.rb
+++ b/app/mailers/notify.rb
@@ -10,6 +10,8 @@ class Notify < BaseMailer
include Emails::Builds
add_template_helper MergeRequestsHelper
+ add_template_helper DiffHelper
+ add_template_helper BlobHelper
add_template_helper EmailsHelper
def test_email(recipient_email, subject, body)
diff --git a/app/models/ability.rb b/app/models/ability.rb
index f70268d3138..b354b1990c7 100644
--- a/app/models/ability.rb
+++ b/app/models/ability.rb
@@ -60,6 +60,7 @@ class Ability
:read_project_member,
:read_merge_request,
:read_note,
+ :read_pipeline,
:read_commit_status,
:read_container_image,
:download_code
@@ -205,6 +206,7 @@ class Ability
:read_commit_status,
:read_build,
:read_container_image,
+ :read_pipeline,
]
end
@@ -216,6 +218,8 @@ class Ability
:update_commit_status,
:create_build,
:update_build,
+ :create_pipeline,
+ :update_pipeline,
:create_merge_request,
:create_wiki,
:push_code,
@@ -248,6 +252,7 @@ class Ability
:admin_commit_status,
:admin_build,
:admin_container_image,
+ :admin_pipeline
]
end
@@ -290,6 +295,7 @@ class Ability
unless project.builds_enabled
rules += named_abilities('build')
+ rules += named_abilities('pipeline')
end
unless project.container_registry_enabled
diff --git a/app/models/application_setting.rb b/app/models/application_setting.rb
index f5079f92444..9a14954b4a7 100644
--- a/app/models/application_setting.rb
+++ b/app/models/application_setting.rb
@@ -7,7 +7,7 @@ class ApplicationSetting < ActiveRecord::Base
serialize :restricted_visibility_levels
serialize :import_sources
- serialize :disabled_oauth_sign_in_sources
+ serialize :disabled_oauth_sign_in_sources, Array
serialize :restricted_signup_domains, Array
attr_accessor :restricted_signup_domains_raw
diff --git a/app/models/ci/build.rb b/app/models/ci/build.rb
index 92327bdb08d..ff7dd44c526 100644
--- a/app/models/ci/build.rb
+++ b/app/models/ci/build.rb
@@ -53,6 +53,7 @@ module Ci
new_build.stage_idx = build.stage_idx
new_build.trigger_request = build.trigger_request
new_build.save
+ MergeRequests::AddTodoWhenBuildFailsService.new(build.project, nil).close(new_build)
new_build
end
end
@@ -290,9 +291,15 @@ module Ci
end
def can_be_served?(runner)
+ return false unless has_tags? || runner.run_untagged?
+
(tag_list - runner.tag_list).empty?
end
+ def has_tags?
+ tag_list.any?
+ end
+
def any_runners_online?
project.any_runners? { |runner| runner.active? && runner.online? && can_be_served?(runner) }
end
diff --git a/app/models/ci/commit.rb b/app/models/ci/commit.rb
index f4b61c75ab6..6675a3f5d53 100644
--- a/app/models/ci/commit.rb
+++ b/app/models/ci/commit.rb
@@ -8,8 +8,6 @@ module Ci
has_many :builds, class_name: 'Ci::Build'
has_many :trigger_requests, dependent: :destroy, class_name: 'Ci::TriggerRequest'
- delegate :stages, to: :statuses
-
validates_presence_of :sha
validates_presence_of :status
validate :valid_commit_sha
@@ -22,7 +20,8 @@ module Ci
end
def self.stages
- CommitStatus.where(commit: all).stages
+ # We use pluck here due to problems with MySQL which doesn't allow LIMIT/OFFSET in queries
+ CommitStatus.where(commit: pluck(:id)).stages
end
def project_id
@@ -67,6 +66,25 @@ module Ci
end
end
+ def cancel_running
+ builds.running_or_pending.each(&:cancel)
+ end
+
+ def retry_failed
+ builds.latest.failed.select(&:retryable?).each(&:retry)
+ end
+
+ def latest?
+ return false unless ref
+ commit = project.commit(ref)
+ return false unless commit
+ commit.sha == sha
+ end
+
+ def triggered?
+ trigger_requests.any?
+ end
+
def create_builds(user, trigger_request = nil)
return unless config_processor
config_processor.stages.any? do |stage|
diff --git a/app/models/ci/runner.rb b/app/models/ci/runner.rb
index 819064f99bb..6829dc91cb9 100644
--- a/app/models/ci/runner.rb
+++ b/app/models/ci/runner.rb
@@ -4,7 +4,7 @@ module Ci
LAST_CONTACT_TIME = 5.minutes.ago
AVAILABLE_SCOPES = %w[specific shared active paused online]
- FORM_EDITABLE = %i[description tag_list active]
+ FORM_EDITABLE = %i[description tag_list active run_untagged]
has_many :builds, class_name: 'Ci::Build'
has_many :runner_projects, dependent: :destroy, class_name: 'Ci::RunnerProject'
@@ -26,6 +26,8 @@ module Ci
.where("ci_runner_projects.gl_project_id = :project_id OR ci_runners.is_shared = true", project_id: project_id)
end
+ validate :tag_constraints
+
acts_as_taggable
# Searches for runners matching the given query.
@@ -96,5 +98,18 @@ module Ci
def short_sha
token[0...8] if token
end
+
+ def has_tags?
+ tag_list.any?
+ end
+
+ private
+
+ def tag_constraints
+ unless has_tags? || run_untagged?
+ errors.add(:tags_list,
+ 'can not be empty when runner is not allowed to pick untagged jobs')
+ end
+ end
end
end
diff --git a/app/models/commit_status.rb b/app/models/commit_status.rb
index cacbc13b391..f774b6e0efb 100644
--- a/app/models/commit_status.rb
+++ b/app/models/commit_status.rb
@@ -14,7 +14,8 @@ class CommitStatus < ActiveRecord::Base
alias_attribute :author, :user
scope :latest, -> { where(id: unscope(:select).select('max(id)').group(:name, :commit_id)) }
- scope :ordered, -> { order(:ref, :stage_idx, :name) }
+ scope :retried, -> { where.not(id: latest) }
+ scope :ordered, -> { order(:name) }
scope :ignored, -> { where(allow_failure: true, status: [:failed, :canceled]) }
state_machine :status, initial: :pending do
@@ -45,6 +46,10 @@ class CommitStatus < ActiveRecord::Base
after_transition [:pending, :running] => :success do |commit_status|
MergeRequests::MergeWhenBuildSucceedsService.new(commit_status.commit.project, nil).trigger(commit_status)
end
+
+ after_transition any => :failed do |commit_status|
+ MergeRequests::AddTodoWhenBuildFailsService.new(commit_status.commit.project, nil).execute(commit_status)
+ end
end
delegate :sha, :short_sha, to: :commit
@@ -54,13 +59,15 @@ class CommitStatus < ActiveRecord::Base
end
def self.stages
- order_by = 'max(stage_idx)'
- group('stage').order(order_by).pluck(:stage, order_by).map(&:first).compact
+ # 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')
end
def self.stages_status
- all.stages.inject({}) do |h, stage|
- h[stage] = all.where(stage: stage).status
+ # We execute subquery for each stage to calculate a stage status
+ statuses = unscoped.from(all, :sg).group('stage').pluck('sg.stage', all.where('stage=sg.stage').status_sql)
+ statuses.inject({}) do |h, k|
+ h[k.first] = k.last
h
end
end
diff --git a/app/models/merge_request.rb b/app/models/merge_request.rb
index 45ddcf6812a..722c258244c 100644
--- a/app/models/merge_request.rb
+++ b/app/models/merge_request.rb
@@ -286,6 +286,18 @@ class MergeRequest < ActiveRecord::Base
last_commit == source_project.commit(source_branch)
end
+ def should_remove_source_branch?
+ merge_params['should_remove_source_branch'].present?
+ end
+
+ def force_remove_source_branch?
+ merge_params['force_remove_source_branch'].present?
+ end
+
+ def remove_source_branch?
+ should_remove_source_branch? || force_remove_source_branch?
+ end
+
def mr_and_commit_notes
# Fetch comments only from last 100 commits
commits_for_notes_limit = 100
@@ -426,7 +438,10 @@ class MergeRequest < ActiveRecord::Base
self.merge_when_build_succeeds = false
self.merge_user = nil
- self.merge_params = nil
+ if merge_params
+ merge_params.delete('should_remove_source_branch')
+ merge_params.delete('commit_message')
+ end
self.save
end
diff --git a/app/models/merge_request_diff.rb b/app/models/merge_request_diff.rb
index 6ad8fc3f034..7d5103748f5 100644
--- a/app/models/merge_request_diff.rb
+++ b/app/models/merge_request_diff.rb
@@ -98,9 +98,7 @@ class MergeRequestDiff < ActiveRecord::Base
commits = compare.commits
if commits.present?
- commits = Commit.decorate(commits, merge_request.source_project).
- sort_by(&:created_at).
- reverse
+ commits = Commit.decorate(commits, merge_request.source_project).reverse
end
commits
diff --git a/app/models/milestone.rb b/app/models/milestone.rb
index fe9a281f366..e0c8454a998 100644
--- a/app/models/milestone.rb
+++ b/app/models/milestone.rb
@@ -59,8 +59,27 @@ class Milestone < ActiveRecord::Base
end
end
+ def self.reference_prefix
+ '%'
+ end
+
def self.reference_pattern
- nil
+ # NOTE: The iid pattern only matches when all characters on the expression
+ # are digits, so it will match %2 but not %2.1 because that's probably a
+ # milestone name and we want it to be matched as such.
+ @reference_pattern ||= %r{
+ (#{Project.reference_pattern})?
+ #{Regexp.escape(reference_prefix)}
+ (?:
+ (?<milestone_iid>
+ \d+(?!\S\w)\b # Integer-based milestone iid, or
+ ) |
+ (?<milestone_name>
+ [^"\s]+\b | # String-based single-word milestone title, or
+ "[^"]+" # String-based multi-word milestone surrounded in quotes
+ )
+ )
+ }x
end
def self.link_reference_pattern
@@ -81,13 +100,26 @@ class Milestone < ActiveRecord::Base
end
end
- def to_reference(from_project = nil)
- escaped_title = self.title.gsub("]", "\\]")
-
- h = Gitlab::Routing.url_helpers
- url = h.namespace_project_milestone_url(self.project.namespace, self.project, self)
+ ##
+ # Returns the String necessary to reference this Milestone in Markdown
+ #
+ # format - Symbol format to use (default: :iid, optional: :name)
+ #
+ # Examples:
+ #
+ # Milestone.first.to_reference # => "%1"
+ # Milestone.first.to_reference(format: :name) # => "%\"goal\""
+ # Milestone.first.to_reference(project) # => "gitlab-org/gitlab-ce%1"
+ #
+ def to_reference(from_project = nil, format: :iid)
+ format_reference = milestone_format_reference(format)
+ reference = "#{self.class.reference_prefix}#{format_reference}"
- "[#{escaped_title}](#{url})"
+ if cross_project_reference?(from_project)
+ project.to_reference + reference
+ else
+ reference
+ end
end
def reference_link_text(from_project = nil)
@@ -159,4 +191,16 @@ class Milestone < ActiveRecord::Base
issues.where(id: ids).
update_all(["position = CASE #{conditions} ELSE position END", *pairs])
end
+
+ private
+
+ def milestone_format_reference(format = :iid)
+ raise ArgumentError, 'Unknown format' unless [:iid, :name].include?(format)
+
+ if format == :name && !name.include?('"')
+ %("#{name}")
+ else
+ iid
+ end
+ end
end
diff --git a/app/models/namespace.rb b/app/models/namespace.rb
index 9c942a8f4e3..da19462f265 100644
--- a/app/models/namespace.rb
+++ b/app/models/namespace.rb
@@ -110,6 +110,10 @@ class Namespace < ActiveRecord::Base
# Ensure old directory exists before moving it
gitlab_shell.add_namespace(path_was)
+ if any_project_has_container_registry_tags?
+ raise Exception.new('Namespace cannot be moved, because at least one project has tags in container registry')
+ end
+
if gitlab_shell.mv_namespace(path_was, path)
Gitlab::UploadsTransfer.new.rename_namespace(path_was, path)
@@ -131,6 +135,10 @@ class Namespace < ActiveRecord::Base
end
end
+ def any_project_has_container_registry_tags?
+ projects.any?(&:has_container_registry_tags?)
+ end
+
def send_update_instructions
projects.each do |project|
project.send_move_instructions("#{path_was}/#{project.path}")
diff --git a/app/models/project.rb b/app/models/project.rb
index a3c4f1d8e9b..37de1dfe4d5 100644
--- a/app/models/project.rb
+++ b/app/models/project.rb
@@ -171,17 +171,17 @@ class Project < ActiveRecord::Base
scope :sorted_by_activity, -> { reorder(last_activity_at: :desc) }
scope :sorted_by_stars, -> { reorder('projects.star_count DESC') }
- scope :sorted_by_names, -> { joins(:namespace).reorder('namespaces.name ASC, projects.name ASC') }
- scope :without_user, ->(user) { where('projects.id NOT IN (:ids)', ids: user.authorized_projects.map(&:id) ) }
- scope :without_team, ->(team) { team.projects.present? ? where('projects.id NOT IN (:ids)', ids: team.projects.map(&:id)) : scoped }
- scope :not_in_group, ->(group) { where('projects.id NOT IN (:ids)', ids: group.project_ids ) }
scope :in_namespace, ->(namespace_ids) { where(namespace_id: namespace_ids) }
- scope :in_group_namespace, -> { joins(:group) }
scope :personal, ->(user) { where(namespace_id: user.namespace_id) }
scope :joined, ->(user) { where('namespace_id != ?', user.namespace_id) }
+ scope :visible_to_user, ->(user) { where(id: user.authorized_projects.select(:id).reorder(nil)) }
scope :non_archived, -> { where(archived: false) }
scope :for_milestones, ->(ids) { joins(:milestones).where('milestones.id' => ids).distinct }
+ scope :with_push, -> { joins(:events).where('events.action = ?', Event::PUSHED) }
+
+ scope :active, -> { joins(:issues, :notes, :merge_requests).order('issues.created_at, notes.created_at, merge_requests.created_at DESC') }
+ scope :abandoned, -> { where('projects.last_activity_at < ?', 6.months.ago) }
state_machine :import_status, initial: :none do
event :import_start do
@@ -204,23 +204,10 @@ class Project < ActiveRecord::Base
state :finished
state :failed
- after_transition any => :started, do: :schedule_add_import_job
- after_transition any => :finished, do: :clear_import_data
+ after_transition any => :finished, do: :reset_cache_and_import_attrs
end
class << self
- def abandoned
- where('projects.last_activity_at < ?', 6.months.ago)
- end
-
- def with_push
- joins(:events).where('events.action = ?', Event::PUSHED)
- end
-
- def active
- joins(:issues, :notes, :merge_requests).order('issues.created_at, notes.created_at, merge_requests.created_at DESC')
- end
-
# Searches for a list of projects based on the query given in `query`.
#
# On PostgreSQL this method uses "ILIKE" to perform a case-insensitive
@@ -282,10 +269,6 @@ class Project < ActiveRecord::Base
projects.iwhere('projects.path' => project_path).take
end
- def find_by_ci_id(id)
- find_by(ci_id: id.to_i)
- end
-
def visibility_levels
Gitlab::VisibilityLevel.options
end
@@ -316,10 +299,6 @@ class Project < ActiveRecord::Base
joins(join_body).reorder('join_note_counts.amount DESC')
end
-
- def visible_to_user(user)
- where(id: user.authorized_projects.select(:id).reorder(nil))
- end
end
def team
@@ -330,12 +309,30 @@ class Project < ActiveRecord::Base
@repository ||= Repository.new(path_with_namespace, self)
end
- def container_registry_url
- if container_registry_enabled? && Gitlab.config.registry.enabled
- "#{Gitlab.config.registry.host_with_port}/#{path_with_namespace}"
+ def container_registry_repository
+ return unless Gitlab.config.registry.enabled
+
+ @container_registry_repository ||= begin
+ token = Auth::ContainerRegistryAuthenticationService.full_access_token(path_with_namespace)
+ url = Gitlab.config.registry.api_url
+ host_port = Gitlab.config.registry.host_port
+ registry = ContainerRegistry::Registry.new(url, token: token, path: host_port)
+ registry.repository(path_with_namespace)
end
end
+ def container_registry_repository_url
+ if Gitlab.config.registry.enabled
+ "#{Gitlab.config.registry.host_port}/#{path_with_namespace}"
+ end
+ end
+
+ def has_container_registry_tags?
+ return unless container_registry_repository
+
+ container_registry_repository.tags.any?
+ end
+
def commit(id = 'HEAD')
repository.commit(id)
end
@@ -349,10 +346,6 @@ class Project < ActiveRecord::Base
id && persisted?
end
- def schedule_add_import_job
- run_after_commit(:add_import_job)
- end
-
def add_import_job
if forked?
job_id = RepositoryForkWorker.perform_async(self.id, forked_from_project.path_with_namespace, self.namespace.path)
@@ -367,7 +360,7 @@ class Project < ActiveRecord::Base
end
end
- def clear_import_data
+ def reset_cache_and_import_attrs
update(import_error: nil)
ProjectCacheWorker.perform_async(self.id)
@@ -376,14 +369,14 @@ class Project < ActiveRecord::Base
end
def import_url=(value)
- import_url = Gitlab::ImportUrl.new(value)
+ import_url = Gitlab::UrlSanitizer.new(value)
create_or_update_import_data(credentials: import_url.credentials)
super(import_url.sanitized_url)
end
def import_url
if import_data && super
- import_url = Gitlab::ImportUrl.new(super, credentials: import_data.credentials)
+ import_url = Gitlab::UrlSanitizer.new(super, credentials: import_data.credentials)
import_url.full_url
else
super
@@ -433,12 +426,7 @@ class Project < ActiveRecord::Base
end
def safe_import_url
- result = URI.parse(self.import_url)
- result.password = '*****' unless result.password.nil?
- result.user = '*****' unless result.user.nil? || result.user == "git" #tokens or other data may be saved as user
- result.to_s
- rescue
- self.import_url
+ Gitlab::UrlSanitizer.new(import_url).masked_url
end
def check_limit
@@ -751,6 +739,11 @@ class Project < ActiveRecord::Base
expire_caches_before_rename(old_path_with_namespace)
+ if has_container_registry_tags?
+ # we currently doesn't support renaming repository if it contains tags in container registry
+ raise Exception.new('Project cannot be renamed, because tags are present in its container registry')
+ end
+
if gitlab_shell.mv_repository(old_path_with_namespace, new_path_with_namespace)
# If repository moved successfully we need to send update instructions to users.
# However we cannot allow rollback since we moved repository
diff --git a/app/models/project_services/slack_service/issue_message.rb b/app/models/project_services/slack_service/issue_message.rb
index 438ff33fdff..88e053ec192 100644
--- a/app/models/project_services/slack_service/issue_message.rb
+++ b/app/models/project_services/slack_service/issue_message.rb
@@ -34,7 +34,12 @@ class SlackService
private
def message
- "#{user_name} #{state} #{issue_link} in #{project_link}: *#{title}*"
+ case state
+ when "opened"
+ "[#{project_link}] Issue #{state} by #{user_name}"
+ else
+ "[#{project_link}] Issue #{issue_link} #{state} by #{user_name}"
+ end
end
def opened_issue?
@@ -42,7 +47,11 @@ class SlackService
end
def description_message
- [{ text: format(description), color: attachment_color }]
+ [{
+ title: issue_title,
+ title_link: issue_url,
+ text: format(description),
+ color: "#C95823" }]
end
def project_link
@@ -50,7 +59,11 @@ class SlackService
end
def issue_link
- "[issue ##{issue_iid}](#{issue_url})"
+ "[#{issue_title}](#{issue_url})"
+ end
+
+ def issue_title
+ "##{issue_iid} #{title}"
end
end
end
diff --git a/app/models/repository.rb b/app/models/repository.rb
index 3716ea6ad6c..ecc8795c954 100644
--- a/app/models/repository.rb
+++ b/app/models/repository.rb
@@ -245,7 +245,7 @@ class Repository
def cache_keys
%i(size branch_names tag_names commit_count
readme version contribution_guide changelog
- license_blob license_key)
+ license_blob license_key gitignore)
end
def build_cache
@@ -256,6 +256,10 @@ class Repository
end
end
+ def expire_gitignore
+ cache.expire(:gitignore)
+ end
+
def expire_tags_cache
cache.expire(:tag_names)
@tags = nil
@@ -472,33 +476,37 @@ class Repository
def changelog
cache.fetch(:changelog) do
- tree(:head).blobs.find do |file|
- file.name =~ /\A(changelog|history|changes|news)/i
- end
+ file_on_head(/\A(changelog|history|changes|news)/i)
end
end
def license_blob
- return nil if !exists? || empty?
+ return nil unless head_exists?
cache.fetch(:license_blob) do
- tree(:head).blobs.find do |file|
- file.name =~ /\A(licen[sc]e|copying)(\..+|\z)/i
- end
+ file_on_head(/\A(licen[sc]e|copying)(\..+|\z)/i)
end
end
def license_key
- return nil if !exists? || empty?
+ return nil unless head_exists?
cache.fetch(:license_key) do
Licensee.license(path).try(:key)
end
end
- def gitlab_ci_yml
+ def gitignore
return nil if !exists? || empty?
+ cache.fetch(:gitignore) do
+ file_on_head(/\A\.gitignore\z/)
+ end
+ end
+
+ def gitlab_ci_yml
+ return nil unless head_exists?
+
@gitlab_ci_yml ||= tree(:head).blobs.find do |file|
file.name == '.gitlab-ci.yml'
end
@@ -854,7 +862,7 @@ class Repository
def search_files(query, ref)
offset = 2
- args = %W(#{Gitlab.config.git.bin_path} grep -i -I -n --before-context #{offset} --after-context #{offset} -e #{Regexp.escape(query)} #{ref || root_ref})
+ args = %W(#{Gitlab.config.git.bin_path} grep -i -I -n --before-context #{offset} --after-context #{offset} -E -e #{Regexp.escape(query)} #{ref || root_ref})
Gitlab::Popen.popen(args, path_to_repo).first.scrub.split(/^--$/)
end
@@ -965,7 +973,7 @@ class Repository
end
def main_language
- return if empty? || rugged.head_unborn?
+ return unless head_exists?
Linguist::Repository.new(rugged, rugged.head.target_id).language
end
@@ -985,4 +993,12 @@ class Repository
def cache
@cache ||= RepositoryCache.new(path_with_namespace)
end
+
+ def head_exists?
+ exists? && !empty? && !rugged.head_unborn?
+ end
+
+ def file_on_head(regex)
+ tree(:head).blobs.find { |file| file.name =~ regex }
+ end
end
diff --git a/app/models/todo.rb b/app/models/todo.rb
index f8b59fe4126..3a091373329 100644
--- a/app/models/todo.rb
+++ b/app/models/todo.rb
@@ -1,6 +1,7 @@
class Todo < ActiveRecord::Base
- ASSIGNED = 1
- MENTIONED = 2
+ ASSIGNED = 1
+ MENTIONED = 2
+ BUILD_FAILED = 3
belongs_to :author, class_name: "User"
belongs_to :note
@@ -28,6 +29,10 @@ class Todo < ActiveRecord::Base
state :done
end
+ def build_failed?
+ action == BUILD_FAILED
+ end
+
def body
if note.present?
note.note
diff --git a/app/models/user.rb b/app/models/user.rb
index 368a3f3cfba..6a09b78455b 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -397,11 +397,6 @@ class User < ActiveRecord::Base
owned_groups.select(:id), namespace.id).joins(:namespace)
end
- # Team membership in authorized projects
- def tm_in_authorized_projects
- ProjectMember.where(source_id: authorized_projects.map(&:id), user_id: self.id)
- end
-
def is_admin?
admin
end
@@ -491,10 +486,6 @@ class User < ActiveRecord::Base
"#{name} (#{username})"
end
- def tm_of(project)
- project.project_member_by_id(self.id)
- end
-
def already_forked?(project)
!!fork_of(project)
end
diff --git a/app/services/auth/container_registry_authentication_service.rb b/app/services/auth/container_registry_authentication_service.rb
index b636f55d031..2bbab643e69 100644
--- a/app/services/auth/container_registry_authentication_service.rb
+++ b/app/services/auth/container_registry_authentication_service.rb
@@ -6,7 +6,7 @@ module Auth
return error('not found', 404) unless registry.enabled
if params[:offline_token]
- return error('forbidden', 403) unless current_user
+ return error('unauthorized', 401) unless current_user || project
else
return error('forbidden', 403) unless scope
end
@@ -14,6 +14,17 @@ module Auth
{ token: authorized_token(scope).encoded }
end
+ def self.full_access_token(*names)
+ registry = Gitlab.config.registry
+ token = JSONWebToken::RSAToken.new(registry.key)
+ token.issuer = registry.issuer
+ token.audience = AUDIENCE
+ token[:access] = names.map do |name|
+ { type: 'repository', name: name, actions: %w(*) }
+ end
+ token.encoded
+ end
+
private
def authorized_token(*accesses)
diff --git a/app/services/ci/create_pipeline_service.rb b/app/services/ci/create_pipeline_service.rb
new file mode 100644
index 00000000000..5bc0c31cb42
--- /dev/null
+++ b/app/services/ci/create_pipeline_service.rb
@@ -0,0 +1,50 @@
+module Ci
+ class CreatePipelineService < BaseService
+ def execute
+ pipeline = project.ci_commits.new(params)
+
+ unless ref_names.include?(params[:ref])
+ pipeline.errors.add(:base, 'Reference not found')
+ return pipeline
+ end
+
+ unless commit
+ pipeline.errors.add(:base, 'Commit not found')
+ return pipeline
+ end
+
+ unless can?(current_user, :create_pipeline, project)
+ pipeline.errors.add(:base, 'Insufficient permissions to create a new pipeline')
+ return pipeline
+ end
+
+ begin
+ Ci::Commit.transaction do
+ pipeline.sha = commit.id
+
+ unless pipeline.config_processor
+ pipeline.errors.add(:base, pipeline.yaml_errors || 'Missing .gitlab-ci.yml file')
+ raise ActiveRecord::Rollback
+ end
+
+ pipeline.save!
+ pipeline.create_builds(current_user)
+ end
+ rescue
+ pipeline.errors.add(:base, 'The pipeline could not be created. Please try again.')
+ end
+
+ pipeline
+ end
+
+ private
+
+ def ref_names
+ @ref_names ||= project.repository.ref_names
+ end
+
+ def commit
+ @commit ||= project.commit(params[:ref])
+ end
+ end
+end
diff --git a/app/services/create_commit_builds_service.rb b/app/services/create_commit_builds_service.rb
index 0d2aa1ff03d..5b6fefe669e 100644
--- a/app/services/create_commit_builds_service.rb
+++ b/app/services/create_commit_builds_service.rb
@@ -18,19 +18,16 @@ class CreateCommitBuildsService
return false
end
- commit = project.ci_commit(sha, ref)
- unless commit
- commit = project.ci_commits.new(sha: sha, ref: ref, before_sha: before_sha, tag: tag)
+ commit = Ci::Commit.new(project: project, sha: sha, ref: ref, before_sha: before_sha, tag: tag)
- # Skip creating ci_commit when no gitlab-ci.yml is found
- unless commit.ci_yaml_file
- return false
- end
-
- # Create a new ci_commit
- commit.save!
+ # Skip creating ci_commit when no gitlab-ci.yml is found
+ unless commit.ci_yaml_file
+ return false
end
+ # Create a new ci_commit
+ commit.save!
+
# Skip creating builds for commits that have [ci skip]
unless commit.skip_ci?
# Create builds for commit
diff --git a/app/services/issues/update_service.rb b/app/services/issues/update_service.rb
index 3563cbaa997..c7d406cc331 100644
--- a/app/services/issues/update_service.rb
+++ b/app/services/issues/update_service.rb
@@ -24,6 +24,10 @@ module Issues
todo_service.reassigned_issue(issue, current_user)
end
+ if issue.previous_changes.include?('confidential')
+ create_confidentiality_note(issue)
+ end
+
added_labels = issue.labels - old_labels
if added_labels.present?
notification_service.relabeled_issue(issue, added_labels, current_user)
@@ -37,5 +41,11 @@ module Issues
def close_service
Issues::CloseService
end
+
+ private
+
+ def create_confidentiality_note(issue)
+ SystemNoteService.change_issue_confidentiality(issue, issue.project, current_user)
+ end
end
end
diff --git a/app/services/merge_requests/add_todo_when_build_fails_service.rb b/app/services/merge_requests/add_todo_when_build_fails_service.rb
new file mode 100644
index 00000000000..566049525cb
--- /dev/null
+++ b/app/services/merge_requests/add_todo_when_build_fails_service.rb
@@ -0,0 +1,17 @@
+module MergeRequests
+ class AddTodoWhenBuildFailsService < MergeRequests::BaseService
+ # Adds a todo to the parent merge_request when a CI build fails
+ def execute(commit_status)
+ each_merge_request(commit_status) do |merge_request|
+ todo_service.merge_request_build_failed(merge_request)
+ end
+ end
+
+ # Closes any pending build failed todos for the parent MRs when a build is retried
+ def close(commit_status)
+ each_merge_request(commit_status) do |merge_request|
+ todo_service.merge_request_build_retried(merge_request)
+ end
+ end
+ end
+end
diff --git a/app/services/merge_requests/base_service.rb b/app/services/merge_requests/base_service.rb
index e6837a18696..9d7fca6882d 100644
--- a/app/services/merge_requests/base_service.rb
+++ b/app/services/merge_requests/base_service.rb
@@ -38,5 +38,30 @@ module MergeRequests
def filter_params
super(:merge_request)
end
+
+ def merge_request_from(commit_status)
+ branches = commit_status.ref
+
+ # This is for ref-less builds
+ branches ||= @project.repository.branch_names_contains(commit_status.sha)
+
+ return [] if branches.blank?
+
+ merge_requests = @project.origin_merge_requests.opened.where(source_branch: branches).to_a
+ merge_requests += @project.fork_merge_requests.opened.where(source_branch: branches).to_a
+
+ merge_requests.uniq.select(&:source_project)
+ end
+
+ def each_merge_request(commit_status)
+ merge_request_from(commit_status).each do |merge_request|
+ ci_commit = merge_request.ci_commit
+
+ next unless ci_commit
+ next unless ci_commit.sha == commit_status.sha
+
+ yield merge_request, ci_commit
+ end
+ end
end
end
diff --git a/app/services/merge_requests/create_service.rb b/app/services/merge_requests/create_service.rb
index 33609d01f20..96a25330af1 100644
--- a/app/services/merge_requests/create_service.rb
+++ b/app/services/merge_requests/create_service.rb
@@ -8,11 +8,14 @@ module MergeRequests
@project = Project.find(params[:target_project_id]) if params[:target_project_id]
filter_params
- label_params = params[:label_ids]
- merge_request = MergeRequest.new(params.except(:label_ids))
+ label_params = params.delete(:label_ids)
+ force_remove_source_branch = params.delete(:force_remove_source_branch)
+
+ merge_request = MergeRequest.new(params)
merge_request.source_project = source_project
merge_request.target_project ||= source_project
merge_request.author = current_user
+ merge_request.merge_params['force_remove_source_branch'] = force_remove_source_branch
if merge_request.save
merge_request.update_attributes(label_ids: label_params)
diff --git a/app/services/merge_requests/merge_service.rb b/app/services/merge_requests/merge_service.rb
index 9a58383b398..9aaf5a5e561 100644
--- a/app/services/merge_requests/merge_service.rb
+++ b/app/services/merge_requests/merge_service.rb
@@ -45,10 +45,14 @@ module MergeRequests
def after_merge
MergeRequests::PostMergeService.new(project, current_user).execute(merge_request)
- if params[:should_remove_source_branch].present?
- DeleteBranchService.new(@merge_request.source_project, current_user).
+ if params[:should_remove_source_branch].present? || @merge_request.force_remove_source_branch?
+ DeleteBranchService.new(@merge_request.source_project, branch_deletion_user).
execute(merge_request.source_branch)
end
end
+
+ def branch_deletion_user
+ @merge_request.force_remove_source_branch? ? @merge_request.author : current_user
+ end
end
end
diff --git a/app/services/merge_requests/merge_when_build_succeeds_service.rb b/app/services/merge_requests/merge_when_build_succeeds_service.rb
index d6af12f9739..8fd6a4ea1f6 100644
--- a/app/services/merge_requests/merge_when_build_succeeds_service.rb
+++ b/app/services/merge_requests/merge_when_build_succeeds_service.rb
@@ -20,15 +20,9 @@ module MergeRequests
# Triggers the automatic merge of merge_request once the build succeeds
def trigger(commit_status)
- merge_requests = merge_request_from(commit_status)
-
- merge_requests.each do |merge_request|
+ each_merge_request(commit_status) do |merge_request, ci_commit|
next unless merge_request.merge_when_build_succeeds?
next unless merge_request.mergeable?
-
- ci_commit = merge_request.ci_commit
- next unless ci_commit
- next unless ci_commit.sha == commit_status.sha
next unless ci_commit.success?
MergeWorker.perform_async(merge_request.id, merge_request.merge_user_id, merge_request.merge_params)
@@ -47,20 +41,5 @@ module MergeRequests
end
end
- private
-
- def merge_request_from(commit_status)
- branches = commit_status.ref
-
- # This is for ref-less builds
- branches ||= @project.repository.branch_names_contains(commit_status.sha)
-
- return [] if branches.blank?
-
- merge_requests = @project.origin_merge_requests.opened.where(source_branch: branches).to_a
- merge_requests += @project.fork_merge_requests.opened.where(source_branch: branches).to_a
-
- merge_requests.uniq.select(&:source_project)
- end
end
end
diff --git a/app/services/merge_requests/refresh_service.rb b/app/services/merge_requests/refresh_service.rb
index 8b3d56c2b4c..fe0579744b4 100644
--- a/app/services/merge_requests/refresh_service.rb
+++ b/app/services/merge_requests/refresh_service.rb
@@ -12,6 +12,7 @@ module MergeRequests
close_merge_requests
reload_merge_requests
reset_merge_when_build_succeeds
+ mark_pending_todos_done
# Leave a system note if a branch was deleted/added
if branch_added? || branch_removed?
@@ -80,6 +81,12 @@ module MergeRequests
merge_requests_for_source_branch.each(&:reset_merge_when_build_succeeds)
end
+ def mark_pending_todos_done
+ merge_requests_for_source_branch.each do |merge_request|
+ todo_service.merge_request_push(merge_request, @current_user)
+ end
+ end
+
def find_new_commits
if branch_added?
@commits = []
diff --git a/app/services/merge_requests/update_service.rb b/app/services/merge_requests/update_service.rb
index 477c64e7377..026a37997d4 100644
--- a/app/services/merge_requests/update_service.rb
+++ b/app/services/merge_requests/update_service.rb
@@ -11,6 +11,8 @@ module MergeRequests
params.except!(:target_project_id)
params.except!(:source_branch)
+ merge_request.merge_params['force_remove_source_branch'] = params.delete(:force_remove_source_branch)
+
update(merge_request)
end
diff --git a/app/services/projects/autocomplete_service.rb b/app/services/projects/autocomplete_service.rb
index ba50305dbd5..eb73948006e 100644
--- a/app/services/projects/autocomplete_service.rb
+++ b/app/services/projects/autocomplete_service.rb
@@ -4,6 +4,10 @@ module Projects
@project.issues.visible_to_user(current_user).opened.select([:iid, :title])
end
+ def milestones
+ @project.milestones.active.reorder(due_date: :asc, title: :asc).select([:iid, :title])
+ end
+
def merge_requests
@project.merge_requests.opened.select([:iid, :title])
end
diff --git a/app/services/projects/create_service.rb b/app/services/projects/create_service.rb
index 501e58c1407..6728fabea1e 100644
--- a/app/services/projects/create_service.rb
+++ b/app/services/projects/create_service.rb
@@ -6,6 +6,7 @@ module Projects
def execute
forked_from_project_id = params.delete(:forked_from_project_id)
+ import_data = params.delete(:import_data)
@project = Project.new(params)
@@ -49,16 +50,14 @@ module Projects
@project.build_forked_project_link(forked_from_project_id: forked_from_project_id)
end
- Project.transaction do
- @project.save
+ save_project_and_import_data(import_data)
- if @project.persisted? && !@project.import?
- raise 'Failed to create repository' unless @project.create_repository
- end
- end
+ @project.import_start if @project.import?
after_create_actions if @project.persisted?
+ @project.add_import_job if @project.import?
+
@project
rescue => e
message = "Unable to save project: #{e.message}"
@@ -93,8 +92,16 @@ module Projects
unless @project.group
@project.team << [current_user, :master, current_user]
end
+ end
- @project.import_start if @project.import?
+ def save_project_and_import_data(import_data)
+ Project.transaction do
+ @project.create_or_update_import_data(data: import_data[:data], credentials: import_data[:credentials]) if import_data
+
+ if @project.save && !@project.import?
+ raise 'Failed to create repository' unless @project.create_repository
+ end
+ end
end
end
end
diff --git a/app/services/projects/destroy_service.rb b/app/services/projects/destroy_service.rb
index 48a6131b444..f09072975c3 100644
--- a/app/services/projects/destroy_service.rb
+++ b/app/services/projects/destroy_service.rb
@@ -26,6 +26,10 @@ module Projects
Project.transaction do
project.destroy!
+ unless remove_registry_tags
+ raise_error('Failed to remove project container registry. Please try again or contact administrator')
+ end
+
unless remove_repository(repo_path)
raise_error('Failed to remove project repository. Please try again or contact administrator')
end
@@ -59,6 +63,12 @@ module Projects
end
end
+ def remove_registry_tags
+ return true unless Gitlab.config.registry.enabled
+
+ project.container_registry_repository.delete_tags
+ end
+
def raise_error(message)
raise DestroyError.new(message)
end
diff --git a/app/services/projects/transfer_service.rb b/app/services/projects/transfer_service.rb
index 111b3ec05ea..03b57dea51e 100644
--- a/app/services/projects/transfer_service.rb
+++ b/app/services/projects/transfer_service.rb
@@ -34,6 +34,11 @@ module Projects
raise TransferError.new("Project with same path in target namespace already exists")
end
+ if project.has_container_registry_tags?
+ # we currently doesn't support renaming repository if it contains tags in container registry
+ raise TransferError.new('Project cannot be transferred, because tags are present in its container registry')
+ end
+
project.expire_caches_before_rename(old_path)
# Apply new namespace id and visibility level
diff --git a/app/services/system_note_service.rb b/app/services/system_note_service.rb
index 4bdb1b0c074..4e8fa0818b9 100644
--- a/app/services/system_note_service.rb
+++ b/app/services/system_note_service.rb
@@ -169,12 +169,33 @@ class SystemNoteService
#
# Returns the created Note object
def self.change_title(noteable, project, author, old_title)
- return unless noteable.respond_to?(:title)
+ new_title = noteable.title.dup
- body = "Title changed from **#{old_title}** to **#{noteable.title}**"
+ old_diffs, new_diffs = Gitlab::Diff::InlineDiff.new(old_title, new_title).inline_diffs
+
+ marked_old_title = Gitlab::Diff::InlineDiffMarker.new(old_title).mark(old_diffs, mode: :deletion, markdown: true)
+ marked_new_title = Gitlab::Diff::InlineDiffMarker.new(new_title).mark(new_diffs, mode: :addition, markdown: true)
+
+ body = "Changed title: **#{marked_old_title}** → **#{marked_new_title}**"
create_note(noteable: noteable, project: project, author: author, note: body)
end
+ # Called when the confidentiality changes
+ #
+ # issue - Issue object
+ # project - Project owning the issue
+ # author - User performing the change
+ #
+ # Example Note text:
+ #
+ # "Made the issue confidential"
+ #
+ # Returns the created Note object
+ def self.change_issue_confidentiality(issue, project, author)
+ body = issue.confidential ? 'Made the issue confidential' : 'Made the issue visible'
+ create_note(noteable: issue, project: project, author: author, note: body)
+ end
+
# Called when a branch in Noteable is changed
#
# noteable - Noteable object
diff --git a/app/services/todo_service.rb b/app/services/todo_service.rb
index 42c5bca90fd..4bf4e144727 100644
--- a/app/services/todo_service.rb
+++ b/app/services/todo_service.rb
@@ -80,6 +80,30 @@ class TodoService
mark_pending_todos_as_done(merge_request, current_user)
end
+ # When a build fails on the HEAD of a merge request we should:
+ #
+ # * create a todo for that user to fix it
+ #
+ def merge_request_build_failed(merge_request)
+ create_build_failed_todo(merge_request)
+ end
+
+ # When a new commit is pushed to a merge request we should:
+ #
+ # * mark all pending todos related to the merge request for that user as done
+ #
+ def merge_request_push(merge_request, current_user)
+ mark_pending_todos_as_done(merge_request, current_user)
+ end
+
+ # When a build is retried to a merge request we should:
+ #
+ # * mark all pending todos related to the merge request for the author as done
+ #
+ def merge_request_build_retried(merge_request)
+ mark_pending_todos_as_done(merge_request, merge_request.author)
+ end
+
# When create a note we should:
#
# * mark all pending todos related to the noteable for the note author as done
@@ -145,6 +169,12 @@ class TodoService
create_todos(mentioned_users, attributes)
end
+ def create_build_failed_todo(merge_request)
+ author = merge_request.author
+ attributes = attributes_for_todo(merge_request.project, merge_request, author, Todo::BUILD_FAILED)
+ create_todos(author, attributes)
+ end
+
def attributes_for_target(target)
attributes = {
project_id: target.project.id,
diff --git a/app/views/admin/runners/show.html.haml b/app/views/admin/runners/show.html.haml
index 4dfb3ed05bb..c3784bf7192 100644
--- a/app/views/admin/runners/show.html.haml
+++ b/app/views/admin/runners/show.html.haml
@@ -9,8 +9,6 @@
%span.runner-state.runner-state-specific
Specific
-
-
- if @runner.shared?
.bs-callout.bs-callout-success
%h4 This runner will process builds from ALL UNASSIGNED projects
diff --git a/app/views/dashboard/todos/_todo.html.haml b/app/views/dashboard/todos/_todo.html.haml
index aa0aff86d4d..539f1dc6036 100644
--- a/app/views/dashboard/todos/_todo.html.haml
+++ b/app/views/dashboard/todos/_todo.html.haml
@@ -1,13 +1,13 @@
%li{class: "todo todo-#{todo.done? ? 'done' : 'pending'}", id: dom_id(todo), data:{url: todo_target_path(todo)} }
.todo-item.todo-block
= image_tag avatar_icon(todo.author_email, 40), class: 'avatar s40', alt:''
-
.todo-title.title
- %span.author-name
- - if todo.author
- = link_to_author(todo)
- - else
- (removed)
+ - unless todo.build_failed?
+ %span.author-name
+ - if todo.author
+ = link_to_author(todo)
+ - else
+ (removed)
%span.todo-label
= todo_action_name(todo)
- if todo.target
diff --git a/app/views/groups/_activities.html.haml b/app/views/groups/_activities.html.haml
index dc76599b776..71cc4d87b1f 100644
--- a/app/views/groups/_activities.html.haml
+++ b/app/views/groups/_activities.html.haml
@@ -4,7 +4,7 @@
.nav-block
- if current_user
.controls
- = link_to dashboard_projects_path(:atom, { private_token: current_user.private_token }), class: 'btn rss-btn' do
+ = link_to group_path(@group, format: :atom, private_token: current_user.private_token), class: 'btn rss-btn' do
%i.fa.fa-rss
= render 'shared/event_filter'
diff --git a/app/views/groups/issues.atom.builder b/app/views/groups/issues.atom.builder
index 486d1d8587a..a6eb9abada6 100644
--- a/app/views/groups/issues.atom.builder
+++ b/app/views/groups/issues.atom.builder
@@ -1,9 +1,9 @@
xml.instruct!
xml.feed "xmlns" => "http://www.w3.org/2005/Atom", "xmlns:media" => "http://search.yahoo.com/mrss/" do
- xml.title "#{@user.name} issues"
- xml.link href: issues_dashboard_url(format: :atom, private_token: @user.private_token), rel: "self", type: "application/atom+xml"
- xml.link href: issues_dashboard_url, rel: "alternate", type: "text/html"
- xml.id issues_dashboard_url
+ xml.title "#{@group.name} issues"
+ xml.link href: issues_group_url(format: :atom, private_token: current_user.try(:private_token)), rel: "self", type: "application/atom+xml"
+ xml.link href: issues_group_url, rel: "alternate", type: "text/html"
+ xml.id issues_group_url
xml.updated @issues.first.created_at.xmlschema if @issues.any?
@issues.each do |issue|
diff --git a/app/views/layouts/nav/_project.html.haml b/app/views/layouts/nav/_project.html.haml
index 479bde33719..6dff488eda5 100644
--- a/app/views/layouts/nav/_project.html.haml
+++ b/app/views/layouts/nav/_project.html.haml
@@ -38,6 +38,14 @@
%span
Commits
+ - if project_nav_tab? :pipelines
+ = nav_link(controller: :pipelines) do
+ = link_to project_pipelines_path(@project), title: 'Pipelines', class: 'shortcuts-pipelines' do
+ = icon('ship fw')
+ %span
+ Pipelines
+ %span.count.ci_counter= number_with_delimiter(@project.ci_commits.running_or_pending.count)
+
- if project_nav_tab? :builds
= nav_link(controller: %w(builds)) do
= link_to project_builds_path(@project), title: 'Builds', class: 'shortcuts-builds' do
@@ -46,6 +54,13 @@
Builds
%span.count.builds_counter= number_with_delimiter(@project.builds.running_or_pending.count(:all))
+ - if project_nav_tab? :container_registry
+ = nav_link(controller: %w(container_registry)) do
+ = link_to project_container_registry_path(@project), title: 'Container Registry', class: 'shortcuts-container-registry' do
+ = icon('hdd-o fw')
+ %span
+ Container Registry
+
- if project_nav_tab? :graphs
= nav_link(controller: %w(graphs)) do
= link_to namespace_project_graph_path(@project.namespace, @project, current_ref), title: 'Graphs', class: 'shortcuts-graphs' do
diff --git a/app/views/layouts/notify.html.haml b/app/views/layouts/notify.html.haml
index 2997f59d946..dde2e2889dc 100644
--- a/app/views/layouts/notify.html.haml
+++ b/app/views/layouts/notify.html.haml
@@ -4,6 +4,7 @@
%title
GitLab
= stylesheet_link_tag 'notify'
+ = yield :head
%body
%div.content
= yield
diff --git a/app/views/notify/repository_push_email.html.haml b/app/views/notify/repository_push_email.html.haml
index f2e405b14fd..f1532371b2e 100644
--- a/app/views/notify/repository_push_email.html.haml
+++ b/app/views/notify/repository_push_email.html.haml
@@ -1,3 +1,6 @@
+= content_for :head do
+ = stylesheet_link_tag 'mailers/repository_push_email'
+
%h3
#{@message.author_name} #{@message.action_name} #{@message.ref_type} #{@message.ref_name}
at #{link_to(@message.project_name_with_namespace, namespace_project_url(@message.project_namespace, @message.project))}
@@ -43,26 +46,38 @@
= diff.new_path
- unless @message.disable_diffs?
- %h4 Changes:
- - @message.diffs.each_with_index do |diff, i|
- %li{id: "diff-#{i}"}
- %a{href: @message.target_url + "#diff-#{i}"}
- - if diff.deleted_file
- %strong
- = diff.old_path
- deleted
- - elsif diff.renamed_file
- %strong
- = diff.old_path
- &rarr;
- %strong
- = diff.new_path
- - else
- %strong
- = diff.new_path
- %hr
- = color_email_diff(diff.diff)
- %br
+ - diff_files = @message.diffs
- - if @message.compare_timeout
- %h5 Huge diff. To prevent performance issues changes are hidden
+ - if @message.compare_timeout
+ %h5 The diff was not included because it is too large.
+ - else
+ %h4 Changes:
+ - diff_files.each_with_index do |diff_file, i|
+ %li{id: "diff-#{i}"}
+ %a{href: @message.target_url + "#diff-#{i}"}<
+ - if diff_file.deleted_file
+ %strong<
+ = diff_file.old_path
+ deleted
+ - elsif diff_file.renamed_file
+ %strong<
+ = diff_file.old_path
+ &rarr;
+ %strong<
+ = diff_file.new_path
+ - else
+ %strong<
+ = diff_file.new_path
+ - if diff_file.too_large?
+ The diff for this file was not included because it is too large.
+ - else
+ %hr
+ - diff_commit = diff_file.deleted_file ? @message.diff_refs.first : @message.diff_refs.last
+ - blob = @message.project.repository.blob_for_diff(diff_commit, diff_file)
+ - if blob && blob.respond_to?(:text?) && blob_text_viewable?(blob)
+ %table.code.white
+ - diff_file.highlighted_diff_lines.each do |line|
+ = render "projects/diffs/line", {line: line, diff_file: diff_file, line_code: nil, plain: true}
+ - else
+ No preview for this file type
+ %br
diff --git a/app/views/notify/repository_push_email.text.haml b/app/views/notify/repository_push_email.text.haml
index 53869e36b28..5ac23aa3997 100644
--- a/app/views/notify/repository_push_email.text.haml
+++ b/app/views/notify/repository_push_email.text.haml
@@ -25,24 +25,28 @@
- else
\- #{diff.new_path}
- unless @message.disable_diffs?
- \
- \
- Changes:
- - @message.diffs.each do |diff|
+ - if @message.compare_timeout
\
- \=====================================
- - if diff.deleted_file
- #{diff.old_path} deleted
- - elsif diff.renamed_file
- #{diff.old_path} → #{diff.new_path}
- - else
- = diff.new_path
- \=====================================
- != diff.diff
- - if @message.compare_timeout
- \
- \
- Huge diff. To prevent performance issues it was hidden
+ \
+ The diff was not included because it is too large.
+ - else
+ \
+ \
+ Changes:
+ - @message.diffs.each do |diff_file|
+ \
+ \=====================================
+ - if diff_file.deleted_file
+ #{diff_file.old_path} deleted
+ - elsif diff_file.renamed_file
+ #{diff_file.old_path} → #{diff_file.new_path}
+ - else
+ = diff_file.new_path
+ \=====================================
+ - if diff_file.too_large?
+ The diff for this file was not included because it is too large.
+ - else
+ != diff_file.diff.diff
- if @message.target_url
\
\
diff --git a/app/views/projects/_md_preview.html.haml b/app/views/projects/_md_preview.html.haml
index 8de44a6c914..81afea2c60a 100644
--- a/app/views/projects/_md_preview.html.haml
+++ b/app/views/projects/_md_preview.html.haml
@@ -8,7 +8,7 @@
%a.js-md-preview-button{ href: "#md-preview-holder", tabindex: -1 }
Preview
%li.pull-right
- %button.zen-cotrol.zen-control-full.js-zen-enter{ type: 'button', tabindex: -1 }
+ %button.zen-control.zen-control-full.js-zen-enter{ type: 'button', tabindex: -1 }
Go full screen
.md-write-holder
diff --git a/app/views/projects/_zen.html.haml b/app/views/projects/_zen.html.haml
index e1e35013968..413477a2d3a 100644
--- a/app/views/projects/_zen.html.haml
+++ b/app/views/projects/_zen.html.haml
@@ -4,5 +4,5 @@
= f.text_area attr, class: classes, placeholder: placeholder
- else
= text_area_tag attr, nil, class: classes, placeholder: placeholder
- %a.zen-cotrol.zen-control-leave.js-zen-leave{ href: "#" }
+ %a.zen-control.zen-control-leave.js-zen-leave{ href: "#" }
= icon('compress')
diff --git a/app/views/projects/blob/_editor.html.haml b/app/views/projects/blob/_editor.html.haml
index fefa652a3da..4071b59c003 100644
--- a/app/views/projects/blob/_editor.html.haml
+++ b/app/views/projects/blob/_editor.html.haml
@@ -16,6 +16,9 @@
.license-selector.js-license-selector.hide
= select_tag :license_type, grouped_options_for_select(licenses_for_select, @project.repository.license_key), include_blank: true, class: 'select2 license-select', data: {placeholder: 'Choose a license template', project: @project.name, fullname: @project.namespace.human_name}
+ .gitignore-selector.hidden
+ = dropdown_tag("Choose a .gitignore template", options: { toggle_class: 'js-gitignore-selector', title: "Choose a template", filter: true, placeholder: "Filter", data: { filenames: gitignore_names } } )
+
.encoding-selector
= select_tag :encoding, options_for_select([ "base64", "text" ], "text"), class: 'select2'
diff --git a/app/views/projects/buttons/_fork.html.haml b/app/views/projects/buttons/_fork.html.haml
index 5fb5fe5af2f..34ad9fe2c43 100644
--- a/app/views/projects/buttons/_fork.html.haml
+++ b/app/views/projects/buttons/_fork.html.haml
@@ -12,7 +12,8 @@
= link_to new_namespace_project_fork_path(@project.namespace, @project), title: "Fork project", class: 'btn has-tooltip' do
= icon('code-fork fw')
Fork
- = link_to namespace_project_forks_path(@project.namespace, @project), class: 'count-with-arrow' do
+ %div.count-with-arrow
%span.arrow
%span.count
- = @project.forks_count
+ = link_to namespace_project_forks_path(@project.namespace, @project) do
+ = @project.forks_count
diff --git a/app/views/projects/ci/builds/_build.html.haml b/app/views/projects/ci/builds/_build.html.haml
index 8e95f040273..962b9fb2595 100644
--- a/app/views/projects/ci/builds/_build.html.haml
+++ b/app/views/projects/ci/builds/_build.html.haml
@@ -13,7 +13,9 @@
%strong ##{build.id}
- if build.stuck?
- %i.fa.fa-warning.text-warning
+ = icon('warning', class: 'text-warning has-tooltip', title: 'Build is stuck. Check runners.')
+ - if defined?(retried) && retried
+ = icon('warning', class: 'text-warning has-tooltip', title: 'Build was retried.')
- if defined?(commit_sha) && commit_sha
%td
@@ -40,25 +42,29 @@
%td
= build.name
- %td
- .label-container
- - if build.tags.any?
- - build.tags.each do |tag|
- %span.label.label-primary
- = tag
- - if build.try(:trigger_request)
- %span.label.label-info triggered
- - if build.try(:allow_failure)
- %span.label.label-danger allowed to fail
- - if defined?(retried) && retried
- %span.label.label-warning retried
+ .pull-right
+ .label-container
+ - if build.tags.any?
+ - build.tags.each do |tag|
+ %span.label.label-primary
+ = tag
+ - if build.try(:trigger_request)
+ %span.label.label-info triggered
+ - if build.try(:allow_failure)
+ %span.label.label-danger allowed to fail
+ - if defined?(retried) && retried
+ %span.label.label-warning retried
%td.duration
- if build.duration
+ = icon("clock-o")
+ &nbsp;
#{duration_in_words(build.finished_at, build.started_at)}
%td.timestamp
- if build.finished_at
+ = icon("calendar")
+ &nbsp;
%span #{time_ago_with_tooltip(build.finished_at)}
- if defined?(coverage) && coverage
@@ -70,11 +76,11 @@
.pull-right
- if can?(current_user, :read_build, build) && build.artifacts?
= link_to download_namespace_project_build_artifacts_path(build.project.namespace, build.project, build), title: 'Download artifacts', class: 'btn btn-build' do
- %i.fa.fa-download
+ = icon('download')
- if can?(current_user, :update_build, build)
- if build.active?
= link_to cancel_namespace_project_build_path(build.project.namespace, build.project, build, return_to: request.original_url), method: :post, title: 'Cancel', class: 'btn btn-build' do
- %i.fa.fa-remove.cred
+ = icon('remove', class: 'cred')
- elsif defined?(allow_retry) && allow_retry && build.retryable?
= link_to retry_namespace_project_build_path(build.project.namespace, build.project, build, return_to: request.original_url), method: :post, title: 'Retry', class: 'btn btn-build' do
- %i.fa.fa-refresh
+ = icon('refresh')
diff --git a/app/views/projects/ci/commits/_commit.html.haml b/app/views/projects/ci/commits/_commit.html.haml
new file mode 100644
index 00000000000..13162b41f9b
--- /dev/null
+++ b/app/views/projects/ci/commits/_commit.html.haml
@@ -0,0 +1,77 @@
+- status = commit.status
+%tr.commit
+ %td.commit-link
+ = link_to namespace_project_pipeline_path(@project.namespace, @project, commit.id), class: "ci-status ci-#{status}" do
+ = ci_icon_for_status(status)
+ %strong ##{commit.id}
+
+ %td
+ %div.branch-commit
+ - if commit.ref
+ = link_to commit.ref, namespace_project_commits_path(@project.namespace, @project, commit.ref), class: "monospace"
+ &middot;
+ = link_to commit.short_sha, namespace_project_commit_path(@project.namespace, @project, commit.sha), class: "commit-id monospace"
+ &nbsp;
+ - if commit.latest?
+ %span.label.label-success latest
+ - if commit.tag?
+ %span.label.label-primary tag
+ - if commit.triggered?
+ %span.label.label-primary triggered
+ - if commit.yaml_errors.present?
+ %span.label.label-danger.has-tooltip{ title: "#{commit.yaml_errors}" } yaml invalid
+ - if commit.builds.any?(&:stuck?)
+ %span.label.label-warning stuck
+
+ %p
+ %span
+ - if commit_data = commit.commit_data
+ = link_to_gfm commit_data.title, namespace_project_commit_path(@project.namespace, @project, commit_data.id), class: "commit-row-message"
+ - else
+ Cant find HEAD commit for this branch
+
+
+ - stages_status = commit.statuses.stages_status
+ - stages.each do |stage|
+ %td
+ - if status = stages_status[stage]
+ - tooltip = "#{stage.titleize}: #{status}"
+ %span.has-tooltip{ title: "#{tooltip}", class: "ci-status-icon-#{status}" }
+ = ci_icon_for_status(status)
+
+ %td
+ - if commit.started_at && commit.finished_at
+ %p
+ = icon("clock-o")
+ &nbsp;
+ #{duration_in_words(commit.finished_at, commit.started_at)}
+ - if commit.finished_at
+ %p
+ = icon("calendar")
+ &nbsp;
+ #{time_ago_with_tooltip(commit.finished_at)}
+
+ %td
+ .controls.hidden-xs.pull-right
+ - artifacts = commit.builds.latest.select { |b| b.artifacts? }
+ - if artifacts.present?
+ .dropdown.inline.build-artifacts
+ %button.dropdown-toggle.btn{type: 'button', 'data-toggle' => 'dropdown'}
+ = icon('download')
+ %b.caret
+ %ul.dropdown-menu.dropdown-menu-align-right
+ - artifacts.each do |build|
+ %li
+ = link_to download_namespace_project_build_artifacts_path(@project.namespace, @project, build), rel: 'nofollow' do
+ = icon("download")
+ %span #{build.name}
+
+ - if can?(current_user, :update_pipeline, @project)
+ &nbsp;
+ - if commit.retryable? && commit.builds.failed.any?
+ = link_to retry_namespace_project_pipeline_path(@project.namespace, @project, commit.id), class: 'btn has-tooltip', title: "Retry", method: :post do
+ = icon("repeat")
+ &nbsp;
+ - if commit.active?
+ = link_to cancel_namespace_project_pipeline_path(@project.namespace, @project, commit.id), class: 'btn btn-remove has-tooltip', title: "Cancel", method: :post do
+ = icon("remove")
diff --git a/app/views/projects/commit/_builds.html.haml b/app/views/projects/commit/_builds.html.haml
index 5c9a319edeb..7f7a15aa214 100644
--- a/app/views/projects/commit/_builds.html.haml
+++ b/app/views/projects/commit/_builds.html.haml
@@ -1,2 +1,2 @@
- @ci_commits.each do |ci_commit|
- = render "ci_commit", ci_commit: ci_commit
+ = render "ci_commit", ci_commit: ci_commit, pipeline_details: true
diff --git a/app/views/projects/commit/_ci_commit.html.haml b/app/views/projects/commit/_ci_commit.html.haml
index e849aefb188..8228c067be0 100644
--- a/app/views/projects/commit/_ci_commit.html.haml
+++ b/app/views/projects/commit/_ci_commit.html.haml
@@ -1,24 +1,27 @@
.row-content-block.build-content.middle-block
.pull-right
- - if can?(current_user, :update_build, @project)
+ - if can?(current_user, :update_pipeline, @project)
- if ci_commit.builds.latest.failed.any?(&:retryable?)
- = link_to "Retry failed", retry_builds_namespace_project_commit_path(@project.namespace, @project, ci_commit.sha), class: 'btn btn-grouped btn-primary', method: :post
+ = link_to "Retry failed", retry_namespace_project_pipeline_path(@project.namespace, @project, ci_commit.id), class: 'btn btn-grouped btn-primary', method: :post
- if ci_commit.builds.running_or_pending.any?
- = link_to "Cancel running", cancel_builds_namespace_project_commit_path(@project.namespace, @project, ci_commit.sha), data: { confirm: 'Are you sure?' }, class: 'btn btn-grouped btn-danger', method: :post
+ = link_to "Cancel running", cancel_namespace_project_pipeline_path(@project.namespace, @project, ci_commit.id), data: { confirm: 'Are you sure?' }, class: 'btn btn-grouped btn-danger', method: :post
- .oneline
- = pluralize ci_commit.statuses.count(:id), "build"
- - if ci_commit.ref
- for
- %span.label.label-info
- = ci_commit.ref
- - if defined?(link_to_commit) && link_to_commit
- for commit
- = link_to ci_commit.short_sha, namespace_project_commit_path(@project.namespace, @project, ci_commit.sha), class: "monospace"
- - if ci_commit.duration
- in
- = time_interval_in_words ci_commit.duration
+ .oneline.clearfix
+ - if defined?(pipeline_details) && pipeline_details
+ Pipeline
+ = link_to "##{ci_commit.id}", namespace_project_pipeline_path(@project.namespace, @project, ci_commit.id), class: "monospace"
+ with
+ = pluralize ci_commit.statuses.count(:id), "build"
+ - if ci_commit.ref
+ for
+ = link_to ci_commit.ref, namespace_project_commits_path(@project.namespace, @project, ci_commit.ref), class: "monospace"
+ - if defined?(link_to_commit) && link_to_commit
+ for commit
+ = link_to ci_commit.short_sha, namespace_project_commit_path(@project.namespace, @project, ci_commit.sha), class: "monospace"
+ - if ci_commit.duration
+ in
+ = time_interval_in_words ci_commit.duration
- if ci_commit.yaml_errors.present?
.bs-callout.bs-callout-danger
@@ -34,38 +37,5 @@
.table-holder
%table.table.builds
- %thead
- %tr
- %th Status
- %th Build ID
- %th Stage
- %th Name
- %th Tags
- %th Duration
- %th Finished at
- - if @project.build_coverage_enabled?
- %th Coverage
- %th
- - builds = ci_commit.statuses.latest.ordered
- = render builds, coverage: @project.build_coverage_enabled?, stage: true, ref: false, allow_retry: true
-
-- if ci_commit.retried.any?
- .row-content-block.second-block
- Retried builds
-
- .table-holder
- %table.table.builds
- %thead
- %tr
- %th Status
- %th Build ID
- %th Ref
- %th Stage
- %th Name
- %th Tags
- %th Duration
- %th Finished at
- - if @project.build_coverage_enabled?
- %th Coverage
- %th
- = render ci_commit.retried, coverage: @project.build_coverage_enabled?, stage: true, ref: false
+ - ci_commit.statuses.stages.each do |stage|
+ = render 'projects/commit/ci_stage', stage: stage, statuses: ci_commit.statuses.where(stage: stage)
diff --git a/app/views/projects/commit/_ci_stage.html.haml b/app/views/projects/commit/_ci_stage.html.haml
new file mode 100644
index 00000000000..aaa318e1eb3
--- /dev/null
+++ b/app/views/projects/commit/_ci_stage.html.haml
@@ -0,0 +1,14 @@
+%tr
+ %th{colspan: 10}
+ %strong
+ - status = statuses.latest.status
+ %span{class: "ci-status-link ci-status-icon-#{status}"}
+ = ci_icon_for_status(status)
+ - if stage
+ &nbsp;
+ = stage.titleize.pluralize
+ = render statuses.latest.ordered, coverage: @project.build_coverage_enabled?, stage: false, ref: false, allow_retry: true
+ = render statuses.retried.ordered, coverage: @project.build_coverage_enabled?, stage: false, ref: false, retried: true
+ %tr
+ %td{colspan: 10}
+ &nbsp;
diff --git a/app/views/projects/commit/_commit_box.html.haml b/app/views/projects/commit/_commit_box.html.haml
index 01163e526b2..028564c9305 100644
--- a/app/views/projects/commit/_commit_box.html.haml
+++ b/app/views/projects/commit/_commit_box.html.haml
@@ -1,6 +1,6 @@
.pull-right.commit-action-buttons
%div
- - if @notes_count > 0
+ - if defined?(@notes_count) && @notes_count > 0
%span.btn.disabled.btn-grouped
%i.fa.fa-comment
= @notes_count
@@ -23,11 +23,6 @@
%p
.commit-info-row
- - if @commit.status
- = link_to builds_namespace_project_commit_path(@project.namespace, @project, @commit.id), class: "ci-status ci-#{@commit.status}" do
- = ci_icon_for_status(@commit.status)
- build:
- = ci_label_for_status(@commit.status)
%span.light Authored by
%strong
= commit_author_link(@commit, avatar: true, size: 24)
@@ -51,6 +46,17 @@
%span.commit-info.branches
%i.fa.fa-spinner.fa-spin
+- if @commit.status
+ .commit-info-row
+ Builds for
+ = pluralize(@commit.ci_commits.count, 'pipeline')
+ = link_to builds_namespace_project_commit_path(@project.namespace, @project, @commit.id), class: "ci-status-link ci-status-icon-#{@commit.status}" do
+ = ci_icon_for_status(@commit.status)
+ = ci_label_for_status(@commit.status)
+ - if @commit.ci_commits.duration
+ in
+ = time_interval_in_words @commit.ci_commits.duration
+
.commit-box.content-block
%h3.commit-title
= markdown escape_once(@commit.title), pipeline: :single_line
diff --git a/app/views/projects/commits/_commit.html.haml b/app/views/projects/commits/_commit.html.haml
index c7d8c9a0d15..655cb0ac3cb 100644
--- a/app/views/projects/commits/_commit.html.haml
+++ b/app/views/projects/commits/_commit.html.haml
@@ -17,7 +17,7 @@
.pull-right
- if commit.status
- = render_ci_status(commit)
+ = render_commit_status(commit)
= clipboard_button(clipboard_text: commit.id)
= link_to commit.short_id, namespace_project_commit_path(project.namespace, project, commit), class: "commit_short_id"
diff --git a/app/views/projects/commits/_commits.html.haml b/app/views/projects/commits/_commits.html.haml
index 82f39e59284..7283a78a64e 100644
--- a/app/views/projects/commits/_commits.html.haml
+++ b/app/views/projects/commits/_commits.html.haml
@@ -3,7 +3,7 @@
- commits, hidden = limited_commits(@commits)
-- commits.group_by { |c| c.committed_date.in_time_zone.to_date }.sort.reverse.each do |day, commits|
+- commits.chunk { |c| c.committed_date.in_time_zone.to_date }.each do |day, commits|
.row.commits-row
.col-md-2.hidden-xs.hidden-sm
%h5.commits-row-date
diff --git a/app/views/projects/container_registry/_header_title.html.haml b/app/views/projects/container_registry/_header_title.html.haml
new file mode 100644
index 00000000000..f1863c52a3e
--- /dev/null
+++ b/app/views/projects/container_registry/_header_title.html.haml
@@ -0,0 +1 @@
+- header_title project_title(@project, "Container Registry", project_container_registry_path(@project))
diff --git a/app/views/projects/container_registry/_tag.html.haml b/app/views/projects/container_registry/_tag.html.haml
new file mode 100644
index 00000000000..4e9f936539b
--- /dev/null
+++ b/app/views/projects/container_registry/_tag.html.haml
@@ -0,0 +1,21 @@
+%tr.tag
+ %td
+ = escape_once(tag.name)
+ = clipboard_button(clipboard_text: "docker pull #{tag.path}")
+ %td
+ - if layer = tag.layers.first
+ %span.has-tooltip{ title: "#{layer.revision}" }
+ = layer.short_revision
+ - else
+ \-
+ %td
+ = number_to_human_size(tag.total_size)
+ &middot;
+ = pluralize(tag.layers.size, "layer")
+ %td
+ = time_ago_in_words(tag.created_at)
+ - if can?(current_user, :update_container_image, @project)
+ %td.content
+ .controls.hidden-xs.pull-right
+ = link_to namespace_project_container_registry_path(@project.namespace, @project, tag.name), class: 'btn btn-remove has-tooltip', title: "Remove", data: { confirm: "Are you sure?" }, method: :delete do
+ = icon("trash cred")
diff --git a/app/views/projects/container_registry/index.html.haml b/app/views/projects/container_registry/index.html.haml
new file mode 100644
index 00000000000..e1e762410f2
--- /dev/null
+++ b/app/views/projects/container_registry/index.html.haml
@@ -0,0 +1,40 @@
+- page_title "Container Registry"
+= render "header_title"
+
+%hr
+
+%ul.content-list
+ %li.light.prepend-top-default
+ %p
+ A 'container image' is a snapshot of a container.
+ You can host your container images with GitLab.
+ %br
+ To start using container images hosted on GitLab you first need to login:
+ %pre
+ %code
+ docker login #{Gitlab.config.registry.host_port}
+ %br
+ Then you are free to create and upload a container image with build and push commands:
+ %pre
+ docker build -t #{escape_once(@project.container_registry_repository_url)} .
+ %br
+ docker push #{escape_once(@project.container_registry_repository_url)}
+
+ - if @tags.blank?
+ %li
+ .nothing-here-block No images in Container Registry for this project.
+
+ - else
+ .table-holder
+ %table.table.tags
+ %thead
+ %tr
+ %th Name
+ %th Image ID
+ %th Size
+ %th Created
+ - if can?(current_user, :update_container_image, @project)
+ %th
+
+ - @tags.each do |tag|
+ = render 'tag', tag: tag \ No newline at end of file
diff --git a/app/views/projects/deploy_keys/index.html.haml b/app/views/projects/deploy_keys/index.html.haml
index e230834e8ba..04fbb37d93f 100644
--- a/app/views/projects/deploy_keys/index.html.haml
+++ b/app/views/projects/deploy_keys/index.html.haml
@@ -19,7 +19,7 @@
%ul.well-list
= render @enabled_keys
- else
- .profile-settings-message.text-center
+ .settings-message.text-center
No deploy keys found. Create one with the form above or add existing one below.
%h5.prepend-top-default
Deploy keys from projects you have access to (#{@available_project_keys.size})
@@ -27,7 +27,7 @@
%ul.well-list
= render @available_project_keys
- else
- .profile-settings-message.text-center
+ .settings-message.text-center
No deploy keys from your projects could be found. Create one with the form above or add existing one below.
- if @available_public_keys.any?
%h5.prepend-top-default
diff --git a/app/views/projects/diffs/_file.html.haml b/app/views/projects/diffs/_file.html.haml
index 0f04fc5d33c..e5983c58039 100644
--- a/app/views/projects/diffs/_file.html.haml
+++ b/app/views/projects/diffs/_file.html.haml
@@ -11,11 +11,9 @@
= link_to "#diff-#{i}" do
- if diff_file.renamed_file
- old_path, new_path = mark_inline_diffs(diff_file.old_path, diff_file.new_path)
- .filename.old
- = old_path
+ = old_path
&rarr;
- .filename.new
- = new_path
+ = new_path
- else
%span
= diff_file.new_path
@@ -41,7 +39,7 @@
.diff-content.diff-wrap-lines
- # Skip all non non-supported blobs
- - return unless blob.respond_to?('text?')
+ - return unless blob.respond_to?(:text?)
- if diff_file.too_large?
.nothing-here-block This diff could not be displayed because it is too large.
- elsif blob_text_viewable?(blob) && !project.repository.diffable?(blob)
diff --git a/app/views/projects/empty.html.haml b/app/views/projects/empty.html.haml
index 1a2e59752fe..636beb73ec2 100644
--- a/app/views/projects/empty.html.haml
+++ b/app/views/projects/empty.html.haml
@@ -15,10 +15,14 @@
If you already have files you can push them using command line instructions below.
%p
Otherwise you can start with adding a
- = link_to "README", new_readme_path, class: 'underlined-link'
+ = succeed ',' do
+ = link_to "README", new_readme_path, class: 'underlined-link'
+ a
+ = succeed ',' do
+ = link_to "LICENSE", add_special_file_path(@project, file_name: 'LICENSE'), class: 'underlined-link'
or a
- = link_to "LICENSE", add_special_file_path(@project, file_name: 'LICENSE'), class: 'underlined-link'
- file to this project.
+ = link_to '.gitignore', add_special_file_path(@project, file_name: '.gitignore'), class: 'underlined-link'
+ to this project.
- if can?(current_user, :push_code, @project)
%div{ class: container_class }
diff --git a/app/views/projects/generic_commit_statuses/_generic_commit_status.html.haml b/app/views/projects/generic_commit_statuses/_generic_commit_status.html.haml
index f21c864e35c..8129514964a 100644
--- a/app/views/projects/generic_commit_statuses/_generic_commit_status.html.haml
+++ b/app/views/projects/generic_commit_statuses/_generic_commit_status.html.haml
@@ -12,6 +12,9 @@
- else
%strong ##{generic_commit_status.id}
+ - if defined?(retried) && retried
+ = icon('warning', class: 'text-warning has-tooltip', title: 'Status was retried.')
+
- if defined?(commit_sha) && commit_sha
%td
= link_to generic_commit_status.short_sha, namespace_project_commit_path(generic_commit_status.project.namespace, generic_commit_status.project, generic_commit_status.sha), class: "monospace"
@@ -42,13 +45,19 @@
- generic_commit_status.tags.each do |tag|
%span.label.label-primary
= tag
+ - if defined?(retried) && retried
+ %span.label.label-warning retried
%td.duration
- if generic_commit_status.duration
+ = icon("clock-o")
+ &nbsp;
#{duration_in_words(generic_commit_status.finished_at, generic_commit_status.started_at)}
%td.timestamp
- if generic_commit_status.finished_at
+ = icon("calendar")
+ &nbsp;
%span #{time_ago_with_tooltip(generic_commit_status.finished_at)}
- if defined?(coverage) && coverage
diff --git a/app/views/projects/hooks/index.html.haml b/app/views/projects/hooks/index.html.haml
index 36c1d69f060..cffe9a01a96 100644
--- a/app/views/projects/hooks/index.html.haml
+++ b/app/views/projects/hooks/index.html.haml
@@ -80,5 +80,5 @@
- @hooks.each do |hook|
= render "project_hook", hook: hook
- else
- %p.profile-settings-message.text-center.append-bottom-0
+ %p.settings-message.text-center.append-bottom-0
No webhooks found, add one in the form above.
diff --git a/app/views/projects/issues/_merge_requests.html.haml b/app/views/projects/issues/_merge_requests.html.haml
index d6b38b327ff..e953353567e 100644
--- a/app/views/projects/issues/_merge_requests.html.haml
+++ b/app/views/projects/issues/_merge_requests.html.haml
@@ -7,7 +7,7 @@
%li
%span.merge-request-ci-status
- if merge_request.ci_commit
- = render_ci_status(merge_request.ci_commit)
+ = render_pipeline_status(merge_request.ci_commit)
- elsif has_any_ci
= icon('blank fw')
%span.merge-request-id
diff --git a/app/views/projects/issues/_related_branches.html.haml b/app/views/projects/issues/_related_branches.html.haml
index bdfa0c7009e..5f9d2919982 100644
--- a/app/views/projects/issues/_related_branches.html.haml
+++ b/app/views/projects/issues/_related_branches.html.haml
@@ -8,7 +8,7 @@
- ci_commit = @project.ci_commit(sha, branch) if sha
- if ci_commit
%span.related-branch-ci-status
- = render_ci_status(ci_commit)
+ = render_pipeline_status(ci_commit)
%span.related-branch-info
%strong
= link_to namespace_project_compare_path(@project.namespace, @project, from: @project.default_branch, to: branch), class: "label-branch" do
diff --git a/app/views/projects/merge_requests/_merge_request.html.haml b/app/views/projects/merge_requests/_merge_request.html.haml
index 73c6a95f5ca..2c54171c6bd 100644
--- a/app/views/projects/merge_requests/_merge_request.html.haml
+++ b/app/views/projects/merge_requests/_merge_request.html.haml
@@ -13,7 +13,7 @@
- if merge_request.ci_commit
%li
- = render_ci_status(merge_request.ci_commit)
+ = render_pipeline_status(merge_request.ci_commit)
- if merge_request.open? && merge_request.broken?
%li
diff --git a/app/views/projects/merge_requests/widget/open/_accept.html.haml b/app/views/projects/merge_requests/widget/open/_accept.html.haml
index 807833741af..cfdf4edac37 100644
--- a/app/views/projects/merge_requests/widget/open/_accept.html.haml
+++ b/app/views/projects/merge_requests/widget/open/_accept.html.haml
@@ -25,7 +25,10 @@
- else
= f.button class: "btn btn-create btn-grouped js-merge-button accept_merge_request #{status_class}" do
Accept Merge Request
- - if @merge_request.can_remove_source_branch?(current_user)
+ - if @merge_request.force_remove_source_branch?
+ .accept-control
+ The source branch will be removed.
+ - elsif @merge_request.can_remove_source_branch?(current_user)
.accept-control.checkbox
= label_tag :should_remove_source_branch, class: "remove_source_checkbox" do
= check_box_tag :should_remove_source_branch
diff --git a/app/views/projects/merge_requests/widget/open/_merge_when_build_succeeds.html.haml b/app/views/projects/merge_requests/widget/open/_merge_when_build_succeeds.html.haml
index 2168294c683..b83ddcab3a4 100644
--- a/app/views/projects/merge_requests/widget/open/_merge_when_build_succeeds.html.haml
+++ b/app/views/projects/merge_requests/widget/open/_merge_when_build_succeeds.html.haml
@@ -2,17 +2,16 @@
Set by #{link_to_member(@project, @merge_request.merge_user, avatar: true)}
to be merged automatically when the build succeeds.
%div
- - should_remove_source_branch = @merge_request.merge_params["should_remove_source_branch"].present?
%p
= succeed '.' do
The changes will be merged into
%span.label-branch= @merge_request.target_branch
- - if should_remove_source_branch
+ - if @merge_request.remove_source_branch?
The source branch will be removed.
- else
The source branch will not be removed.
- - remove_source_branch_button = @merge_request.can_remove_source_branch?(current_user) && !should_remove_source_branch && @merge_request.merge_user == current_user
+ - remove_source_branch_button = !@merge_request.remove_source_branch? && @merge_request.can_remove_source_branch?(current_user) && @merge_request.merge_user == current_user
- user_can_cancel_automatic_merge = @merge_request.can_cancel_merge_when_build_succeeds?(current_user)
- if remove_source_branch_button || user_can_cancel_automatic_merge
.clearfix.prepend-top-10
diff --git a/app/views/projects/merge_requests/widget/open/_not_allowed.html.haml b/app/views/projects/merge_requests/widget/open/_not_allowed.html.haml
index a8145558ca8..57ce1959021 100644
--- a/app/views/projects/merge_requests/widget/open/_not_allowed.html.haml
+++ b/app/views/projects/merge_requests/widget/open/_not_allowed.html.haml
@@ -1,4 +1,6 @@
-%h4
+%h4
Ready to be merged automatically
%p
Ask someone with write access to this repository to merge this request.
+ - if @merge_request.force_remove_source_branch?
+ The source branch will be removed.
diff --git a/app/views/projects/pipelines/_header_title.html.haml b/app/views/projects/pipelines/_header_title.html.haml
new file mode 100644
index 00000000000..faf63d64a79
--- /dev/null
+++ b/app/views/projects/pipelines/_header_title.html.haml
@@ -0,0 +1 @@
+- header_title project_title(@project, "Pipelines", project_pipelines_path(@project))
diff --git a/app/views/projects/pipelines/_info.html.haml b/app/views/projects/pipelines/_info.html.haml
new file mode 100644
index 00000000000..8289aefcde7
--- /dev/null
+++ b/app/views/projects/pipelines/_info.html.haml
@@ -0,0 +1,37 @@
+%p
+.commit-info-row
+ Pipeline
+ = link_to "##{@pipeline.id}", namespace_project_pipeline_path(@project.namespace, @project, @pipeline.id), class: "monospace"
+ with
+ = pluralize @pipeline.statuses.count(:id), "build"
+ - if @pipeline.ref
+ for
+ = link_to @pipeline.ref, namespace_project_commits_path(@project.namespace, @project, @pipeline.ref), class: "monospace"
+ - if @pipeline.duration
+ in
+ = time_interval_in_words @pipeline.duration
+
+ .pull-right
+ = link_to namespace_project_pipeline_path(@project.namespace, @project, @pipeline), class: "ci-status ci-#{@pipeline.status}" do
+ = ci_icon_for_status(@pipeline.status)
+ = ci_label_for_status(@pipeline.status)
+
+- if @commit
+ .commit-info-row
+ %span.light Authored by
+ %strong
+ = commit_author_link(@commit, avatar: true, size: 24)
+ #{time_ago_with_tooltip(@commit.authored_date)}
+
+.commit-info-row
+ %span.light Commit
+ = link_to @pipeline.sha, namespace_project_commit_path(@project.namespace, @project, @pipeline.sha), class: "monospace"
+ = clipboard_button(clipboard_text: @pipeline.sha)
+
+- if @commit
+ .commit-box.content-block
+ %h3.commit-title
+ = markdown escape_once(@commit.title), pipeline: :single_line
+ - if @commit.description.present?
+ %pre.commit-description
+ = preserve(markdown(escape_once(@commit.description), pipeline: :single_line))
diff --git a/app/views/projects/pipelines/index.html.haml b/app/views/projects/pipelines/index.html.haml
new file mode 100644
index 00000000000..9d5b6d367c9
--- /dev/null
+++ b/app/views/projects/pipelines/index.html.haml
@@ -0,0 +1,66 @@
+- page_title "Pipelines"
+= render "header_title"
+
+.top-area
+ %ul.nav-links
+ %li{class: ('active' if @scope.nil?)}
+ = link_to project_pipelines_path(@project) do
+ All
+ %span.badge.js-totalbuilds-count
+ = number_with_delimiter(@pipelines_count)
+
+ %li{class: ('active' if @scope == 'running')}
+ = link_to project_pipelines_path(@project, scope: :running) do
+ Running
+ %span.badge.js-running-count
+ = number_with_delimiter(@running_or_pending_count)
+
+ %li{class: ('active' if @scope == 'branches')}
+ = link_to project_pipelines_path(@project, scope: :branches) do
+ Branches
+
+ %li{class: ('active' if @scope == 'tags')}
+ = link_to project_pipelines_path(@project, scope: :tags) do
+ Tags
+
+ .nav-controls
+ - if can? current_user, :create_pipeline, @project
+ = link_to new_namespace_project_pipeline_path(@project.namespace, @project), class: 'btn btn-create' do
+ = icon('plus')
+ New pipeline
+
+ - unless @repository.gitlab_ci_yml
+ = link_to 'Get started with Pipelines', help_page_path('ci/quick_start', 'README'), class: 'btn btn-info'
+
+ = link_to ci_lint_path, class: 'btn btn-default' do
+ = icon('wrench')
+ %span CI Lint
+
+.row-content-block
+ - if @scope == 'running'
+ Running pipelines for this project
+ - elsif @scope.nil?
+ Pipelines for this project
+ - else
+ #{@scope.titleize} for this project
+
+%ul.content-list
+ - stages = @pipelines.stages
+ - if @pipelines.blank?
+ %li
+ .nothing-here-block No pipelines to show
+ - else
+ .table-holder
+ %table.table.builds
+ %tbody
+ %th ID
+ %th Commit
+ - stages.each do |stage|
+ %th
+ %span.pipeline-stage.has-tooltip{ title: "#{stage.titleize}" }
+ = stage.titleize.pluralize
+ %th
+ %th
+ = render @pipelines, commit_sha: true, stage: true, allow_retry: true, stages: stages
+
+ = paginate @pipelines, theme: 'gitlab'
diff --git a/app/views/projects/pipelines/new.html.haml b/app/views/projects/pipelines/new.html.haml
new file mode 100644
index 00000000000..b97c9f5f3b6
--- /dev/null
+++ b/app/views/projects/pipelines/new.html.haml
@@ -0,0 +1,22 @@
+- page_title "New Pipeline"
+= render "header_title"
+
+%h3.page-title
+ New Pipeline
+%hr
+
+= form_for @pipeline, as: :pipeline, url: namespace_project_pipelines_path(@project.namespace, @project), html: { id: "new-pipeline-form", class: "form-horizontal js-new-pipeline-form js-requires-input" } do |f|
+ = form_errors(@pipeline)
+ .form-group
+ = f.label :ref, 'Create for', class: 'control-label'
+ .col-sm-10
+ = f.text_field :ref, required: true, tabindex: 2, class: 'form-control'
+ .help-block Existing branch name, tag
+ .form-actions
+ = f.submit 'Create pipeline', class: 'btn btn-create', tabindex: 3
+ = link_to 'Cancel', namespace_project_pipelines_path(@project.namespace, @project), class: 'btn btn-cancel'
+
+:javascript
+ var availableRefs = #{@project.repository.ref_names.to_json};
+
+ new NewBranchForm($('.js-new-pipeline-form'), availableRefs)
diff --git a/app/views/projects/pipelines/show.html.haml b/app/views/projects/pipelines/show.html.haml
new file mode 100644
index 00000000000..b082d4d5da8
--- /dev/null
+++ b/app/views/projects/pipelines/show.html.haml
@@ -0,0 +1,9 @@
+- page_title "Pipeline"
+
+= render "header_title"
+.prepend-top-default
+ - if @commit
+ = render "projects/pipelines/info"
+ %div.block-connector
+
+= render "projects/commit/ci_commit", ci_commit: @pipeline
diff --git a/app/views/projects/protected_branches/_branches_list.html.haml b/app/views/projects/protected_branches/_branches_list.html.haml
index b9e9dd8aaea..565905cbe7b 100644
--- a/app/views/projects/protected_branches/_branches_list.html.haml
+++ b/app/views/projects/protected_branches/_branches_list.html.haml
@@ -1,7 +1,7 @@
%h5.prepend-top-0
Already Protected (#{@branches.size})
- if @branches.empty?
- %p.profile-settings-message.text-center
+ %p.settings-message.text-center
No branches are protected, protect a branch with the form above.
- else
- can_admin_project = can?(current_user, :admin_project, @project)
diff --git a/app/views/projects/runners/_form.html.haml b/app/views/projects/runners/_form.html.haml
index 2d6c964ae94..d62f5c8f131 100644
--- a/app/views/projects/runners/_form.html.haml
+++ b/app/views/projects/runners/_form.html.haml
@@ -1,4 +1,5 @@
= form_for runner, url: runner_form_url, html: { class: 'form-horizontal' } do |f|
+ = form_errors(runner)
.form-group
= label :active, "Active", class: 'control-label'
.col-sm-10
@@ -6,6 +7,12 @@
= f.check_box :active
%span.light Paused runners don't accept new builds
.form-group
+ = label :run_untagged, 'Run untagged jobs', class: 'control-label'
+ .col-sm-10
+ .checkbox
+ = f.check_box :run_untagged
+ %span.light Indicates whether this runner can pick jobs without tags
+ .form-group
= label_tag :token, class: 'control-label' do
Token
.col-sm-10
diff --git a/app/views/projects/runners/_runner.html.haml b/app/views/projects/runners/_runner.html.haml
index 47ec420189d..96e2aac451f 100644
--- a/app/views/projects/runners/_runner.html.haml
+++ b/app/views/projects/runners/_runner.html.haml
@@ -5,7 +5,7 @@
- if @runners.include?(runner)
= link_to runner.short_sha, runner_path(runner)
%small
- =link_to edit_namespace_project_runner_path(@project.namespace, @project, runner) do
+ = link_to edit_namespace_project_runner_path(@project.namespace, @project, runner) do
%i.fa.fa-edit.btn
- else
= runner.short_sha
diff --git a/app/views/projects/runners/edit.html.haml b/app/views/projects/runners/edit.html.haml
index 771947d7908..95706888655 100644
--- a/app/views/projects/runners/edit.html.haml
+++ b/app/views/projects/runners/edit.html.haml
@@ -1,5 +1,6 @@
- page_title "Edit", "#{@runner.description} ##{@runner.id}", "Runners"
%h4 Runner ##{@runner.id}
+
%hr
= render 'form', runner: @runner, runner_form_url: runner_path(@runner)
diff --git a/app/views/projects/runners/show.html.haml b/app/views/projects/runners/show.html.haml
index 5bf4c09ca25..f24e1b9144e 100644
--- a/app/views/projects/runners/show.html.haml
+++ b/app/views/projects/runners/show.html.haml
@@ -17,50 +17,39 @@
%th Property Name
%th Value
%tr
- %td
- Tags
+ %td Active
+ %td= @runner.active? ? 'Yes' : 'No'
+ %tr
+ %td Can run untagged jobs
+ %td= @runner.run_untagged? ? 'Yes' : 'No'
+ %tr
+ %td Tags
%td
- @runner.tag_list.each do |tag|
%span.label.label-primary
= tag
%tr
- %td
- Name
- %td
- = @runner.name
+ %td Name
+ %td= @runner.name
%tr
- %td
- Version
- %td
- = @runner.version
+ %td Version
+ %td= @runner.version
%tr
- %td
- Revision
- %td
- = @runner.revision
+ %td Revision
+ %td= @runner.revision
%tr
- %td
- Platform
- %td
- = @runner.platform
+ %td Platform
+ %td= @runner.platform
%tr
- %td
- Architecture
- %td
- = @runner.architecture
+ %td Architecture
+ %td= @runner.architecture
%tr
- %td
- Description
- %td
- = @runner.description
+ %td Description
+ %td= @runner.description
%tr
- %td
- Last contact
+ %td Last contact
%td
- if @runner.contacted_at
#{time_ago_in_words(@runner.contacted_at)} ago
- else
Never
-
-
-
diff --git a/app/views/projects/triggers/index.html.haml b/app/views/projects/triggers/index.html.haml
index f91885b216d..d73ac987161 100644
--- a/app/views/projects/triggers/index.html.haml
+++ b/app/views/projects/triggers/index.html.haml
@@ -18,7 +18,7 @@
%th
= render partial: 'trigger', collection: @triggers, as: :trigger
- else
- %p.profile-settings-message.text-center.append-bottom-default
+ %p.settings-message.text-center.append-bottom-default
There are no triggers to use, add one by the button below.
= form_for @trigger, url: url_for(controller: 'projects/triggers', action: 'create') do |f|
diff --git a/app/views/projects/variables/_content.html.haml b/app/views/projects/variables/_content.html.haml
new file mode 100644
index 00000000000..0249e0c1bf1
--- /dev/null
+++ b/app/views/projects/variables/_content.html.haml
@@ -0,0 +1,8 @@
+%h4.prepend-top-0
+ Secret Variables
+%p
+ These variables will be set to environment by the runner.
+%p
+ So you can use them for passwords, secret keys or whatever you want.
+%p
+ The value of the variable can be visible in build log if explicitly asked to do so.
diff --git a/app/views/projects/variables/_form.html.haml b/app/views/projects/variables/_form.html.haml
new file mode 100644
index 00000000000..a5bae83e0ce
--- /dev/null
+++ b/app/views/projects/variables/_form.html.haml
@@ -0,0 +1,10 @@
+= form_for [@project.namespace.becomes(Namespace), @project, @variable] do |f|
+ = form_errors(@variable)
+
+ .form-group
+ = f.label :key, "Key", class: "label-light"
+ = f.text_field :key, class: "form-control", placeholder: "PROJECT_VARIABLE", required: true
+ .form-group
+ = f.label :value, "Value", class: "label-light"
+ = f.text_area :value, class: "form-control", placeholder: "PROJECT_VARIABLE", required: true
+ = f.submit btn_text, class: "btn btn-save"
diff --git a/app/views/projects/variables/_table.html.haml b/app/views/projects/variables/_table.html.haml
new file mode 100644
index 00000000000..6c43f822db4
--- /dev/null
+++ b/app/views/projects/variables/_table.html.haml
@@ -0,0 +1,25 @@
+.table-responsive.variables-table
+ %table.table
+ %colgroup
+ %col
+ %col
+ %col{ width: 100 }
+ %thead
+ %th Key
+ %th Value
+ %th
+ %tbody
+ - @project.variables.each do |variable|
+ - if variable.id?
+ %tr
+ %td= variable.key
+ %td= variable.value
+ %td
+ = link_to namespace_project_variable_path(@project.namespace, @project, variable), class: "btn btn-transparent btn-variable-edit" do
+ %span.sr-only
+ Update
+ = icon("pencil")
+ = link_to namespace_project_variable_path(@project.namespace, @project, variable), class: "btn btn-transparent btn-variable-delete", method: :delete, data: { confirm: "Are you sure?" } do
+ %span.sr-only
+ Remove
+ = icon("trash")
diff --git a/app/views/projects/variables/index.html.haml b/app/views/projects/variables/index.html.haml
new file mode 100644
index 00000000000..09bb54600af
--- /dev/null
+++ b/app/views/projects/variables/index.html.haml
@@ -0,0 +1,17 @@
+- page_title "Variables"
+
+.row.prepend-top-default.append-bottom-default
+ .col-lg-3
+ = render "content"
+ .col-lg-9
+ %h5.prepend-top-0
+ Add a variable
+ = render "form", btn_text: "Add new variable"
+ %hr
+ %h5.prepend-top-0
+ Your variables (#{@project.variables.size})
+ - if @project.variables.empty?
+ %p.settings-message.text-center.append-bottom-0
+ No variables found, add one with the form above.
+ - else
+ = render "table"
diff --git a/app/views/projects/variables/show.html.haml b/app/views/projects/variables/show.html.haml
index ca284b84d39..297a53ca98c 100644
--- a/app/views/projects/variables/show.html.haml
+++ b/app/views/projects/variables/show.html.haml
@@ -1,36 +1,9 @@
- page_title "Variables"
-%h3.page-title
- Secret Variables
-%p.light
- These variables will be set to environment by the runner.
- %br
- So you can use them for passwords, secret keys or whatever you want.
- %br
- The value of the variable can be visible in build log if explicitly asked to do so.
-
-%hr
-
-
-= nested_form_for @project, url: url_for(controller: 'projects/variables', action: 'update'), html: { class: 'form-horizontal' } do |f|
- = form_errors(@project)
-
- = f.fields_for :variables do |variable_form|
- .form-group
- = variable_form.label :key, 'Key', class: 'control-label'
- .col-sm-10
- = variable_form.text_field :key, class: 'form-control', placeholder: "PROJECT_VARIABLE"
-
- .form-group
- = variable_form.label :value, 'Value', class: 'control-label'
- .col-sm-10
- = variable_form.text_area :value, class: 'form-control', rows: 2, placeholder: ""
-
- = variable_form.link_to_remove "Remove this variable", class: 'btn btn-danger pull-right prepend-top-10'
- %hr
- %p
- .clearfix
- = f.link_to_add "Add a variable", :variables, class: 'btn btn-success pull-right'
-
- .form-actions
- = f.submit 'Save changes', class: 'btn btn-save', return_to: request.original_url
+.row.prepend-top-default.append-bottom-default
+ .col-lg-3
+ = render "content"
+ .col-lg-9
+ %h5.prepend-top-0
+ Update variable
+ = render "form", btn_text: "Save variable"
diff --git a/app/views/shared/groups/_list.html.haml b/app/views/shared/groups/_list.html.haml
index 1aa7ed1f2eb..427595c47a5 100644
--- a/app/views/shared/groups/_list.html.haml
+++ b/app/views/shared/groups/_list.html.haml
@@ -3,4 +3,4 @@
- groups.each_with_index do |group, i|
= render "shared/groups/group", group: group
- else
- %h3 No groups found
+ .nothing-here-block No groups found
diff --git a/app/views/shared/issuable/_form.html.haml b/app/views/shared/issuable/_form.html.haml
index 5c52cc6d1da..fc3410f425d 100644
--- a/app/views/shared/issuable/_form.html.haml
+++ b/app/views/shared/issuable/_form.html.haml
@@ -44,45 +44,53 @@
This issue is confidential and should only be visible to team members
- if can?(current_user, :"admin_#{issuable.to_ability_name}", issuable.project)
+ - has_due_date = issuable.has_attribute?(:due_date)
%hr
- .form-group
- .issue-assignee
- = f.label :assignee_id, "Assignee", class: 'control-label'
- .col-sm-10
- .issuable-form-select-holder
- = users_select_tag("#{issuable.class.model_name.param_key}[assignee_id]",
- placeholder: 'Select assignee', class: 'custom-form-control', null_user: true,
- selected: issuable.assignee_id, project: @target_project || @project,
- first_user: true, current_user: true, include_blank: true)
- &nbsp;
- = link_to 'Assign to me', '#', class: 'btn assign-to-me-link'
- .form-group
- .issue-milestone
- = f.label :milestone_id, "Milestone", class: 'control-label'
- .col-sm-10
- - if milestone_options(issuable).present?
+ .row
+ %div{ class: (has_due_date ? "col-lg-6" : "col-sm-12") }
+ .form-group.issue-assignee
+ = f.label :assignee_id, "Assignee", class: "control-label #{"col-lg-4" if has_due_date}"
+ .col-sm-10{ class: ("col-lg-8" if has_due_date) }
.issuable-form-select-holder
- = f.select(:milestone_id, milestone_options(issuable),
- { include_blank: true }, { class: 'select2', data: { placeholder: 'Select milestone' } })
- - else
- .prepend-top-10
- %span.light No open milestones available.
- &nbsp;
- - if can? current_user, :admin_milestone, issuable.project
- = link_to 'Create new milestone', new_namespace_project_milestone_path(issuable.project.namespace, issuable.project), target: :blank
- .form-group
- - has_labels = issuable.project.labels.any?
- = f.label :label_ids, "Labels", class: 'control-label'
- .col-sm-10{ class: ('issuable-form-padding-top' if !has_labels) }
- - if has_labels
- .issuable-form-select-holder
- = f.collection_select :label_ids, issuable.project.labels.all, :id, :name,
- { selected: issuable.label_ids }, multiple: true, class: 'select2', data: { placeholder: "Select labels" }
- - else
- %span.light No labels yet.
- &nbsp;
- - if can? current_user, :admin_label, issuable.project
- = link_to 'Create new label', new_namespace_project_label_path(issuable.project.namespace, issuable.project), target: :blank
+ = users_select_tag("#{issuable.class.model_name.param_key}[assignee_id]",
+ placeholder: 'Select assignee', class: 'custom-form-control', null_user: true,
+ selected: issuable.assignee_id, project: @target_project || @project,
+ first_user: true, current_user: true, include_blank: true)
+ %div
+ = link_to 'Assign to me', '#', class: 'assign-to-me-link prepend-top-5 inline'
+ .form-group.issue-milestone
+ = f.label :milestone_id, "Milestone", class: "control-label #{"col-lg-4" if has_due_date}"
+ .col-sm-10{ class: ("col-lg-8" if has_due_date) }
+ - if milestone_options(issuable).present?
+ .issuable-form-select-holder
+ = f.select(:milestone_id, milestone_options(issuable),
+ { include_blank: true }, { class: 'select2', data: { placeholder: 'Select milestone' } })
+ - else
+ .prepend-top-10
+ %span.light No open milestones available.
+ - if can? current_user, :admin_milestone, issuable.project
+ %div
+ = link_to 'Create new milestone', new_namespace_project_milestone_path(issuable.project.namespace, issuable.project), target: :blank, class: "prepend-top-5 inline"
+ .form-group
+ - has_labels = issuable.project.labels.any?
+ = f.label :label_ids, "Labels", class: "control-label #{"col-lg-4" if has_due_date}"
+ .col-sm-10{ class: "#{"col-lg-8" if has_due_date} #{'issuable-form-padding-top' if !has_labels}" }
+ - if has_labels
+ .issuable-form-select-holder
+ = f.collection_select :label_ids, issuable.project.labels.all, :id, :name,
+ { selected: issuable.label_ids }, multiple: true, class: 'select2', data: { placeholder: "Select labels" }
+ - else
+ %span.light No labels yet.
+ - if can? current_user, :admin_label, issuable.project
+ %div
+ = link_to 'Create new label', new_namespace_project_label_path(issuable.project.namespace, issuable.project), target: :blank, class: "prepend-top-5 inline"
+ - if has_due_date
+ .col-lg-6
+ .form-group
+ = f.label :due_date, "Due date", class: "control-label"
+ = f.hidden_field :due_date, id: "issuable-due-date"
+ .col-sm-10
+ .datepicker
- if issuable.can_move?(current_user)
%hr
@@ -114,6 +122,13 @@
- if @merge_request.new_record?
&nbsp;
= link_to 'Change branches', mr_change_branches_path(@merge_request)
+ - if @merge_request.can_remove_source_branch?(current_user)
+ .form-group
+ .col-sm-10.col-sm-offset-2
+ .checkbox
+ = label_tag 'merge_request[force_remove_source_branch]' do
+ = check_box_tag 'merge_request[force_remove_source_branch]', '1', @merge_request.force_remove_source_branch?
+ Remove source branch when merge request is accepted.
- is_footer = !(issuable.is_a?(MergeRequest) && issuable.new_record?)
.row-content-block{class: (is_footer ? "footer-block" : "middle-block")}
diff --git a/app/views/shared/milestones/_participants_tab.html.haml b/app/views/shared/milestones/_participants_tab.html.haml
index 67ae85ac276..549d2e2f61e 100644
--- a/app/views/shared/milestones/_participants_tab.html.haml
+++ b/app/views/shared/milestones/_participants_tab.html.haml
@@ -3,6 +3,6 @@
%li
= link_to user, title: user.name, class: "darken" do
= image_tag avatar_icon(user, 32), class: "avatar s32"
- %strong= truncate(user.name, lenght: 40)
+ %strong= truncate(user.name, length: 40)
%br
%small.cgray= user.username
diff --git a/app/views/shared/projects/_project.html.haml b/app/views/shared/projects/_project.html.haml
index ab8b022411d..9ef021747a5 100644
--- a/app/views/shared/projects/_project.html.haml
+++ b/app/views/shared/projects/_project.html.haml
@@ -17,7 +17,7 @@
= project.main_language
- if project.commit.try(:status)
%span
- = render_ci_status(project.commit)
+ = render_commit_status(project.commit)
- if forks
%span
= icon('code-fork')
diff --git a/app/workers/emails_on_push_worker.rb b/app/workers/emails_on_push_worker.rb
index 6ebcba5f39b..fa959fc56e3 100644
--- a/app/workers/emails_on_push_worker.rb
+++ b/app/workers/emails_on_push_worker.rb
@@ -27,15 +27,18 @@ class EmailsOnPushWorker
:push
end
+ diff_refs = nil
compare = nil
reverse_compare = false
if action == :push
compare = Gitlab::Git::Compare.new(project.repository.raw_repository, before_sha, after_sha)
+ diff_refs = [project.merge_base_commit(before_sha, after_sha), project.commit(after_sha)]
return false if compare.same
if compare.commits.empty?
compare = Gitlab::Git::Compare.new(project.repository.raw_repository, after_sha, before_sha)
+ diff_refs = [project.merge_base_commit(after_sha, before_sha), project.commit(before_sha)]
reverse_compare = true
@@ -48,13 +51,14 @@ class EmailsOnPushWorker
send_email(
recipient,
project_id,
- author_id: author_id,
- ref: ref,
- action: action,
- compare: compare,
- reverse_compare: reverse_compare,
- send_from_committer_email: send_from_committer_email,
- disable_diffs: disable_diffs
+ author_id: author_id,
+ ref: ref,
+ action: action,
+ compare: compare,
+ reverse_compare: reverse_compare,
+ diff_refs: diff_refs,
+ send_from_committer_email: send_from_committer_email,
+ disable_diffs: disable_diffs
)
# These are input errors and won't be corrected even if Sidekiq retries
diff --git a/app/workers/repository_import_worker.rb b/app/workers/repository_import_worker.rb
index 2937493c614..fbc7ed63c6a 100644
--- a/app/workers/repository_import_worker.rb
+++ b/app/workers/repository_import_worker.rb
@@ -13,7 +13,7 @@ class RepositoryImportWorker
result = Projects::ImportService.new(project, current_user).execute
if result[:status] == :error
- project.update(import_error: result[:message])
+ project.update(import_error: Gitlab::UrlSanitizer.sanitize(result[:message]))
project.import_fail
return
end
diff --git a/config/application.rb b/config/application.rb
index cba80f38f1f..0e5a77285e5 100644
--- a/config/application.rb
+++ b/config/application.rb
@@ -26,6 +26,8 @@ module Gitlab
#{config.root}/app/models/members
#{config.root}/app/models/project_services))
+ config.generators.templates.push("#{config.root}/generator_templates")
+
# Only load the plugins named here, in the order given (default is alphabetical).
# :all can be used as a placeholder for all plugins not explicitly named.
# config.plugins = [ :exception_notification, :ssl_requirement, :all ]
@@ -39,7 +41,7 @@ module Gitlab
config.encoding = "utf-8"
# Configure sensitive parameters which will be filtered from the log file.
- #
+ #
# Parameters filtered:
# - Password (:password, :password_confirmation)
# - Private tokens (:private_token)
@@ -78,6 +80,7 @@ module Gitlab
config.assets.precompile << "*.png"
config.assets.precompile << "print.css"
config.assets.precompile << "notify.css"
+ config.assets.precompile << "mailers/repository_push_email.css"
# Version of your assets, change this if you want to expire all your assets
config.assets.version = '1.0'
diff --git a/config/gitlab.yml.example b/config/gitlab.yml.example
index d935121d88b..0510e7df597 100644
--- a/config/gitlab.yml.example
+++ b/config/gitlab.yml.example
@@ -179,10 +179,11 @@ production: &base
registry:
# enabled: true
# host: registry.example.com
- # port: 5000
- # api_url: http://localhost:5000/
- # key: config/registry.key
- # issuer: omnibus-certificate
+ # port: 5005
+ # api_url: http://localhost:5000/ # internal address to the registry, will be used by GitLab to directly communicate with API
+ # key_path: config/registry.key
+ # path: shared/registry
+ # issuer: gitlab-issuer
#
# 2. GitLab CI settings
diff --git a/config/initializers/1_settings.rb b/config/initializers/1_settings.rb
index d1fcb053bee..124d63ce3ac 100644
--- a/config/initializers/1_settings.rb
+++ b/config/initializers/1_settings.rb
@@ -249,9 +249,12 @@ Settings.artifacts['max_size'] ||= 100 # in megabytes
Settings['registry'] ||= Settingslogic.new({})
Settings.registry['enabled'] ||= false
Settings.registry['host'] ||= "example.com"
+Settings.registry['port'] ||= nil
Settings.registry['api_url'] ||= "http://localhost:5000/"
Settings.registry['key'] ||= nil
Settings.registry['issuer'] ||= nil
+Settings.registry['host_port'] ||= [Settings.registry['host'], Settings.registry['port']].compact.join(':')
+Settings.registry['path'] = File.expand_path(Settings.registry['path'] || File.join(Settings.shared['path'], 'registry'), Rails.root)
#
# Git LFS
diff --git a/config/routes.rb b/config/routes.rb
index e1b72556098..d8a2435b078 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -663,9 +663,16 @@ Rails.application.routes.draw do
end
resources :protected_branches, only: [:index, :create, :update, :destroy], constraints: { id: Gitlab::Regex.git_reference_regex }
- resource :variables, only: [:show, :update]
+ resources :variables, only: [:index, :show, :update, :create, :destroy]
resources :triggers, only: [:index, :create, :destroy]
+ resources :pipelines, only: [:index, :new, :create, :show] do
+ member do
+ post :cancel
+ post :retry
+ end
+ end
+
resources :builds, only: [:index, :show], constraints: { id: /\d+/ } do
collection do
post :cancel_all
@@ -693,6 +700,8 @@ Rails.application.routes.draw do
end
end
+ resources :container_registry, only: [:index, :destroy], constraints: { id: Gitlab::Regex.container_registry_reference_regex }
+
resources :milestones, constraints: { id: /\d+/ } do
member do
put :sort_issues
diff --git a/db/migrate/20160302152808_remove_wrong_import_url_from_projects.rb b/db/migrate/20160302152808_remove_wrong_import_url_from_projects.rb
index 8a351cf27a3..561c18a5776 100644
--- a/db/migrate/20160302152808_remove_wrong_import_url_from_projects.rb
+++ b/db/migrate/20160302152808_remove_wrong_import_url_from_projects.rb
@@ -24,7 +24,7 @@ class RemoveWrongImportUrlFromProjects < ActiveRecord::Migration
def process_projects_with_wrong_url
projects_with_wrong_import_url.each do |project|
begin
- import_url = Gitlab::ImportUrl.new(project["import_url"])
+ import_url = Gitlab::UrlSanitizer.new(project["import_url"])
update_import_url(import_url, project)
update_import_data(import_url, project)
diff --git a/db/migrate/20160308212903_add_default_group_visibility_to_application_settings.rb b/db/migrate/20160308212903_add_default_group_visibility_to_application_settings.rb
index 75de5f70fa2..72b862d67d2 100644
--- a/db/migrate/20160308212903_add_default_group_visibility_to_application_settings.rb
+++ b/db/migrate/20160308212903_add_default_group_visibility_to_application_settings.rb
@@ -7,7 +7,9 @@ class AddDefaultGroupVisibilityToApplicationSettings < ActiveRecord::Migration
add_column :application_settings, :default_group_visibility, :integer
# Unfortunately, this can't be a `default`, since we don't want the configuration specific
# `allowed_visibility_level` to end up in schema.rb
- execute("UPDATE application_settings SET default_group_visibility = #{allowed_visibility_level}")
+
+ visibility_level = allowed_visibility_level || Gitlab::VisibilityLevel::PRIVATE
+ execute("UPDATE application_settings SET default_group_visibility = #{visibility_level}")
end
def down
diff --git a/db/migrate/20160504112519_add_run_untagged_to_ci_runner.rb b/db/migrate/20160504112519_add_run_untagged_to_ci_runner.rb
new file mode 100644
index 00000000000..84e5e4eabe2
--- /dev/null
+++ b/db/migrate/20160504112519_add_run_untagged_to_ci_runner.rb
@@ -0,0 +1,13 @@
+class AddRunUntaggedToCiRunner < ActiveRecord::Migration
+ include Gitlab::Database::MigrationHelpers
+ disable_ddl_transaction!
+
+ def up
+ add_column_with_default(:ci_runners, :run_untagged, :boolean,
+ default: true, allow_null: false)
+ end
+
+ def down
+ remove_column(:ci_runners, :run_untagged)
+ end
+end
diff --git a/db/schema.rb b/db/schema.rb
index af4f4c609e7..aee5fb90937 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: 20160509201028) do
+ActiveRecord::Schema.define(version: 20160516174813) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
@@ -82,6 +82,7 @@ ActiveRecord::Schema.define(version: 20160509201028) do
t.integer "metrics_packet_size", default: 1
t.text "disabled_oauth_sign_in_sources"
t.string "health_check_access_token"
+ t.boolean "send_user_confirmation_email", default: false
end
create_table "audit_events", force: :cascade do |t|
@@ -269,6 +270,7 @@ ActiveRecord::Schema.define(version: 20160509201028) do
t.string "revision"
t.string "platform"
t.string "architecture"
+ t.boolean "run_untagged", default: true, null: false
end
add_index "ci_runners", ["description"], name: "index_ci_runners_on_description_trigram", using: :gin, opclasses: {"description"=>"gin_trgm_ops"}
@@ -632,10 +634,10 @@ ActiveRecord::Schema.define(version: 20160509201028) do
t.string "line_code"
t.string "commit_id"
t.integer "noteable_id"
- t.boolean "system", default: false, null: false
+ t.boolean "system", default: false, null: false
t.text "st_diff"
t.integer "updated_by_id"
- t.boolean "is_award", default: false, null: false
+ t.boolean "is_award", default: false, null: false
t.string "type"
end
diff --git a/doc/README.md b/doc/README.md
index e358da1c424..a297ce54f3e 100644
--- a/doc/README.md
+++ b/doc/README.md
@@ -41,8 +41,10 @@
- [Git LFS configuration](workflow/lfs/lfs_administration.md)
- [Housekeeping](administration/housekeeping.md) Keep your Git repository tidy and fast.
- [GitLab Performance Monitoring](monitoring/performance/introduction.md) Configure GitLab and InfluxDB for measuring performance metrics
+- [Monitoring uptime](monitoring/health_check.md) Check the server status using the health check endpoint
- [Sidekiq Troubleshooting](administration/troubleshooting/sidekiq.md) Debug when Sidekiq appears hung and is not processing jobs
- [High Availability](administration/high_availability/README.md) Configure multiple servers for scaling or high availability
+- [Container Registry](administration/container_registry.md) Configure Docker Registry with GitLab
## Contributor documentation
diff --git a/doc/administration/container_registry.md b/doc/administration/container_registry.md
new file mode 100644
index 00000000000..caf9a5bef2c
--- /dev/null
+++ b/doc/administration/container_registry.md
@@ -0,0 +1,375 @@
+# GitLab Container Registry Administration
+
+> **Note:**
+This feature was [introduced][ce-4040] in GitLab 8.8.
+
+With the Docker Container Registry integrated into GitLab, every project can
+have its own space to store its Docker images.
+
+You can read more about Docker Registry at https://docs.docker.com/registry/introduction/.
+
+---
+
+<!-- START doctoc generated TOC please keep comment here to allow auto update -->
+<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
+**Table of Contents** *generated with [DocToc](https://github.com/thlorenz/doctoc)*
+
+- [Enable the Container Registry](#enable-the-container-registry)
+- [Container Registry domain configuration](#container-registry-domain-configuration)
+ - [Configure Container Registry under an existing GitLab domain](#configure-container-registry-under-an-existing-gitlab-domain)
+ - [Configure Container Registry under its own domain](#configure-container-registry-under-its-own-domain)
+- [Disable Container Registry site-wide](#disable-container-registry-site-wide)
+- [Disable Container Registry per project](#disable-container-registry-per-project)
+- [Disable Container Registry for new projects site-wide](#disable-container-registry-for-new-projects-site-wide)
+- [Container Registry storage path](#container-registry-storage-path)
+- [Storage limitations](#storage-limitations)
+- [Changelog](#changelog)
+
+<!-- END doctoc generated TOC please keep comment here to allow auto update -->
+
+## Enable the Container Registry
+
+**Omnibus GitLab installations**
+
+All you have to do is configure the domain name under which the Container
+Registry will listen to. Read [#container-registry-domain-configuration](#container-registry-domain-configuration)
+and pick one of the two options that fits your case.
+
+>**Note:**
+The container Registry works under HTTPS by default. Using HTTP is possible
+but not recommended and out of the scope of this document.
+Read the [insecure Registry documentation][docker-insecure] if you want to
+implement this.
+
+---
+
+**Installations from source**
+
+If you have installed GitLab from source:
+
+1. You will have to [install Docker Registry][registry-deploy] by yourself.
+1. After the installation is complete, you will have to configure the Registry's
+ settings in `gitlab.yml` in order to enable it.
+1. Use the sample NGINX configuration file that is found under
+ [`lib/support/nginx/registry-ssl`][registry-ssl] and edit it to match the
+ `host`, `port` and TLS certs paths.
+
+The contents of `gitlab.yml` are:
+
+```
+registry:
+ enabled: true
+ host: registry.gitlab.example.com
+ port: 5005
+ api_url: http://localhost:5000/
+ key_path: config/registry.key
+ path: shared/registry
+ issuer: gitlab-issuer
+```
+
+where:
+
+| Parameter | Description |
+| --------- | ----------- |
+| `enabled` | `true` or `false`. Enables the Registry in GitLab. By default this is `false`. |
+| `host` | The host URL under which the Registry will run and the users will be able to use. |
+| `port` | The port under which the external Registry domain will listen on. |
+| `api_url` | The internal API URL under which the Registry is exposed to. It defaults to `http://localhost:5000`. |
+| `key_path`| The private key location that is a pair of Registry's `rootcertbundle`. Read the [token auth configuration documentation][token-config]. |
+| `path` | This should be the same directory like specified in Registry's `rootdirectory`. Read the [storage configuration documentation][storage-config]. This path needs to be readable by the GitLab user, the web-server user and the Registry user. Read more in [#container-registry-storage-path](#container-registry-storage-path). |
+| `issuer` | This should be the same value as configured in Registry's `issuer`. Read the [token auth configuration documentation][token-config]. |
+
+>**Note:**
+GitLab does not ship with a Registry init file. Hence, [restarting GitLab][restart gitlab]
+will not restart the Registry should you modify its settings. Read the upstream
+documentation on how to achieve that.
+
+## Container Registry domain configuration
+
+There are two ways you can configure the Registry's external domain.
+
+- Either [use the existing GitLab domain][existing-domain] where in that case
+ the Registry will have to listen on a port and reuse GitLab's TLS certificate,
+- or [use a completely separate domain][new-domain] with a new TLS certificate
+ for that domain.
+
+Since the container Registry requires a TLS certificate, in the end it all boils
+down to how easy or pricey is to get a new one.
+
+Please take this into consideration before configuring the Container Registry
+for the first time.
+
+### Configure Container Registry under an existing GitLab domain
+
+If the Registry is configured to use the existing GitLab domain, you can
+expose the Registry on a port so that you can reuse the existing GitLab TLS
+certificate.
+
+Assuming that the GitLab domain is `https://gitlab.example.com` and the port the
+Registry is exposed to the outside world is `4567`, here is what you need to set
+in `gitlab.rb` or `gitlab.yml` if you are using Omnibus GitLab or installed
+GitLab from source respectively.
+
+---
+
+**Omnibus GitLab installations**
+
+1. Your `/etc/gitlab/gitlab.rb` should contain the Registry URL as well as the
+ path to the existing TLS certificate and key used by GitLab:
+
+ ```ruby
+ registry_external_url 'https://gitlab.example.com:4567'
+ ```
+
+ Note how the `registry_external_url` is listening on HTTPS under the
+ existing GitLab URL, but on a different port.
+
+ If your TLS certificate is not in `/etc/gitlab/ssl/gitlab.example.com.crt`
+ and key not in `/etc/gitlab/ssl/gitlab.example.com.key` uncomment the lines
+ below:
+
+ ```ruby
+ registry_nginx['ssl_certificate'] = "/path/to/certificate.pem"
+ registry_nginx['ssl_certificate_key'] = "/path/to/certificate.key"
+ ```
+
+1. Save the file and [reconfigure GitLab][] for the changes to take effect.
+
+---
+
+**Installations from source**
+
+1. Open `/home/git/gitlab/config/gitlab.yml`, find the `registry` entry and
+ configure it with the following settings:
+
+ ```
+ registry:
+ enabled: true
+ host: gitlab.example.com
+ port: 4567
+ ```
+
+1. Save the file and [restart GitLab][] for the changes to take effect.
+1. Make the relevant changes in NGINX as well (domain, port, TLS certificates path).
+
+---
+
+Users should now be able to login to the Container Registry with their GitLab
+credentials using:
+
+```bash
+docker login gitlab.example.com:4567
+```
+
+### Configure Container Registry under its own domain
+
+If the Registry is configured to use its own domain, you will need a TLS
+certificate for that specific domain (e.g., `registry.example.com`) or maybe
+a wildcard certificate if hosted under a subdomain of your existing GitLab
+domain (e.g., `registry.gitlab.example.com`).
+
+Let's assume that you want the container Registry to be accessible at
+`https://registry.gitlab.example.com`.
+
+---
+
+**Omnibus GitLab installations**
+
+1. Place your TLS certificate and key in
+ `/etc/gitlab/ssl/registry.gitlab.example.com.crt` and
+ `/etc/gitlab/ssl/registry.gitlab.example.com.key` and make sure they have
+ correct permissions:
+
+ ```bash
+ chmod 600 /etc/gitlab/ssl/registry.gitlab.example.com.*
+ ```
+
+1. Once the TLS certificate is in place, edit `/etc/gitlab/gitlab.rb` with:
+
+ ```ruby
+ registry_external_url 'https://registry.gitlab.example.com'
+ ```
+
+ Note how the `registry_external_url` is listening on HTTPS.
+
+1. Save the file and [reconfigure GitLab][] for the changes to take effect.
+
+> **Note:**
+If you have a [wildcard certificate][], you need to specify the path to the
+certificate in addition to the URL, in this case `/etc/gitlab/gitlab.rb` will
+look like:
+>
+```ruby
+registry_nginx['ssl_certificate'] = "/etc/gitlab/ssl/certificate.pem"
+registry_nginx['ssl_certificate_key'] = "/etc/gitlab/ssl/certificate.key"
+```
+
+---
+
+**Installations from source**
+
+1. Open `/home/git/gitlab/config/gitlab.yml`, find the `registry` entry and
+ configure it with the following settings:
+
+ ```
+ registry:
+ enabled: true
+ host: registry.gitlab.example.com
+ ```
+
+1. Save the file and [restart GitLab][] for the changes to take effect.
+1. Make the relevant changes in NGINX as well (domain, port, TLS certificates path).
+
+---
+
+Users should now be able to login to the Container Registry using their GitLab
+credentials:
+
+```bash
+docker login registry.gitlab.example.com
+```
+
+## Disable Container Registry site-wide
+
+>**Note:**
+Disabling the Registry in the Rails GitLab application as set by the following
+steps, will not remove any existing Docker images. This is handled by the
+Registry application itself.
+
+**Omnibus GitLab**
+
+1. Open `/etc/gitlab/gitlab.rb` and set `registry['enable']` to `false`:
+
+ ```ruby
+ registry['enable'] = false
+ ```
+
+1. Save the file and [reconfigure GitLab][] for the changes to take effect.
+
+---
+
+**Installations from source**
+
+1. Open `/home/git/gitlab/config/gitlab.yml`, find the `registry` entry and
+ set `enabled` to `false`:
+
+ ```
+ registry:
+ enabled: false
+ ```
+
+1. Save the file and [restart GitLab][] for the changes to take effect.
+
+## Disable Container Registry per project
+
+If Registry is enabled in your GitLab instance, but you don't need it for your
+project, you can disable it from your project's settings. Read the user guide
+on how to achieve that.
+
+## Disable Container Registry for new projects site-wide
+
+If the Container Registry is enabled, then it will be available on all new
+projects. To disable this function and let the owners of a project to enable
+the Container Registry by themselves, follow the steps below.
+
+---
+
+**Omnibus GitLab installations**
+
+1. Edit `/etc/gitlab/gitlab.rb` and add the following line:
+
+ ```ruby
+ gitlab_rails['gitlab_default_projects_features_container_registry'] = false
+ ```
+
+1. Save the file and [reconfigure GitLab][] for the changes to take effect.
+
+---
+
+**Installations from source**
+
+1. Open `/home/git/gitlab/config/gitlab.yml`, find the `default_projects_features`
+ entry and configure it so that `container_registry` is set to `false`:
+
+ ```
+ ## Default project features settings
+ default_projects_features:
+ issues: true
+ merge_requests: true
+ wiki: true
+ snippets: false
+ builds: true
+ container_registry: false
+ ```
+
+1. Save the file and [restart GitLab][] for the changes to take effect.
+
+## Container Registry storage path
+
+To change the storage path where Docker images will be stored, follow the
+steps below.
+
+This path is accessible to:
+
+- the user running the Container Registry daemon,
+- the user running GitLab
+
+> **Warning** You should confirm that all GitLab, Registry and web server users
+have access to this directory.
+
+---
+
+**Omnibus GitLab installations**
+
+The default location where images are stored in Omnibus, is
+`/var/opt/gitlab/gitlab-rails/shared/registry`. To change it:
+
+1. Edit `/etc/gitlab/gitlab.rb`:
+
+ ```ruby
+ gitlab_rails['registry_path'] = "/path/to/registry/storage"
+ ```
+
+1. Save the file and [reconfigure GitLab][] for the changes to take effect.
+
+---
+
+**Installations from source**
+
+The default location where images are stored in source installations, is
+`/home/git/gitlab/shared/registry`. To change it:
+
+1. Open `/home/git/gitlab/config/gitlab.yml`, find the `registry` entry and
+ change the `path` setting:
+
+ ```
+ registry:
+ path: shared/registry
+ ```
+
+1. Save the file and [restart GitLab][] for the changes to take effect.
+
+## Storage limitations
+
+Currently, there is no storage limitation, which means a user can upload an
+infinite amount of Docker images with arbitrary sizes. This setting will be
+configurable in future releases.
+
+## Changelog
+
+**GitLab 8.8 ([source docs][8-8-docs])**
+
+- GitLab Container Registry feature was introduced.
+
+[reconfigure gitlab]: restart_gitlab.md#omnibus-gitlab-reconfigure
+[restart gitlab]: restart_gitlab.md#installations-from-source
+[wildcard certificate]: https://en.wikipedia.org/wiki/Wildcard_certificate
+[ce-4040]: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/4040
+[docker-insecure]: https://docs.docker.com/registry/insecure/
+[registry-deploy]: https://docs.docker.com/registry/deploying/
+[storage-config]: https://docs.docker.com/registry/configuration/#storage
+[token-config]: https://docs.docker.com/registry/configuration/#token
+[8-8-docs]: https://gitlab.com/gitlab-org/gitlab-ce/blob/8-8-stable/doc/administration/container_registry.md
+[registry-ssl]: https://gitlab.com/gitlab-org/gitlab-ce/blob/master/lib/support/nginx/registry-ssl
+[existing-domain]: #configure-container-registry-under-an-existing-gitlab-domain
+[new-domain]: #configure-container-registry-under-its-own-domain
diff --git a/doc/api/README.md b/doc/api/README.md
index ff039f1886f..27c5962decf 100644
--- a/doc/api/README.md
+++ b/doc/api/README.md
@@ -33,7 +33,7 @@ following locations:
- [Build triggers](build_triggers.md)
- [Build Variables](build_variables.md)
- [Runners](runners.md)
-- [Licenses](licenses.md)
+- [Open source license templates](licenses.md)
## Authentication
diff --git a/doc/api/groups.md b/doc/api/groups.md
index 2821bc21b81..1ccb9715e96 100644
--- a/doc/api/groups.md
+++ b/doc/api/groups.md
@@ -265,7 +265,6 @@ GET /groups/:id/members
{
"id": 1,
"username": "raymond_smith",
- "email": "ray@smith.org",
"name": "Raymond Smith",
"state": "active",
"created_at": "2012-10-22T14:13:35Z",
@@ -274,7 +273,6 @@ GET /groups/:id/members
{
"id": 2,
"username": "john_doe",
- "email": "joh@doe.org",
"name": "John Doe",
"state": "active",
"created_at": "2012-10-22T14:13:35Z",
diff --git a/doc/api/runners.md b/doc/api/runners.md
index cc6c6b7cb2f..ddfa298f79d 100644
--- a/doc/api/runners.md
+++ b/doc/api/runners.md
@@ -275,7 +275,7 @@ POST /projects/:id/runners
| `runner_id` | integer | yes | The ID of a runner |
```
-curl -X POST -H "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v3/project/9/runners" -F "runner_id=9"
+curl -X POST -H "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v3/projects/9/runners" -F "runner_id=9"
```
Example response:
@@ -306,7 +306,7 @@ DELETE /projects/:id/runners/:runner_id
| `runner_id` | integer | yes | The ID of a runner |
```
-curl -X DELETE -H "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v3/project/9/runners/9"
+curl -X DELETE -H "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v3/projects/9/runners/9"
```
Example response:
diff --git a/doc/ci/deployment/README.md b/doc/ci/examples/deployment/README.md
index 7d91ce6710f..7d91ce6710f 100644
--- a/doc/ci/deployment/README.md
+++ b/doc/ci/examples/deployment/README.md
diff --git a/doc/ci/quick_start/README.md b/doc/ci/quick_start/README.md
index 6a42a935abd..386b8e29fcf 100644
--- a/doc/ci/quick_start/README.md
+++ b/doc/ci/quick_start/README.md
@@ -212,8 +212,8 @@ If you want to receive e-mail notifications about the result status of the
builds, you should explicitly enable the **Builds Emails** service under your
project's settings.
-For more information read the [Builds emails service documentation]
-(../../project_services/builds_emails.md).
+For more information read the
+[Builds emails service documentation](../../project_services/builds_emails.md).
## Builds badge
diff --git a/doc/ci/runners/README.md b/doc/ci/runners/README.md
index a06650b3387..b42d7a62ebc 100644
--- a/doc/ci/runners/README.md
+++ b/doc/ci/runners/README.md
@@ -125,7 +125,13 @@ shared runners will only run the jobs they are equipped to run.
For instance, at GitLab we have runners tagged with "rails" if they contain
the appropriate dependencies to run Rails test suites.
-### Be Careful with Sensitive Information
+### Prevent runner with tags from picking jobs without tags
+
+You can configure a runner to prevent it from picking jobs with tags when
+the runnner does not have tags assigned. This setting is available on each
+runner in *Project Settings* > *Runners*.
+
+### Be careful with sensitive information
If you can run a build on a runner, you can get access to any code it runs
and get the token of the runner. With shared runners, this means that anyone
diff --git a/doc/ci/triggers/README.md b/doc/ci/triggers/README.md
index 79ed512aabb..5c316510d0e 100644
--- a/doc/ci/triggers/README.md
+++ b/doc/ci/triggers/README.md
@@ -33,7 +33,7 @@ POST /projects/:id/trigger/builds
The required parameters are the trigger's `token` and the Git `ref` on which
the trigger will be performed. Valid refs are the branch, the tag or the commit
-SHA. The `:id` of a project can be found by [querying the API](../api/projects.md)
+SHA. The `:id` of a project can be found by [querying the API](../../api/projects.md)
or by visiting the **Triggers** page which provides self-explanatory examples.
When a rebuild is triggered, the information is exposed in GitLab's UI under
diff --git a/doc/ci/yaml/README.md b/doc/ci/yaml/README.md
index 7e9bced7616..63866d8c71c 100644
--- a/doc/ci/yaml/README.md
+++ b/doc/ci/yaml/README.md
@@ -128,7 +128,7 @@ builds, including deploy builds. This can be an array or a multi-line string.
### after_script
>**Note:**
-Introduced in GitLab 8.7 and GitLab Runner v1.2.
+Introduced in GitLab 8.7 and requires Gitlab Runner v1.2 (not yet released)
`after_script` is used to define the command that will be run after for all
builds. This has to be an array or a multi-line string.
diff --git a/doc/development/migration_style_guide.md b/doc/development/migration_style_guide.md
index 28dedf3978c..1c13b094582 100644
--- a/doc/development/migration_style_guide.md
+++ b/doc/development/migration_style_guide.md
@@ -8,7 +8,10 @@ In addition, having to take a server offline for a an upgrade small or big is
a big burden for most organizations. For this reason it is important that your
migrations are written carefully, can be applied online and adhere to the style guide below.
-It's advised to have offline migrations only in major GitLab releases.
+Migrations should not require GitLab installations to be taken offline unless
+_absolutely_ necessary. If a migration requires downtime this should be
+clearly mentioned during the review process as well as being documented in the
+monthly release post.
When writing your migrations, also consider that databases might have stale data
or inconsistencies and guard for that. Try to make as little assumptions as possible
@@ -58,6 +61,45 @@ remove_index :namespaces, column: :name if index_exists?(:namespaces, :name)
If you need to add an unique index please keep in mind there is possibility of existing duplicates. If it is possible write a separate migration for handling this situation. It can be just removing or removing with overwriting all references to these duplicates depend on situation.
+When adding an index make sure to use the method `add_concurrent_index` instead
+of the regular `add_index` method. The `add_concurrent_index` method
+automatically creates concurrent indexes when using PostgreSQL, removing the
+need for downtime. To use this method you must disable transactions by calling
+the method `disable_ddl_transaction!` in the body of your migration class like
+so:
+
+```
+class MyMigration < ActiveRecord::Migration
+ disable_ddl_transaction!
+
+ def change
+
+ end
+end
+```
+
+## Adding Columns With Default Values
+
+When adding columns with default values you should use the method
+`add_column_with_default`. This method ensures the table is updated without
+requiring downtime. This method is not reversible so you must manually define
+the `up` and `down` methods in your migration class.
+
+For example, to add the column `foo` to the `projects` table with a default
+value of `10` you'd write the following:
+
+```
+class MyMigration < ActiveRecord::Migration
+ def up
+ add_column_with_default(:projects, :foo, :integer, 10)
+ end
+
+ def down
+ remove_column(:projects, :foo)
+ end
+end
+```
+
## Testing
Make sure that your migration works with MySQL and PostgreSQL with data. An empty database does not guarantee that your migration is correct.
@@ -89,4 +131,4 @@ select_all("SELECT name, COUNT(id) as cnt FROM tags GROUP BY name HAVING COUNT(i
execute("UPDATE taggings SET tag_id = #{origin_tag_id} WHERE tag_id IN(#{duplicate_ids.join(",")})")
execute("DELETE FROM tags WHERE id IN(#{duplicate_ids.join(",")})")
end
-``` \ No newline at end of file
+```
diff --git a/doc/markdown/markdown.md b/doc/markdown/markdown.md
index 4f199b6af6f..236eb7b12c4 100644
--- a/doc/markdown/markdown.md
+++ b/doc/markdown/markdown.md
@@ -8,6 +8,7 @@
* [Multiple underscores in words](#multiple-underscores-in-words)
* [URL auto-linking](#url-auto-linking)
* [Code and Syntax Highlighting](#code-and-syntax-highlighting)
+* [Inline Diff](#inline-diff)
* [Emoji](#emoji)
* [Special GitLab references](#special-gitlab-references)
* [Task lists](#task-lists)
@@ -153,6 +154,19 @@ s = "There is no highlighting for this."
But let's throw in a <b>tag</b>.
```
+## Inline Diff
+
+With inline diffs tags you can display {+ additions +} or [- deletions -].
+
+The wrapping tags can be either curly braces or square brackets [+ additions +] or {- deletions -}.
+
+However the wrapping tags cannot be mixed as such:
+
+- {+ additions +]
+- [+ additions +}
+- {- deletions -]
+- [- deletions -}
+
## Emoji
Sometimes you want to :monkey: around a bit and add some :star2: to your :speech_balloon:. Well we have a gift for you:
@@ -185,20 +199,23 @@ GFM will turn that reference into a link so you can navigate between them easily
GFM will recognize the following:
-| input | references |
-|:-----------------------|:---------------------------|
-| `@user_name` | specific user |
-| `@group_name` | specific group |
-| `@all` | entire team |
-| `#123` | issue |
-| `!123` | merge request |
-| `$123` | snippet |
-| `~123` | label by ID |
-| `~bug` | one-word label by name |
-| `~"feature request"` | multi-word label by name |
-| `9ba12248` | specific commit |
-| `9ba12248...b19a04f5` | commit range comparison |
-| `[README](doc/README)` | repository file references |
+| input | references |
+|:-----------------------|:--------------------------- |
+| `@user_name` | specific user |
+| `@group_name` | specific group |
+| `@all` | entire team |
+| `#123` | issue |
+| `!123` | merge request |
+| `$123` | snippet |
+| `~123` | label by ID |
+| `~bug` | one-word label by name |
+| `~"feature request"` | multi-word label by name |
+| `%123` | milestone by ID |
+| `%v1.23` | one-word milestone by name |
+| `%"release candidate"` | multi-word milestone by name |
+| `9ba12248` | specific commit |
+| `9ba12248...b19a04f5` | commit range comparison |
+| `[README](doc/README)` | repository file references |
GFM also recognizes certain cross-project references:
@@ -206,6 +223,7 @@ GFM also recognizes certain cross-project references:
|:----------------------------------------|:------------------------|
| `namespace/project#123` | issue |
| `namespace/project!123` | merge request |
+| `namespace/project%123` | milestone |
| `namespace/project$123` | snippet |
| `namespace/project@9ba12248` | specific commit |
| `namespace/project@9ba12248...b19a04f5` | commit range comparison |
@@ -402,7 +420,7 @@ There are two ways to create links, inline-style and reference-style.
[I'm a reference-style link][Arbitrary case-insensitive reference text]
-[I'm a relative reference to a repository file](LICENSE)
+[I'm a relative reference to a repository file](LICENSE)[^1]
[You can use numbers for reference-style link definitions][1]
@@ -594,3 +612,4 @@ By including colons in the header row, you can align the text within that column
[rouge]: http://rouge.jneen.net/ "Rouge website"
[redcarpet]: https://github.com/vmg/redcarpet "Redcarpet website"
+[^1]: This link will be broken if you see this document from the Help page or docs.gitlab.com
diff --git a/doc/monitoring/health_check.md b/doc/monitoring/health_check.md
new file mode 100644
index 00000000000..defbf37ac19
--- /dev/null
+++ b/doc/monitoring/health_check.md
@@ -0,0 +1,66 @@
+# Health Check
+
+>**Note:** This feature was [introduced][ce-3888] in GitLab 8.8.
+
+GitLab provides a health check endpoint for uptime monitoring on the `health_check` web
+endpoint. The health check reports on the overall system status based on the status of
+the database connection, the state of the database migrations, and the ability to write
+and access the cache. This endpoint can be provided to uptime monitoring services like
+[Pingdom][pingdom], [Nagios][nagios-health], and [NewRelic][newrelic-health].
+
+## Access Token
+
+An access token needs to be provided while accessing the health check endpoint. The current
+accepted token can be found on the `admin/heath_check` page of your GitLab instance.
+
+![access token](img/health_check_token.png)
+
+The access token can be passed as a URL parameter:
+
+```
+https://gitlab.example.com/health_check.json?token=ACCESS_TOKEN
+```
+
+or as an HTTP header:
+
+```bash
+curl -H "TOKEN: ACCESS_TOKEN" https://gitlab.example.com/health_check.json
+```
+
+## Using the Endpoint
+
+Once you have the access token, health information can be retrieved as plain text, JSON,
+or XML using the `health_check` endpoint:
+
+- `https://gitlab.example.com/health_check?token=ACCESS_TOKEN`
+- `https://gitlab.example.com/health_check.json?token=ACCESS_TOKEN`
+- `https://gitlab.example.com/health_check.xml?token=ACCESS_TOKEN`
+
+You can also ask for the status of specific services:
+
+- `https://gitlab.example.com/health_check/cache.json?token=ACCESS_TOKEN`
+- `https://gitlab.example.com/health_check/database.json?token=ACCESS_TOKEN`
+- `https://gitlab.example.com/health_check/migrations.json?token=ACCESS_TOKEN`
+
+For example, the JSON output of the following health check:
+
+```bash
+curl -H "TOKEN: ACCESS_TOKEN" https://gitlab.example.com/health_check.json
+```
+
+would be like:
+
+```
+{"healthy":true,"message":"success"}
+```
+
+## Status
+
+On failure, the endpoint will return a `500` HTTP status code. On success, the endpoint
+will return a valid successful HTTP status code, and a `success` message. Ideally your
+uptime monitoring should look for the success message.
+
+[ce-3888]: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/3888
+[pingdom]: https://www.pingdom.com
+[nagios-health]: https://nagios-plugins.org/doc/man/check_http.html
+[newrelic-health]: https://docs.newrelic.com/docs/alerts/alert-policies/downtime-alerts/availability-monitoring
diff --git a/doc/monitoring/img/health_check_token.png b/doc/monitoring/img/health_check_token.png
new file mode 100644
index 00000000000..2daf8606b00
--- /dev/null
+++ b/doc/monitoring/img/health_check_token.png
Binary files differ
diff --git a/doc/permissions/permissions.md b/doc/permissions/permissions.md
index 6be5ea0b486..b76ce31cbad 100644
--- a/doc/permissions/permissions.md
+++ b/doc/permissions/permissions.md
@@ -39,6 +39,7 @@ documentation](../workflow/add-user/add-user.md).
| Cancel and retry builds | | | ✓ | ✓ | ✓ |
| Create or update commit status | | | ✓ | ✓ | ✓ |
| Update a container registry | | | ✓ | ✓ | ✓ |
+| Remove a container registry image | | | ✓ | ✓ | ✓ |
| Create new milestones | | | | ✓ | ✓ |
| Add new team members | | | | ✓ | ✓ |
| Push to protected branches | | | | ✓ | ✓ |
diff --git a/doc/workflow/lfs/manage_large_binaries_with_git_lfs.md b/doc/workflow/lfs/manage_large_binaries_with_git_lfs.md
index 1295dfbd770..9fe065fa680 100644
--- a/doc/workflow/lfs/manage_large_binaries_with_git_lfs.md
+++ b/doc/workflow/lfs/manage_large_binaries_with_git_lfs.md
@@ -127,7 +127,7 @@ To prevent this from happening, set the lfs url in project Git config:
```bash
-git config --add lfs.url "http://gitlab.example.com/group/project.git/info/lfs/objects/batch"
+git config --add lfs.url "http://gitlab.example.com/group/project.git/info/lfs"
```
### Credentials are always required when pushing an object
diff --git a/doc/workflow/notifications.md b/doc/workflow/notifications.md
index 80817c98d22..cbca94c0b5e 100644
--- a/doc/workflow/notifications.md
+++ b/doc/workflow/notifications.md
@@ -69,7 +69,7 @@ In all of the below cases, the notification will be sent to:
...with notification level "Participating" or higher
-- Watchers: project members with notification level "Watch"
+- Watchers: users with notification level "Watch"
- Subscribers: anyone who manually subscribed to the issue/merge request
| Event | Sent to |
diff --git a/features/steps/dashboard/dashboard.rb b/features/steps/dashboard/dashboard.rb
index b5980b35102..80ed4c6d64c 100644
--- a/features/steps/dashboard/dashboard.rb
+++ b/features/steps/dashboard/dashboard.rb
@@ -13,7 +13,7 @@ class Spinach::Features::Dashboard < Spinach::FeatureSteps
end
step 'I should see "Shop" project CI status' do
- expect(page).to have_link "Build skipped"
+ expect(page).to have_link "Commit: skipped"
end
step 'I should see last push widget' do
diff --git a/features/steps/project/commits/commits.rb b/features/steps/project/commits/commits.rb
index 93c37bf507f..f33f37be951 100644
--- a/features/steps/project/commits/commits.rb
+++ b/features/steps/project/commits/commits.rb
@@ -173,7 +173,7 @@ class Spinach::Features::ProjectCommits < Spinach::FeatureSteps
end
step 'I see commit ci info' do
- expect(page).to have_content "build: pending"
+ expect(page).to have_content "Builds for 1 pipeline pending"
end
step 'I click status link' do
@@ -181,7 +181,7 @@ class Spinach::Features::ProjectCommits < Spinach::FeatureSteps
end
step 'I see builds list' do
- expect(page).to have_content "build: pending"
+ expect(page).to have_content "Builds for 1 pipeline pending"
expect(page).to have_content "1 build"
end
diff --git a/features/steps/project/merge_requests.rb b/features/steps/project/merge_requests.rb
index 3b1a00f628a..b79d19f1c58 100644
--- a/features/steps/project/merge_requests.rb
+++ b/features/steps/project/merge_requests.rb
@@ -525,7 +525,7 @@ class Spinach::Features::ProjectMergeRequests < Spinach::FeatureSteps
step 'I should see merge request "Bug NS-05" with CI status' do
page.within ".mr-list" do
- expect(page).to have_link "Build pending"
+ expect(page).to have_link "Pipeline: pending"
end
end
diff --git a/generator_templates/active_record/migration/create_table_migration.rb b/generator_templates/active_record/migration/create_table_migration.rb
new file mode 100644
index 00000000000..27acc75dcc4
--- /dev/null
+++ b/generator_templates/active_record/migration/create_table_migration.rb
@@ -0,0 +1,35 @@
+# See http://doc.gitlab.com/ce/development/migration_style_guide.html
+# for more information on how to write migrations for GitLab.
+
+class <%= migration_class_name %> < ActiveRecord::Migration
+ include Gitlab::Database::MigrationHelpers
+
+ # When using the methods "add_concurrent_index" or "add_column_with_default"
+ # you must disable the use of transactions as these methods can not run in an
+ # existing transaction. When using "add_concurrent_index" make sure that this
+ # method is the _only_ method called in the migration, any other changes
+ # should go in a separate migration. This ensures that upon failure _only_ the
+ # index creation fails and can be retried or reverted easily.
+ #
+ # To disable transactions uncomment the following line and remove these
+ # comments:
+ # disable_ddl_transaction!
+
+ def change
+ create_table :<%= table_name %> do |t|
+<% attributes.each do |attribute| -%>
+<% if attribute.password_digest? -%>
+ t.string :password_digest<%= attribute.inject_options %>
+<% else -%>
+ t.<%= attribute.type %> :<%= attribute.name %><%= attribute.inject_options %>
+<% end -%>
+<% end -%>
+<% if options[:timestamps] %>
+ t.timestamps null: false
+<% end -%>
+ end
+<% attributes_with_index.each do |attribute| -%>
+ add_index :<%= table_name %>, :<%= attribute.index_name %><%= attribute.inject_index_options %>
+<% end -%>
+ end
+end
diff --git a/generator_templates/active_record/migration/migration.rb b/generator_templates/active_record/migration/migration.rb
new file mode 100644
index 00000000000..06bdea11367
--- /dev/null
+++ b/generator_templates/active_record/migration/migration.rb
@@ -0,0 +1,55 @@
+# See http://doc.gitlab.com/ce/development/migration_style_guide.html
+# for more information on how to write migrations for GitLab.
+
+class <%= migration_class_name %> < ActiveRecord::Migration
+ include Gitlab::Database::MigrationHelpers
+
+ # When using the methods "add_concurrent_index" or "add_column_with_default"
+ # you must disable the use of transactions as these methods can not run in an
+ # existing transaction. When using "add_concurrent_index" make sure that this
+ # method is the _only_ method called in the migration, any other changes
+ # should go in a separate migration. This ensures that upon failure _only_ the
+ # index creation fails and can be retried or reverted easily.
+ #
+ # To disable transactions uncomment the following line and remove these
+ # comments:
+ # disable_ddl_transaction!
+
+<%- if migration_action == 'add' -%>
+ def change
+<% attributes.each do |attribute| -%>
+ <%- if attribute.reference? -%>
+ add_reference :<%= table_name %>, :<%= attribute.name %><%= attribute.inject_options %>
+ <%- else -%>
+ add_column :<%= table_name %>, :<%= attribute.name %>, :<%= attribute.type %><%= attribute.inject_options %>
+ <%- if attribute.has_index? -%>
+ add_index :<%= table_name %>, :<%= attribute.index_name %><%= attribute.inject_index_options %>
+ <%- end -%>
+ <%- end -%>
+<%- end -%>
+ end
+<%- elsif migration_action == 'join' -%>
+ def change
+ create_join_table :<%= join_tables.first %>, :<%= join_tables.second %> do |t|
+ <%- attributes.each do |attribute| -%>
+ <%= '# ' unless attribute.has_index? -%>t.index <%= attribute.index_name %><%= attribute.inject_index_options %>
+ <%- end -%>
+ end
+ end
+<%- else -%>
+ def change
+<% attributes.each do |attribute| -%>
+<%- if migration_action -%>
+ <%- if attribute.reference? -%>
+ remove_reference :<%= table_name %>, :<%= attribute.name %><%= attribute.inject_options %>
+ <%- else -%>
+ <%- if attribute.has_index? -%>
+ remove_index :<%= table_name %>, :<%= attribute.index_name %><%= attribute.inject_index_options %>
+ <%- end -%>
+ remove_column :<%= table_name %>, :<%= attribute.name %>, :<%= attribute.type %><%= attribute.inject_options %>
+ <%- end -%>
+<%- end -%>
+<%- end -%>
+ end
+<%- end -%>
+end
diff --git a/lib/api/api.rb b/lib/api/api.rb
index 360fb41a721..6cd909f6115 100644
--- a/lib/api/api.rb
+++ b/lib/api/api.rb
@@ -58,5 +58,6 @@ module API
mount ::API::Runners
mount ::API::Licenses
mount ::API::Subscriptions
+ mount ::API::Gitignores
end
end
diff --git a/lib/api/entities.rb b/lib/api/entities.rb
index dbd03ea74fa..31491cf31dd 100644
--- a/lib/api/entities.rb
+++ b/lib/api/entities.rb
@@ -408,6 +408,7 @@ module API
class RunnerDetails < Runner
expose :tag_list
+ expose :run_untagged
expose :version, :revision, :platform, :architecture
expose :contacted_at
expose :token, if: lambda { |runner, options| options[:current_user].is_admin? || !runner.is_shared? }
@@ -456,5 +457,13 @@ module API
expose(:limitations) { |license| license.meta['limitations'] }
expose :content
end
+
+ class GitignoresList < Grape::Entity
+ expose :name
+ end
+
+ class Gitignore < Grape::Entity
+ expose :name, :content
+ end
end
end
diff --git a/lib/api/gitignores.rb b/lib/api/gitignores.rb
new file mode 100644
index 00000000000..270c9501dd2
--- /dev/null
+++ b/lib/api/gitignores.rb
@@ -0,0 +1,29 @@
+module API
+ class Gitignores < Grape::API
+
+ # Get the list of the available gitignore templates
+ #
+ # Example Request:
+ # GET /gitignores
+ get 'gitignores' do
+ present Gitlab::Gitignore.all, with: Entities::GitignoresList
+ end
+
+ # Get the text for a specific gitignore
+ #
+ # Parameters:
+ # name (required) - The name of a license
+ #
+ # Example Request:
+ # GET /gitignores/Elixir
+ #
+ get 'gitignores/:name' do
+ required_attributes! [:name]
+
+ gitignore = Gitlab::Gitignore.find(params[:name])
+ not_found!('.gitignore') unless gitignore
+
+ present gitignore, with: Entities::Gitignore
+ end
+ end
+end
diff --git a/lib/api/notes.rb b/lib/api/notes.rb
index 71a53e6f0d6..d4fcfd3d4d3 100644
--- a/lib/api/notes.rb
+++ b/lib/api/notes.rb
@@ -19,20 +19,24 @@ module API
# GET /projects/:id/issues/:noteable_id/notes
# GET /projects/:id/snippets/:noteable_id/notes
get ":id/#{noteables_str}/:#{noteable_id_str}/notes" do
- @noteable = user_project.send(:"#{noteables_str}").find(params[:"#{noteable_id_str}"])
-
- # We exclude notes that are cross-references and that cannot be viewed
- # by the current user. By doing this exclusion at this level and not
- # at the DB query level (which we cannot in that case), the current
- # page can have less elements than :per_page even if
- # there's more than one page.
- notes =
- # paginate() only works with a relation. This could lead to a
- # mismatch between the pagination headers info and the actual notes
- # array returned, but this is really a edge-case.
- paginate(@noteable.notes).
- reject { |n| n.cross_reference_not_visible_for?(current_user) }
- present notes, with: Entities::Note
+ @noteable = user_project.send(noteables_str.to_sym).find(params[noteable_id_str.to_sym])
+
+ if can?(current_user, noteable_read_ability_name(@noteable), @noteable)
+ # We exclude notes that are cross-references and that cannot be viewed
+ # by the current user. By doing this exclusion at this level and not
+ # at the DB query level (which we cannot in that case), the current
+ # page can have less elements than :per_page even if
+ # there's more than one page.
+ notes =
+ # paginate() only works with a relation. This could lead to a
+ # mismatch between the pagination headers info and the actual notes
+ # array returned, but this is really a edge-case.
+ paginate(@noteable.notes).
+ reject { |n| n.cross_reference_not_visible_for?(current_user) }
+ present notes, with: Entities::Note
+ else
+ not_found!("Notes")
+ end
end
# Get a single +noteable+ note
@@ -45,13 +49,14 @@ module API
# GET /projects/:id/issues/:noteable_id/notes/:note_id
# GET /projects/:id/snippets/:noteable_id/notes/:note_id
get ":id/#{noteables_str}/:#{noteable_id_str}/notes/:note_id" do
- @noteable = user_project.send(:"#{noteables_str}").find(params[:"#{noteable_id_str}"])
+ @noteable = user_project.send(noteables_str.to_sym).find(params[noteable_id_str.to_sym])
@note = @noteable.notes.find(params[:note_id])
+ can_read_note = can?(current_user, noteable_read_ability_name(@noteable), @noteable) && !@note.cross_reference_not_visible_for?(current_user)
- if @note.cross_reference_not_visible_for?(current_user)
- not_found!("Note")
- else
+ if can_read_note
present @note, with: Entities::Note
+ else
+ not_found!("Note")
end
end
@@ -136,5 +141,11 @@ module API
end
end
end
+
+ helpers do
+ def noteable_read_ability_name(noteable)
+ "read_#{noteable.class.to_s.underscore.downcase}".to_sym
+ end
+ end
end
end
diff --git a/lib/api/runners.rb b/lib/api/runners.rb
index 8ec91485b26..4faba9dc87b 100644
--- a/lib/api/runners.rb
+++ b/lib/api/runners.rb
@@ -49,7 +49,7 @@ module API
runner = get_runner(params[:id])
authenticate_update_runner!(runner)
- attrs = attributes_for_keys [:description, :active, :tag_list]
+ attrs = attributes_for_keys [:description, :active, :tag_list, :run_untagged]
if runner.update(attrs)
present runner, with: Entities::RunnerDetails, current_user: current_user
else
diff --git a/lib/backup/manager.rb b/lib/backup/manager.rb
index 4962f5e53ce..7d0608f09da 100644
--- a/lib/backup/manager.rb
+++ b/lib/backup/manager.rb
@@ -157,7 +157,7 @@ module Backup
end
def archives_to_backup
- %w{uploads builds artifacts lfs}.map{ |name| (name + ".tar.gz") unless skipped?(name) }.compact
+ %w{uploads builds artifacts lfs registry}.map{ |name| (name + ".tar.gz") unless skipped?(name) }.compact
end
def folders_to_backup
diff --git a/lib/backup/registry.rb b/lib/backup/registry.rb
new file mode 100644
index 00000000000..67fe0231087
--- /dev/null
+++ b/lib/backup/registry.rb
@@ -0,0 +1,13 @@
+require 'backup/files'
+
+module Backup
+ class Registry < Files
+ def initialize
+ super('registry', Settings.registry.path)
+ end
+
+ def create_files_dir
+ Dir.mkdir(app_files_dir, 0700)
+ end
+ end
+end
diff --git a/lib/banzai/filter/inline_diff_filter.rb b/lib/banzai/filter/inline_diff_filter.rb
new file mode 100644
index 00000000000..9e75edd4d4c
--- /dev/null
+++ b/lib/banzai/filter/inline_diff_filter.rb
@@ -0,0 +1,22 @@
+module Banzai
+ module Filter
+ class InlineDiffFilter < HTML::Pipeline::Filter
+ IGNORED_ANCESTOR_TAGS = %w(pre code tt).to_set
+
+ def call
+ search_text_nodes(doc).each do |node|
+ next if has_ancestor?(node, IGNORED_ANCESTOR_TAGS)
+
+ content = node.to_html
+ content = content.gsub(/(?:\[\-(.*?)\-\]|\{\-(.*?)\-\})/, '<span class="idiff left right deletion">\1\2</span>')
+ content = content.gsub(/(?:\[\+(.*?)\+\]|\{\+(.*?)\+\})/, '<span class="idiff left right addition">\1\2</span>')
+
+ next if html == content
+
+ node.replace(content)
+ end
+ doc
+ end
+ end
+ end
+end
diff --git a/lib/banzai/filter/milestone_reference_filter.rb b/lib/banzai/filter/milestone_reference_filter.rb
index 4cb82178024..dad0768f51b 100644
--- a/lib/banzai/filter/milestone_reference_filter.rb
+++ b/lib/banzai/filter/milestone_reference_filter.rb
@@ -10,11 +10,53 @@ module Banzai
project.milestones.find_by(iid: id)
end
- def url_for_object(issue, project)
+ def references_in(text, pattern = Milestone.reference_pattern)
+ # We'll handle here the references that follow the `reference_pattern`.
+ # Other patterns (for example, the link pattern) are handled by the
+ # default implementation.
+ return super(text, pattern) if pattern != Milestone.reference_pattern
+
+ text.gsub(pattern) do |match|
+ milestone = find_milestone($~[:project], $~[:milestone_iid], $~[:milestone_name])
+
+ if milestone
+ yield match, milestone.iid, $~[:project], $~
+ else
+ match
+ end
+ end
+ end
+
+ def find_milestone(project_ref, milestone_id, milestone_name)
+ project = project_from_ref(project_ref)
+ return unless project
+
+ milestone_params = milestone_params(milestone_id, milestone_name)
+ project.milestones.find_by(milestone_params)
+ end
+
+ def milestone_params(iid, name)
+ if name
+ { name: name.tr('"', '') }
+ else
+ { iid: iid.to_i }
+ end
+ end
+
+ def url_for_object(milestone, project)
h = Gitlab::Routing.url_helpers
h.namespace_project_milestone_url(project.namespace, project, milestone,
only_path: context[:only_path])
end
+
+ def object_link_text(object, matches)
+ if context[:project] == object.project
+ super
+ else
+ "#{escape_once(super)} <i>in #{escape_once(object.project.path_with_namespace)}</i>".
+ html_safe
+ end
+ end
end
end
end
diff --git a/lib/banzai/pipeline/gfm_pipeline.rb b/lib/banzai/pipeline/gfm_pipeline.rb
index ed3cfd6b023..b27ecf3c923 100644
--- a/lib/banzai/pipeline/gfm_pipeline.rb
+++ b/lib/banzai/pipeline/gfm_pipeline.rb
@@ -23,7 +23,8 @@ module Banzai
Filter::LabelReferenceFilter,
Filter::MilestoneReferenceFilter,
- Filter::TaskListFilter
+ Filter::TaskListFilter,
+ Filter::InlineDiffFilter
]
end
diff --git a/lib/ci/api/runners.rb b/lib/ci/api/runners.rb
index 192b1d18a51..0c41f22c7c5 100644
--- a/lib/ci/api/runners.rb
+++ b/lib/ci/api/runners.rb
@@ -28,20 +28,20 @@ module Ci
post "register" do
required_attributes! [:token]
+ attributes = { description: params[:description],
+ tag_list: params[:tag_list] }
+
+ unless params[:run_untagged].nil?
+ attributes[:run_untagged] = params[:run_untagged]
+ end
+
runner =
if runner_registration_token_valid?
# Create shared runner. Requires admin access
- Ci::Runner.create(
- description: params[:description],
- tag_list: params[:tag_list],
- is_shared: true
- )
+ Ci::Runner.create(attributes.merge(is_shared: true))
elsif project = Project.find_by(runners_token: params[:token])
# Create a specific runner for project.
- project.runners.create(
- description: params[:description],
- tag_list: params[:tag_list]
- )
+ project.runners.create(attributes)
end
return forbidden! unless runner
diff --git a/lib/container_registry/blob.rb b/lib/container_registry/blob.rb
new file mode 100644
index 00000000000..4e20dc4f875
--- /dev/null
+++ b/lib/container_registry/blob.rb
@@ -0,0 +1,48 @@
+module ContainerRegistry
+ class Blob
+ attr_reader :repository, :config
+
+ delegate :registry, :client, to: :repository
+
+ def initialize(repository, config)
+ @repository = repository
+ @config = config || {}
+ end
+
+ def valid?
+ digest.present?
+ end
+
+ def path
+ "#{repository.path}@#{digest}"
+ end
+
+ def digest
+ config['digest']
+ end
+
+ def type
+ config['mediaType']
+ end
+
+ def size
+ config['size']
+ end
+
+ def revision
+ digest.split(':')[1]
+ end
+
+ def short_revision
+ revision[0..8]
+ end
+
+ def delete
+ client.delete_blob(repository.name, digest)
+ end
+
+ def data
+ @data ||= client.blob(repository.name, digest, type)
+ end
+ end
+end
diff --git a/lib/container_registry/client.rb b/lib/container_registry/client.rb
new file mode 100644
index 00000000000..4d726692f45
--- /dev/null
+++ b/lib/container_registry/client.rb
@@ -0,0 +1,61 @@
+require 'faraday'
+require 'faraday_middleware'
+
+module ContainerRegistry
+ class Client
+ attr_accessor :uri
+
+ MANIFEST_VERSION = 'application/vnd.docker.distribution.manifest.v2+json'
+
+ def initialize(base_uri, options = {})
+ @base_uri = base_uri
+ @faraday = Faraday.new(@base_uri) do |conn|
+ initialize_connection(conn, options)
+ end
+ end
+
+ def repository_tags(name)
+ @faraday.get("/v2/#{name}/tags/list").body
+ end
+
+ def repository_manifest(name, reference)
+ @faraday.get("/v2/#{name}/manifests/#{reference}").body
+ end
+
+ def repository_tag_digest(name, reference)
+ response = @faraday.head("/v2/#{name}/manifests/#{reference}")
+ response.headers['docker-content-digest'] if response.success?
+ end
+
+ def delete_repository_tag(name, reference)
+ @faraday.delete("/v2/#{name}/manifests/#{reference}").success?
+ end
+
+ def blob(name, digest, type = nil)
+ headers = {}
+ headers['Accept'] = type if type
+ @faraday.get("/v2/#{name}/blobs/#{digest}", nil, headers).body
+ end
+
+ def delete_blob(name, digest)
+ @faraday.delete("/v2/#{name}/blobs/#{digest}").success?
+ end
+
+ private
+
+ def initialize_connection(conn, options)
+ conn.request :json
+ conn.headers['Accept'] = MANIFEST_VERSION
+
+ conn.response :json, content_type: /\bjson$/
+
+ if options[:user] && options[:password]
+ conn.request(:basic_auth, options[:user].to_s, options[:password].to_s)
+ elsif options[:token]
+ conn.request(:authorization, :bearer, options[:token].to_s)
+ end
+
+ conn.adapter :net_http
+ end
+ end
+end
diff --git a/lib/container_registry/config.rb b/lib/container_registry/config.rb
new file mode 100644
index 00000000000..589f9f4380a
--- /dev/null
+++ b/lib/container_registry/config.rb
@@ -0,0 +1,16 @@
+module ContainerRegistry
+ class Config
+ attr_reader :tag, :blob, :data
+
+ def initialize(tag, blob)
+ @tag, @blob = tag, blob
+ @data = JSON.parse(blob.data)
+ end
+
+ def [](key)
+ return unless data
+
+ data[key]
+ end
+ end
+end
diff --git a/lib/container_registry/registry.rb b/lib/container_registry/registry.rb
new file mode 100644
index 00000000000..0e634f6b6ef
--- /dev/null
+++ b/lib/container_registry/registry.rb
@@ -0,0 +1,21 @@
+module ContainerRegistry
+ class Registry
+ attr_reader :uri, :client, :path
+
+ def initialize(uri, options = {})
+ @uri = uri
+ @path = options[:path] || default_path
+ @client = ContainerRegistry::Client.new(uri, options)
+ end
+
+ def repository(name)
+ ContainerRegistry::Repository.new(self, name)
+ end
+
+ private
+
+ def default_path
+ @uri.sub(/^https?:\/\//, '')
+ end
+ end
+end
diff --git a/lib/container_registry/repository.rb b/lib/container_registry/repository.rb
new file mode 100644
index 00000000000..0e4a7cb3cc9
--- /dev/null
+++ b/lib/container_registry/repository.rb
@@ -0,0 +1,48 @@
+module ContainerRegistry
+ class Repository
+ attr_reader :registry, :name
+
+ delegate :client, to: :registry
+
+ def initialize(registry, name)
+ @registry, @name = registry, name
+ end
+
+ def path
+ [registry.path, name].compact.join('/')
+ end
+
+ def tag(tag)
+ ContainerRegistry::Tag.new(self, tag)
+ end
+
+ def manifest
+ return @manifest if defined?(@manifest)
+
+ @manifest = client.repository_tags(name)
+ end
+
+ def valid?
+ manifest.present?
+ end
+
+ def tags
+ return @tags if defined?(@tags)
+ return [] unless manifest && manifest['tags']
+
+ @tags = manifest['tags'].map do |tag|
+ ContainerRegistry::Tag.new(self, tag)
+ end
+ end
+
+ def blob(config)
+ ContainerRegistry::Blob.new(self, config)
+ end
+
+ def delete_tags
+ return unless tags
+
+ tags.all?(&:delete)
+ end
+ end
+end
diff --git a/lib/container_registry/tag.rb b/lib/container_registry/tag.rb
new file mode 100644
index 00000000000..43f8d6dc8c2
--- /dev/null
+++ b/lib/container_registry/tag.rb
@@ -0,0 +1,77 @@
+module ContainerRegistry
+ class Tag
+ attr_reader :repository, :name
+
+ delegate :registry, :client, to: :repository
+
+ def initialize(repository, name)
+ @repository, @name = repository, name
+ end
+
+ def valid?
+ manifest.present?
+ end
+
+ def manifest
+ return @manifest if defined?(@manifest)
+
+ @manifest = client.repository_manifest(repository.name, name)
+ end
+
+ def path
+ "#{repository.path}:#{name}"
+ end
+
+ def [](key)
+ return unless manifest
+
+ manifest[key]
+ end
+
+ def digest
+ return @digest if defined?(@digest)
+
+ @digest = client.repository_tag_digest(repository.name, name)
+ end
+
+ def config_blob
+ return @config_blob if defined?(@config_blob)
+ return unless manifest && manifest['config']
+
+ @config_blob = repository.blob(manifest['config'])
+ end
+
+ def config
+ return unless config_blob
+
+ @config ||= ContainerRegistry::Config.new(self, config_blob)
+ end
+
+ def created_at
+ return unless config
+
+ @created_at ||= DateTime.rfc3339(config['created'])
+ end
+
+ def layers
+ return @layers if defined?(@layers)
+ return unless manifest
+
+ @layers = manifest['layers'].map do |layer|
+ repository.blob(layer)
+ end
+ end
+
+ def total_size
+ return unless layers
+
+ layers.map(&:size).sum
+ end
+
+ def delete
+ return unless digest
+
+ client.delete_repository_tag(repository.name, digest)
+ end
+ end
+end
diff --git a/lib/gitlab/bitbucket_import/project_creator.rb b/lib/gitlab/bitbucket_import/project_creator.rb
index 941f818b847..b90ef0b0fba 100644
--- a/lib/gitlab/bitbucket_import/project_creator.rb
+++ b/lib/gitlab/bitbucket_import/project_creator.rb
@@ -11,7 +11,7 @@ module Gitlab
end
def execute
- project = ::Projects::CreateService.new(
+ ::Projects::CreateService.new(
current_user,
name: repo["name"],
path: repo["slug"],
@@ -21,11 +21,8 @@ module Gitlab
import_type: "bitbucket",
import_source: "#{repo["owner"]}/#{repo["slug"]}",
import_url: "ssh://git@bitbucket.org/#{repo["owner"]}/#{repo["slug"]}.git",
+ import_data: { credentials: { bb_session: session_data } }
).execute
-
- project.create_or_update_import_data(credentials: { bb_session: session_data })
-
- project
end
end
end
diff --git a/lib/gitlab/database/migration_helpers.rb b/lib/gitlab/database/migration_helpers.rb
new file mode 100644
index 00000000000..fd14234c558
--- /dev/null
+++ b/lib/gitlab/database/migration_helpers.rb
@@ -0,0 +1,142 @@
+module Gitlab
+ module Database
+ module MigrationHelpers
+ # Creates a new index, concurrently when supported
+ #
+ # On PostgreSQL this method creates an index concurrently, on MySQL this
+ # creates a regular index.
+ #
+ # Example:
+ #
+ # add_concurrent_index :users, :some_column
+ #
+ # See Rails' `add_index` for more info on the available arguments.
+ def add_concurrent_index(*args)
+ if transaction_open?
+ raise 'add_concurrent_index can not be run inside a transaction, ' \
+ 'you can disable transactions by calling disable_ddl_transaction! ' \
+ 'in the body of your migration class'
+ end
+
+ if Database.postgresql?
+ args << { algorithm: :concurrently }
+ end
+
+ add_index(*args)
+ end
+
+ # Updates the value of a column in batches.
+ #
+ # This method updates the table in batches of 5% of the total row count.
+ # Any data inserted while running this method (or after it has finished
+ # running) is _not_ updated automatically.
+ #
+ # This method _only_ updates rows where the column's value is set to NULL.
+ #
+ # table - The name of the table.
+ # column - The name of the column to update.
+ # value - The value for the column.
+ def update_column_in_batches(table, column, value)
+ quoted_table = quote_table_name(table)
+ quoted_column = quote_column_name(column)
+
+ ##
+ # Workaround for #17711
+ #
+ # It looks like for MySQL `ActiveRecord::Base.conntection.quote(true)`
+ # returns correct value (1), but `ActiveRecord::Migration.new.quote`
+ # returns incorrect value ('true'), which causes migrations to fail.
+ #
+ quoted_value = connection.quote(value)
+ processed = 0
+
+ total = exec_query("SELECT COUNT(*) AS count FROM #{quoted_table}").
+ to_hash.
+ first['count'].
+ to_i
+
+ # Update in batches of 5%
+ batch_size = ((total / 100.0) * 5.0).ceil
+
+ while processed < total
+ start_row = exec_query(%Q{
+ SELECT id
+ FROM #{quoted_table}
+ ORDER BY id ASC
+ LIMIT 1 OFFSET #{processed}
+ }).to_hash.first
+
+ stop_row = exec_query(%Q{
+ SELECT id
+ FROM #{quoted_table}
+ ORDER BY id ASC
+ LIMIT 1 OFFSET #{processed + batch_size}
+ }).to_hash.first
+
+ query = %Q{
+ UPDATE #{quoted_table}
+ SET #{quoted_column} = #{quoted_value}
+ WHERE id >= #{start_row['id']}
+ }
+
+ if stop_row
+ query += " AND id < #{stop_row['id']}"
+ end
+
+ execute(query)
+
+ processed += batch_size
+ end
+ end
+
+ # Adds a column with a default value without locking an entire table.
+ #
+ # This method runs the following steps:
+ #
+ # 1. Add the column with a default value of NULL.
+ # 2. Update all existing rows in batches.
+ # 3. Change the default value of the column to the specified value.
+ # 4. Update any remaining rows.
+ #
+ # These steps ensure a column can be added to a large and commonly used
+ # table without locking the entire table for the duration of the table
+ # modification.
+ #
+ # table - The name of the table to update.
+ # column - The name of the column to add.
+ # type - The column type (e.g. `:integer`).
+ # default - The default value for the column.
+ # allow_null - When set to `true` the column will allow NULL values, the
+ # default is to not allow NULL values.
+ def add_column_with_default(table, column, type, default:, allow_null: false)
+ if transaction_open?
+ raise 'add_column_with_default can not be run inside a transaction, ' \
+ 'you can disable transactions by calling disable_ddl_transaction! ' \
+ 'in the body of your migration class'
+ end
+
+ transaction do
+ add_column(table, column, type, default: nil)
+
+ # Changing the default before the update ensures any newly inserted
+ # rows already use the proper default value.
+ change_column_default(table, column, default)
+ end
+
+ begin
+ transaction do
+ update_column_in_batches(table, column, default)
+ end
+ # We want to rescue _all_ exceptions here, even those that don't inherit
+ # from StandardError.
+ rescue Exception => error # rubocop: disable all
+ remove_column(table, column)
+
+ raise error
+ end
+
+ change_column_null(table, column, false) unless allow_null
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/diff/inline_diff_marker.rb b/lib/gitlab/diff/inline_diff_marker.rb
index dccb717e95d..87a9b1e23ac 100644
--- a/lib/gitlab/diff/inline_diff_marker.rb
+++ b/lib/gitlab/diff/inline_diff_marker.rb
@@ -1,6 +1,11 @@
module Gitlab
module Diff
class InlineDiffMarker
+ MARKDOWN_SYMBOLS = {
+ addition: "+",
+ deletion: "-"
+ }
+
attr_accessor :raw_line, :rich_line
def initialize(raw_line, rich_line = raw_line)
@@ -8,7 +13,7 @@ module Gitlab
@rich_line = ERB::Util.html_escape(rich_line)
end
- def mark(line_inline_diffs)
+ def mark(line_inline_diffs, mode: nil, markdown: false)
return rich_line unless line_inline_diffs
marker_ranges = []
@@ -20,13 +25,22 @@ module Gitlab
end
offset = 0
- # Mark each range
- marker_ranges.each_with_index do |range, i|
- class_names = ["idiff"]
- class_names << "left" if i == 0
- class_names << "right" if i == marker_ranges.length - 1
- offset = insert_around_range(rich_line, range, "<span class='#{class_names.join(" ")}'>", "</span>", offset)
+ # Mark each range
+ marker_ranges.each_with_index do |range, index|
+ before_content =
+ if markdown
+ "{#{MARKDOWN_SYMBOLS[mode]}"
+ else
+ "<span class='#{html_class_names(marker_ranges, mode, index)}'>"
+ end
+ after_content =
+ if markdown
+ "#{MARKDOWN_SYMBOLS[mode]}}"
+ else
+ "</span>"
+ end
+ offset = insert_around_range(rich_line, range, before_content, after_content, offset)
end
rich_line.html_safe
@@ -34,6 +48,14 @@ module Gitlab
private
+ def html_class_names(marker_ranges, mode, index)
+ class_names = ["idiff"]
+ class_names << "left" if index == 0
+ class_names << "right" if index == marker_ranges.length - 1
+ class_names << mode if mode
+ class_names.join(" ")
+ end
+
# Mapping of character positions in the raw line, to the rich (highlighted) line
def position_mapping
@position_mapping ||= begin
diff --git a/lib/gitlab/email/message/repository_push.rb b/lib/gitlab/email/message/repository_push.rb
index 2c91a0487c3..e2fee6b9f3e 100644
--- a/lib/gitlab/email/message/repository_push.rb
+++ b/lib/gitlab/email/message/repository_push.rb
@@ -5,6 +5,7 @@ module Gitlab
attr_reader :author_id, :ref, :action
include Gitlab::Routing.url_helpers
+ include DiffHelper
delegate :namespace, :name_with_namespace, to: :project, prefix: :project
delegate :name, to: :author, prefix: :author
@@ -36,7 +37,7 @@ module Gitlab
end
def diffs
- @diffs ||= (compare.diffs if compare)
+ @diffs ||= (safe_diff_files(compare.diffs, diff_refs) if compare)
end
def diffs_count
@@ -47,6 +48,10 @@ module Gitlab
@opts[:compare]
end
+ def diff_refs
+ @opts[:diff_refs]
+ end
+
def compare_timeout
diffs.overflow? if diffs
end
diff --git a/lib/gitlab/fogbugz_import/project_creator.rb b/lib/gitlab/fogbugz_import/project_creator.rb
index 3840765db87..1918d5b208d 100644
--- a/lib/gitlab/fogbugz_import/project_creator.rb
+++ b/lib/gitlab/fogbugz_import/project_creator.rb
@@ -12,7 +12,7 @@ module Gitlab
end
def execute
- project = ::Projects::CreateService.new(
+ ::Projects::CreateService.new(
current_user,
name: repo.safe_name,
path: repo.path,
@@ -21,12 +21,9 @@ module Gitlab
visibility_level: Gitlab::VisibilityLevel::INTERNAL,
import_type: 'fogbugz',
import_source: repo.name,
- import_url: Project::UNKNOWN_IMPORT_URL
+ import_url: Project::UNKNOWN_IMPORT_URL,
+ import_data: { data: { 'repo' => repo.raw_data, 'user_map' => user_map }, credentials: { fb_session: fb_session } }
).execute
-
- project.create_or_update_import_data(data: { 'repo' => repo.raw_data, 'user_map' => user_map }, credentials: { fb_session: fb_session })
-
- project
end
end
end
diff --git a/lib/gitlab/gitignore.rb b/lib/gitlab/gitignore.rb
new file mode 100644
index 00000000000..f46b43b61a4
--- /dev/null
+++ b/lib/gitlab/gitignore.rb
@@ -0,0 +1,56 @@
+module Gitlab
+ class Gitignore
+ FILTER_REGEX = /\.gitignore\z/.freeze
+
+ def initialize(path)
+ @path = path
+ end
+
+ def name
+ File.basename(@path, '.gitignore')
+ end
+
+ def content
+ File.read(@path)
+ end
+
+ class << self
+ def all
+ languages_frameworks + global
+ end
+
+ def find(key)
+ file_name = "#{key}.gitignore"
+
+ directory = select_directory(file_name)
+ directory ? new(File.join(directory, file_name)) : nil
+ end
+
+ def global
+ files_for_folder(global_dir).map { |file| new(File.join(global_dir, file)) }
+ end
+
+ def languages_frameworks
+ files_for_folder(gitignore_dir).map { |file| new(File.join(gitignore_dir, file)) }
+ end
+
+ private
+
+ def select_directory(file_name)
+ [gitignore_dir, global_dir].find { |dir| File.exist?(File.join(dir, file_name)) }
+ end
+
+ def global_dir
+ File.join(gitignore_dir, 'Global')
+ end
+
+ def gitignore_dir
+ Rails.root.join('vendor/gitignore')
+ end
+
+ def files_for_folder(dir)
+ Dir.glob("#{dir.to_s}/*.gitignore").map { |file| file.gsub(FILTER_REGEX, '') }
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/gitlab_import/importer.rb b/lib/gitlab/gitlab_import/importer.rb
index 96717b42bae..3e51c06877e 100644
--- a/lib/gitlab/gitlab_import/importer.rb
+++ b/lib/gitlab/gitlab_import/importer.rb
@@ -5,7 +5,7 @@ module Gitlab
def initialize(project)
@project = project
- credentials = import_data
+ credentials = project.import_data
if credentials && credentials[:password]
@client = Client.new(credentials[:password])
@formatter = Gitlab::ImportFormatter.new
diff --git a/lib/gitlab/google_code_import/project_creator.rb b/lib/gitlab/google_code_import/project_creator.rb
index 0abb7a64c17..326cfcaa8af 100644
--- a/lib/gitlab/google_code_import/project_creator.rb
+++ b/lib/gitlab/google_code_import/project_creator.rb
@@ -11,7 +11,7 @@ module Gitlab
end
def execute
- project = ::Projects::CreateService.new(
+ ::Projects::CreateService.new(
current_user,
name: repo.name,
path: repo.name,
@@ -21,12 +21,9 @@ module Gitlab
visibility_level: Gitlab::VisibilityLevel::PUBLIC,
import_type: "google_code",
import_source: repo.name,
- import_url: repo.import_url
+ import_url: repo.import_url,
+ import_data: { data: { 'repo' => repo.raw_data, 'user_map' => user_map } }
).execute
-
- project.create_or_update_import_data(data: { 'repo' => repo.raw_data, 'user_map' => user_map })
-
- project
end
end
end
diff --git a/lib/gitlab/regex.rb b/lib/gitlab/regex.rb
index ace906a6f59..1cbd6d945a0 100644
--- a/lib/gitlab/regex.rb
+++ b/lib/gitlab/regex.rb
@@ -96,5 +96,9 @@ module Gitlab
(?<![\/.]) (?# rule #6-7)
}x.freeze
end
+
+ def container_registry_reference_regex
+ git_reference_regex
+ end
end
end
diff --git a/lib/gitlab/sanitizers/svg.rb b/lib/gitlab/sanitizers/svg.rb
index b98589dff89..5e95f6c0529 100644
--- a/lib/gitlab/sanitizers/svg.rb
+++ b/lib/gitlab/sanitizers/svg.rb
@@ -1,5 +1,3 @@
-require_relative "svg/whitelist"
-
module Gitlab
module Sanitizers
module SVG
@@ -12,14 +10,14 @@ module Gitlab
DATA_ATTR_PATTERN = /\Adata-(?!xml)[a-z_][\w.\u00E0-\u00F6\u00F8-\u017F\u01DD-\u02AF-]*\z/u
def scrub(node)
- unless ALLOWED_ELEMENTS.include?(node.name)
+ unless Whitelist::ALLOWED_ELEMENTS.include?(node.name)
node.unlink
else
node.attributes.each do |attr_name, attr|
- valid_attributes = ALLOWED_ATTRIBUTES[node.name]
+ valid_attributes = Whitelist::ALLOWED_ATTRIBUTES[node.name]
unless valid_attributes && valid_attributes.include?(attr_name)
- if ALLOWED_DATA_ATTRIBUTES_IN_ELEMENTS.include?(node.name) &&
+ if Whitelist::ALLOWED_DATA_ATTRIBUTES_IN_ELEMENTS.include?(node.name) &&
attr_name.start_with?('data-')
# Arbitrary data attributes are allowed. Verify that the attribute
# is a valid data attribute.
diff --git a/lib/gitlab/sanitizers/svg/whitelist.rb b/lib/gitlab/sanitizers/svg/whitelist.rb
index 917e795b29e..7b6b70d8dbc 100644
--- a/lib/gitlab/sanitizers/svg/whitelist.rb
+++ b/lib/gitlab/sanitizers/svg/whitelist.rb
@@ -4,7 +4,8 @@
module Gitlab
module Sanitizers
module SVG
- ALLOWED_ELEMENTS = %w[
+ class Whitelist
+ ALLOWED_ELEMENTS = %w[
a altGlyph altGlyphDef altGlyphItem animate
animateColor animateMotion animateTransform circle clipPath color-profile
cursor defs desc ellipse feBlend feColorMatrix feComponentTransfer
@@ -18,90 +19,91 @@ module Gitlab
script set stop style svg switch symbol text textPath title tref tspan use
view vkern].freeze
- ALLOWED_DATA_ATTRIBUTES_IN_ELEMENTS = %w[svg].freeze
+ ALLOWED_DATA_ATTRIBUTES_IN_ELEMENTS = %w[svg].freeze
- ALLOWED_ATTRIBUTES = {
- 'a' => %w[alignment-baseline baseline-shift class clip clip-path clip-rule color color-interpolation color-interpolation-filters color-profile color-rendering cursor direction display dominant-baseline enable-background externalResourcesRequired fill fill-opacity fill-rule filter flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight glyph-orientation-horizontal glyph-orientation-vertical id image-rendering kerning letter-spacing lighting-color marker-end marker-mid marker-start mask onactivate onclick onfocusin onfocusout onload onmousedown onmousemove onmouseout onmouseover onmouseup opacity overflow pointer-events requiredExtensions requiredFeatures shape-rendering stop-color stop-opacity stroke stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width style systemLanguage target text-anchor text-decoration text-rendering transform unicode-bidi visibility word-spacing writing-mode xlink:actuate xlink:arcrole xlink:href xlink:role xlink:show xlink:title xlink:type xml:base xml:lang xml:space],
- 'altGlyph' => %w[alignment-baseline baseline-shift class clip clip-path clip-rule color color-interpolation color-interpolation-filters color-profile color-rendering cursor direction display dominant-baseline dx dy enable-background externalResourcesRequired fill fill-opacity fill-rule filter flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight format glyph-orientation-horizontal glyph-orientation-vertical glyphRef id image-rendering kerning letter-spacing lighting-color marker-end marker-mid marker-start mask onactivate onclick onfocusin onfocusout onload onmousedown onmousemove onmouseout onmouseover onmouseup opacity overflow pointer-events requiredExtensions requiredFeatures rotate shape-rendering stop-color stop-opacity stroke stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width style systemLanguage text-anchor text-decoration text-rendering unicode-bidi visibility word-spacing writing-mode x xlink:actuate xlink:arcrole xlink:href xlink:role xlink:show xlink:title xlink:type xml:base xml:lang xml:space y],
- 'altGlyphDef' => %w[id xml:base xml:lang xml:space],
- 'altGlyphItem' => %w[id xml:base xml:lang xml:space],
- 'animate' => %w[accumulate additive alignment-baseline attributeName attributeType baseline-shift begin by calcMode clip clip-path clip-rule color color-interpolation color-interpolation-filters color-profile color-rendering cursor direction display dominant-baseline dur enable-background end externalResourcesRequired fill fill-opacity fill-rule filter flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight from glyph-orientation-horizontal glyph-orientation-vertical id image-rendering kerning keySplines keyTimes letter-spacing lighting-color marker-end marker-mid marker-start mask max min onbegin onend onload onrepeat opacity overflow pointer-events repeatCount repeatDur requiredExtensions requiredFeatures restart shape-rendering stop-color stop-opacity stroke stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width systemLanguage text-anchor text-decoration text-rendering to unicode-bidi values visibility word-spacing writing-mode xlink:actuate xlink:arcrole xlink:href xlink:role xlink:show xlink:title xlink:type xml:base xml:lang xml:space],
- 'animateColor' => %w[accumulate additive alignment-baseline attributeName attributeType baseline-shift begin by calcMode clip clip-path clip-rule color color-interpolation color-interpolation-filters color-profile color-rendering cursor direction display dominant-baseline dur enable-background end externalResourcesRequired fill fill-opacity fill-rule filter flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight from glyph-orientation-horizontal glyph-orientation-vertical id image-rendering kerning keySplines keyTimes letter-spacing lighting-color marker-end marker-mid marker-start mask max min onbegin onend onload onrepeat opacity overflow pointer-events repeatCount repeatDur requiredExtensions requiredFeatures restart shape-rendering stop-color stop-opacity stroke stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width systemLanguage text-anchor text-decoration text-rendering to unicode-bidi values visibility word-spacing writing-mode xlink:actuate xlink:arcrole xlink:href xlink:role xlink:show xlink:title xlink:type xml:base xml:lang xml:space],
- 'animateMotion' => %w[accumulate additive begin by calcMode dur end externalResourcesRequired fill from id keyPoints keySplines keyTimes max min onbegin onend onload onrepeat origin path repeatCount repeatDur requiredExtensions requiredFeatures restart rotate systemLanguage to values xlink:actuate xlink:arcrole xlink:href xlink:role xlink:show xlink:title xlink:type xml:base xml:lang xml:space],
- 'animateTransform' => %w[accumulate additive attributeName attributeType begin by calcMode dur end externalResourcesRequired fill from id keySplines keyTimes max min onbegin onend onload onrepeat repeatCount repeatDur requiredExtensions requiredFeatures restart systemLanguage to type values xlink:actuate xlink:arcrole xlink:href xlink:role xlink:show xlink:title xlink:type xml:base xml:lang xml:space],
- 'circle' => %w[alignment-baseline baseline-shift class clip clip-path clip-rule color color-interpolation color-interpolation-filters color-profile color-rendering cursor cx cy direction display dominant-baseline enable-background externalResourcesRequired fill fill-opacity fill-rule filter flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight glyph-orientation-horizontal glyph-orientation-vertical id image-rendering kerning letter-spacing lighting-color marker-end marker-mid marker-start mask onactivate onclick onfocusin onfocusout onload onmousedown onmousemove onmouseout onmouseover onmouseup opacity overflow pointer-events r requiredExtensions requiredFeatures shape-rendering stop-color stop-opacity stroke stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width style systemLanguage text-anchor text-decoration text-rendering transform unicode-bidi visibility word-spacing writing-mode xml:base xml:lang xml:space],
- 'clipPath' => %w[alignment-baseline baseline-shift class clip clip-path clip-rule clipPathUnits color color-interpolation color-interpolation-filters color-profile color-rendering cursor direction display dominant-baseline enable-background externalResourcesRequired fill fill-opacity fill-rule filter flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight glyph-orientation-horizontal glyph-orientation-vertical id image-rendering kerning letter-spacing lighting-color marker-end marker-mid marker-start mask opacity overflow pointer-events requiredExtensions requiredFeatures shape-rendering stop-color stop-opacity stroke stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width style systemLanguage text-anchor text-decoration text-rendering transform unicode-bidi visibility word-spacing writing-mode xml:base xml:lang xml:space],
- 'color-profile' => %w[id local name rendering-intent xlink:actuate xlink:arcrole xlink:href xlink:role xlink:show xlink:title xlink:type xml:base xml:lang xml:space],
- 'cursor' => %w[externalResourcesRequired id requiredExtensions requiredFeatures systemLanguage x xlink:actuate xlink:arcrole xlink:href xlink:role xlink:show xlink:title xlink:type xml:base xml:lang xml:space y],
- 'defs' => %w[alignment-baseline baseline-shift class clip clip-path clip-rule color color-interpolation color-interpolation-filters color-profile color-rendering cursor direction display dominant-baseline enable-background externalResourcesRequired fill fill-opacity fill-rule filter flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight glyph-orientation-horizontal glyph-orientation-vertical id image-rendering kerning letter-spacing lighting-color marker-end marker-mid marker-start mask onactivate onclick onfocusin onfocusout onload onmousedown onmousemove onmouseout onmouseover onmouseup opacity overflow pointer-events requiredExtensions requiredFeatures shape-rendering stop-color stop-opacity stroke stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width style systemLanguage text-anchor text-decoration text-rendering transform unicode-bidi visibility word-spacing writing-mode xml:base xml:lang xml:space],
- 'desc' => %w[class id style xml:base xml:lang xml:space],
- 'ellipse' => %w[alignment-baseline baseline-shift class clip clip-path clip-rule color color-interpolation color-interpolation-filters color-profile color-rendering cursor cx cy direction display dominant-baseline enable-background externalResourcesRequired fill fill-opacity fill-rule filter flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight glyph-orientation-horizontal glyph-orientation-vertical id image-rendering kerning letter-spacing lighting-color marker-end marker-mid marker-start mask onactivate onclick onfocusin onfocusout onload onmousedown onmousemove onmouseout onmouseover onmouseup opacity overflow pointer-events requiredExtensions requiredFeatures rx ry shape-rendering stop-color stop-opacity stroke stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width style systemLanguage text-anchor text-decoration text-rendering transform unicode-bidi visibility word-spacing writing-mode xml:base xml:lang xml:space],
- 'feBlend' => %w[alignment-baseline baseline-shift class clip clip-path clip-rule color color-interpolation color-interpolation-filters color-profile color-rendering cursor direction display dominant-baseline enable-background fill fill-opacity fill-rule filter flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight glyph-orientation-horizontal glyph-orientation-vertical height id image-rendering in in2 kerning letter-spacing lighting-color marker-end marker-mid marker-start mask mode opacity overflow pointer-events result shape-rendering stop-color stop-opacity stroke stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width style text-anchor text-decoration text-rendering unicode-bidi visibility width word-spacing writing-mode x xml:base xml:lang xml:space y],
- 'feColorMatrix' => %w[alignment-baseline baseline-shift class clip clip-path clip-rule color color-interpolation color-interpolation-filters color-profile color-rendering cursor direction display dominant-baseline enable-background fill fill-opacity fill-rule filter flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight glyph-orientation-horizontal glyph-orientation-vertical height id image-rendering in kerning letter-spacing lighting-color marker-end marker-mid marker-start mask opacity overflow pointer-events result shape-rendering stop-color stop-opacity stroke stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width style text-anchor text-decoration text-rendering type unicode-bidi values visibility width word-spacing writing-mode x xml:base xml:lang xml:space y],
- 'feComponentTransfer' => %w[alignment-baseline baseline-shift class clip clip-path clip-rule color color-interpolation color-interpolation-filters color-profile color-rendering cursor direction display dominant-baseline enable-background fill fill-opacity fill-rule filter flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight glyph-orientation-horizontal glyph-orientation-vertical height id image-rendering in kerning letter-spacing lighting-color marker-end marker-mid marker-start mask opacity overflow pointer-events result shape-rendering stop-color stop-opacity stroke stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width style text-anchor text-decoration text-rendering unicode-bidi visibility width word-spacing writing-mode x xml:base xml:lang xml:space y],
- 'feComposite' => %w[alignment-baseline baseline-shift class clip clip-path clip-rule color color-interpolation color-interpolation-filters color-profile color-rendering cursor direction display dominant-baseline enable-background fill fill-opacity fill-rule filter flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight glyph-orientation-horizontal glyph-orientation-vertical height id image-rendering in in2 k1 k2 k3 k4 kerning letter-spacing lighting-color marker-end marker-mid marker-start mask opacity operator overflow pointer-events result shape-rendering stop-color stop-opacity stroke stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width style text-anchor text-decoration text-rendering unicode-bidi visibility width word-spacing writing-mode x xml:base xml:lang xml:space y],
- 'feConvolveMatrix' => %w[alignment-baseline baseline-shift bias class clip clip-path clip-rule color color-interpolation color-interpolation-filters color-profile color-rendering cursor direction display divisor dominant-baseline edgeMode enable-background fill fill-opacity fill-rule filter flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight glyph-orientation-horizontal glyph-orientation-vertical height id image-rendering in kernelMatrix kernelUnitLength kerning letter-spacing lighting-color marker-end marker-mid marker-start mask opacity order overflow pointer-events preserveAlpha result shape-rendering stop-color stop-opacity stroke stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width style targetX targetY text-anchor text-decoration text-rendering unicode-bidi visibility width word-spacing writing-mode x xml:base xml:lang xml:space y],
- 'feDiffuseLighting' => %w[alignment-baseline baseline-shift class clip clip-path clip-rule color color-interpolation color-interpolation-filters color-profile color-rendering cursor diffuseConstant direction display dominant-baseline enable-background fill fill-opacity fill-rule filter flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight glyph-orientation-horizontal glyph-orientation-vertical height id image-rendering in kernelUnitLength kerning letter-spacing lighting-color marker-end marker-mid marker-start mask opacity overflow pointer-events result shape-rendering stop-color stop-opacity stroke stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width style surfaceScale text-anchor text-decoration text-rendering unicode-bidi visibility width word-spacing writing-mode x xml:base xml:lang xml:space y],
- 'feDisplacementMap' => %w[alignment-baseline baseline-shift class clip clip-path clip-rule color color-interpolation color-interpolation-filters color-profile color-rendering cursor direction display dominant-baseline enable-background fill fill-opacity fill-rule filter flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight glyph-orientation-horizontal glyph-orientation-vertical height id image-rendering in in2 kerning letter-spacing lighting-color marker-end marker-mid marker-start mask opacity overflow pointer-events result scale shape-rendering stop-color stop-opacity stroke stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width style text-anchor text-decoration text-rendering unicode-bidi visibility width word-spacing writing-mode x xChannelSelector xml:base xml:lang xml:space y yChannelSelector],
- 'feDistantLight' => %w[azimuth elevation id xml:base xml:lang xml:space],
- 'feFlood' => %w[alignment-baseline baseline-shift class clip clip-path clip-rule color color-interpolation color-interpolation-filters color-profile color-rendering cursor direction display dominant-baseline enable-background fill fill-opacity fill-rule filter flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight glyph-orientation-horizontal glyph-orientation-vertical height id image-rendering kerning letter-spacing lighting-color marker-end marker-mid marker-start mask opacity overflow pointer-events result shape-rendering stop-color stop-opacity stroke stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width style text-anchor text-decoration text-rendering unicode-bidi visibility width word-spacing writing-mode x xml:base xml:lang xml:space y],
- 'feFuncA' => %w[amplitude exponent id intercept offset slope tableValues type xml:base xml:lang xml:space],
- 'feFuncB' => %w[amplitude exponent id intercept offset slope tableValues type xml:base xml:lang xml:space],
- 'feFuncG' => %w[amplitude exponent id intercept offset slope tableValues type xml:base xml:lang xml:space],
- 'feFuncR' => %w[amplitude exponent id intercept offset slope tableValues type xml:base xml:lang xml:space],
- 'feGaussianBlur' => %w[alignment-baseline baseline-shift class clip clip-path clip-rule color color-interpolation color-interpolation-filters color-profile color-rendering cursor direction display dominant-baseline enable-background fill fill-opacity fill-rule filter flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight glyph-orientation-horizontal glyph-orientation-vertical height id image-rendering in kerning letter-spacing lighting-color marker-end marker-mid marker-start mask opacity overflow pointer-events result shape-rendering stdDeviation stop-color stop-opacity stroke stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width style text-anchor text-decoration text-rendering unicode-bidi visibility width word-spacing writing-mode x xml:base xml:lang xml:space y],
- 'feImage' => %w[alignment-baseline baseline-shift class clip clip-path clip-rule color color-interpolation color-interpolation-filters color-profile color-rendering cursor direction display dominant-baseline enable-background externalResourcesRequired fill fill-opacity fill-rule filter flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight glyph-orientation-horizontal glyph-orientation-vertical height id image-rendering kerning letter-spacing lighting-color marker-end marker-mid marker-start mask opacity overflow pointer-events preserveAspectRatio result shape-rendering stop-color stop-opacity stroke stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width style text-anchor text-decoration text-rendering unicode-bidi visibility width word-spacing writing-mode x xlink:actuate xlink:arcrole xlink:href xlink:role xlink:show xlink:title xlink:type xml:base xml:lang xml:space y],
- 'feMerge' => %w[alignment-baseline baseline-shift class clip clip-path clip-rule color color-interpolation color-interpolation-filters color-profile color-rendering cursor direction display dominant-baseline enable-background fill fill-opacity fill-rule filter flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight glyph-orientation-horizontal glyph-orientation-vertical height id image-rendering kerning letter-spacing lighting-color marker-end marker-mid marker-start mask opacity overflow pointer-events result shape-rendering stop-color stop-opacity stroke stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width style text-anchor text-decoration text-rendering unicode-bidi visibility width word-spacing writing-mode x xml:base xml:lang xml:space y],
- 'feMergeNode' => %w[id xml:base xml:lang xml:space],
- 'feMorphology' => %w[alignment-baseline baseline-shift class clip clip-path clip-rule color color-interpolation color-interpolation-filters color-profile color-rendering cursor direction display dominant-baseline enable-background fill fill-opacity fill-rule filter flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight glyph-orientation-horizontal glyph-orientation-vertical height id image-rendering in kerning letter-spacing lighting-color marker-end marker-mid marker-start mask opacity operator overflow pointer-events radius result shape-rendering stop-color stop-opacity stroke stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width style text-anchor text-decoration text-rendering unicode-bidi visibility width word-spacing writing-mode x xml:base xml:lang xml:space y],
- 'feOffset' => %w[alignment-baseline baseline-shift class clip clip-path clip-rule color color-interpolation color-interpolation-filters color-profile color-rendering cursor direction display dominant-baseline dx dy enable-background fill fill-opacity fill-rule filter flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight glyph-orientation-horizontal glyph-orientation-vertical height id image-rendering in kerning letter-spacing lighting-color marker-end marker-mid marker-start mask opacity overflow pointer-events result shape-rendering stop-color stop-opacity stroke stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width style text-anchor text-decoration text-rendering unicode-bidi visibility width word-spacing writing-mode x xml:base xml:lang xml:space y],
- 'fePointLight' => %w[id x xml:base xml:lang xml:space y z],
- 'feSpecularLighting' => %w[alignment-baseline baseline-shift class clip clip-path clip-rule color color-interpolation color-interpolation-filters color-profile color-rendering cursor direction display dominant-baseline enable-background fill fill-opacity fill-rule filter flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight glyph-orientation-horizontal glyph-orientation-vertical height id image-rendering in kernelUnitLength kerning letter-spacing lighting-color marker-end marker-mid marker-start mask opacity overflow pointer-events result shape-rendering specularConstant specularExponent stop-color stop-opacity stroke stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width style surfaceScale text-anchor text-decoration text-rendering unicode-bidi visibility width word-spacing writing-mode x xml:base xml:lang xml:space y],
- 'feSpotLight' => %w[id limitingConeAngle pointsAtX pointsAtY pointsAtZ specularExponent x xml:base xml:lang xml:space y z],
- 'feTile' => %w[alignment-baseline baseline-shift class clip clip-path clip-rule color color-interpolation color-interpolation-filters color-profile color-rendering cursor direction display dominant-baseline enable-background fill fill-opacity fill-rule filter flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight glyph-orientation-horizontal glyph-orientation-vertical height id image-rendering in kerning letter-spacing lighting-color marker-end marker-mid marker-start mask opacity overflow pointer-events result shape-rendering stop-color stop-opacity stroke stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width style text-anchor text-decoration text-rendering unicode-bidi visibility width word-spacing writing-mode x xml:base xml:lang xml:space y],
- 'feTurbulence' => %w[alignment-baseline baseFrequency baseline-shift class clip clip-path clip-rule color color-interpolation color-interpolation-filters color-profile color-rendering cursor direction display dominant-baseline enable-background fill fill-opacity fill-rule filter flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight glyph-orientation-horizontal glyph-orientation-vertical height id image-rendering kerning letter-spacing lighting-color marker-end marker-mid marker-start mask numOctaves opacity overflow pointer-events result seed shape-rendering stitchTiles stop-color stop-opacity stroke stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width style text-anchor text-decoration text-rendering type unicode-bidi visibility width word-spacing writing-mode x xml:base xml:lang xml:space y],
- 'filter' => %w[alignment-baseline baseline-shift class clip clip-path clip-rule color color-interpolation color-interpolation-filters color-profile color-rendering cursor direction display dominant-baseline enable-background externalResourcesRequired fill fill-opacity fill-rule filter filterRes filterUnits flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight glyph-orientation-horizontal glyph-orientation-vertical height id image-rendering kerning letter-spacing lighting-color marker-end marker-mid marker-start mask opacity overflow pointer-events primitiveUnits shape-rendering stop-color stop-opacity stroke stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width style text-anchor text-decoration text-rendering unicode-bidi visibility width word-spacing writing-mode x xlink:actuate xlink:arcrole xlink:href xlink:role xlink:show xlink:title xlink:type xml:base xml:lang xml:space y],
- 'font' => %w[alignment-baseline baseline-shift class clip clip-path clip-rule color color-interpolation color-interpolation-filters color-profile color-rendering cursor direction display dominant-baseline enable-background externalResourcesRequired fill fill-opacity fill-rule filter flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight glyph-orientation-horizontal glyph-orientation-vertical horiz-adv-x horiz-origin-x horiz-origin-y id image-rendering kerning letter-spacing lighting-color marker-end marker-mid marker-start mask opacity overflow pointer-events shape-rendering stop-color stop-opacity stroke stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width style text-anchor text-decoration text-rendering unicode-bidi vert-adv-y vert-origin-x vert-origin-y visibility word-spacing writing-mode xml:base xml:lang xml:space],
- 'font-face' => %w[accent-height alphabetic ascent bbox cap-height descent font-family font-size font-stretch font-style font-variant font-weight hanging id ideographic mathematical overline-position overline-thickness panose-1 slope stemh stemv strikethrough-position strikethrough-thickness underline-position underline-thickness unicode-range units-per-em v-alphabetic v-hanging v-ideographic v-mathematical widths x-height xml:base xml:lang xml:space],
- 'font-face-format' => %w[id string xml:base xml:lang xml:space],
- 'font-face-name' => %w[id name xml:base xml:lang xml:space],
- 'font-face-src' => %w[id xml:base xml:lang xml:space],
- 'font-face-uri' => %w[id xlink:actuate xlink:arcrole xlink:href xlink:role xlink:show xlink:title xlink:type xml:base xml:lang xml:space],
- 'foreignObject' => %w[alignment-baseline baseline-shift class clip clip-path clip-rule color color-interpolation color-interpolation-filters color-profile color-rendering cursor direction display dominant-baseline enable-background externalResourcesRequired fill fill-opacity fill-rule filter flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight glyph-orientation-horizontal glyph-orientation-vertical height id image-rendering kerning letter-spacing lighting-color marker-end marker-mid marker-start mask onactivate onclick onfocusin onfocusout onload onmousedown onmousemove onmouseout onmouseover onmouseup opacity overflow pointer-events requiredExtensions requiredFeatures shape-rendering stop-color stop-opacity stroke stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width style systemLanguage text-anchor text-decoration text-rendering transform unicode-bidi visibility width word-spacing writing-mode x xml:base xml:lang xml:space y],
- 'g' => %w[alignment-baseline baseline-shift class clip clip-path clip-rule color color-interpolation color-interpolation-filters color-profile color-rendering cursor direction display dominant-baseline enable-background externalResourcesRequired fill fill-opacity fill-rule filter flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight glyph-orientation-horizontal glyph-orientation-vertical id image-rendering kerning letter-spacing lighting-color marker-end marker-mid marker-start mask onactivate onclick onfocusin onfocusout onload onmousedown onmousemove onmouseout onmouseover onmouseup opacity overflow pointer-events requiredExtensions requiredFeatures shape-rendering stop-color stop-opacity stroke stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width style systemLanguage text-anchor text-decoration text-rendering transform unicode-bidi visibility word-spacing writing-mode xml:base xml:lang xml:space],
- 'glyph' => %w[alignment-baseline arabic-form baseline-shift class clip clip-path clip-rule color color-interpolation color-interpolation-filters color-profile color-rendering cursor d direction display dominant-baseline enable-background fill fill-opacity fill-rule filter flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight glyph-name glyph-orientation-horizontal glyph-orientation-vertical horiz-adv-x id image-rendering kerning lang letter-spacing lighting-color marker-end marker-mid marker-start mask opacity orientation overflow pointer-events shape-rendering stop-color stop-opacity stroke stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width style text-anchor text-decoration text-rendering unicode unicode-bidi vert-adv-y vert-origin-x vert-origin-y visibility word-spacing writing-mode xml:base xml:lang xml:space],
- 'glyphRef' => %w[alignment-baseline baseline-shift class clip clip-path clip-rule color color-interpolation color-interpolation-filters color-profile color-rendering cursor direction display dominant-baseline dx dy enable-background fill fill-opacity fill-rule filter flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight format glyph-orientation-horizontal glyph-orientation-vertical glyphRef id image-rendering kerning letter-spacing lighting-color marker-end marker-mid marker-start mask opacity overflow pointer-events shape-rendering stop-color stop-opacity stroke stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width style text-anchor text-decoration text-rendering unicode-bidi visibility word-spacing writing-mode x xlink:actuate xlink:arcrole xlink:href xlink:role xlink:show xlink:title xlink:type xml:base xml:lang xml:space y],
- 'hkern' => %w[g1 g2 id k u1 u2 xml:base xml:lang xml:space],
- 'image' => %w[alignment-baseline baseline-shift class clip clip-path clip-rule color color-interpolation color-interpolation-filters color-profile color-rendering cursor direction display dominant-baseline enable-background externalResourcesRequired fill fill-opacity fill-rule filter flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight glyph-orientation-horizontal glyph-orientation-vertical height id image-rendering kerning letter-spacing lighting-color marker-end marker-mid marker-start mask onactivate onclick onfocusin onfocusout onload onmousedown onmousemove onmouseout onmouseover onmouseup opacity overflow pointer-events preserveAspectRatio requiredExtensions requiredFeatures shape-rendering stop-color stop-opacity stroke stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width style systemLanguage text-anchor text-decoration text-rendering transform unicode-bidi visibility width word-spacing writing-mode x xlink:actuate xlink:arcrole xlink:href xlink:role xlink:show xlink:title xlink:type xml:base xml:lang xml:space y],
- 'line' => %w[alignment-baseline baseline-shift class clip clip-path clip-rule color color-interpolation color-interpolation-filters color-profile color-rendering cursor direction display dominant-baseline enable-background externalResourcesRequired fill fill-opacity fill-rule filter flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight glyph-orientation-horizontal glyph-orientation-vertical id image-rendering kerning letter-spacing lighting-color marker-end marker-mid marker-start mask onactivate onclick onfocusin onfocusout onload onmousedown onmousemove onmouseout onmouseover onmouseup opacity overflow pointer-events requiredExtensions requiredFeatures shape-rendering stop-color stop-opacity stroke stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width style systemLanguage text-anchor text-decoration text-rendering transform unicode-bidi visibility word-spacing writing-mode x1 x2 xml:base xml:lang xml:space y1 y2],
- 'linearGradient' => %w[alignment-baseline baseline-shift class clip clip-path clip-rule color color-interpolation color-interpolation-filters color-profile color-rendering cursor direction display dominant-baseline enable-background externalResourcesRequired fill fill-opacity fill-rule filter flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight glyph-orientation-horizontal glyph-orientation-vertical gradientTransform gradientUnits id image-rendering kerning letter-spacing lighting-color marker-end marker-mid marker-start mask opacity overflow pointer-events shape-rendering spreadMethod stop-color stop-opacity stroke stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width style text-anchor text-decoration text-rendering unicode-bidi visibility word-spacing writing-mode x1 x2 xlink:arcrole xlink:href xlink:role xlink:title xlink:type xml:base xml:lang xml:space y1 y2],
- 'marker' => %w[alignment-baseline baseline-shift class clip clip-path clip-rule color color-interpolation color-interpolation-filters color-profile color-rendering cursor direction display dominant-baseline enable-background externalResourcesRequired fill fill-opacity fill-rule filter flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight glyph-orientation-horizontal glyph-orientation-vertical id image-rendering kerning letter-spacing lighting-color marker-end marker-mid marker-start markerHeight markerUnits markerWidth mask opacity orient overflow pointer-events preserveAspectRatio refX refY shape-rendering stop-color stop-opacity stroke stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width style text-anchor text-decoration text-rendering unicode-bidi viewBox visibility word-spacing writing-mode xml:base xml:lang xml:space],
- 'mask' => %w[alignment-baseline baseline-shift class clip clip-path clip-rule color color-interpolation color-interpolation-filters color-profile color-rendering cursor direction display dominant-baseline enable-background externalResourcesRequired fill fill-opacity fill-rule filter flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight glyph-orientation-horizontal glyph-orientation-vertical height id image-rendering kerning letter-spacing lighting-color marker-end marker-mid marker-start mask maskContentUnits maskUnits opacity overflow pointer-events requiredExtensions requiredFeatures shape-rendering stop-color stop-opacity stroke stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width style systemLanguage text-anchor text-decoration text-rendering unicode-bidi visibility width word-spacing writing-mode x xml:base xml:lang xml:space y],
- 'metadata' => %w[id xml:base xml:lang xml:space],
- 'missing-glyph' => %w[alignment-baseline baseline-shift class clip clip-path clip-rule color color-interpolation color-interpolation-filters color-profile color-rendering cursor d direction display dominant-baseline enable-background fill fill-opacity fill-rule filter flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight glyph-orientation-horizontal glyph-orientation-vertical horiz-adv-x id image-rendering kerning letter-spacing lighting-color marker-end marker-mid marker-start mask opacity overflow pointer-events shape-rendering stop-color stop-opacity stroke stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width style text-anchor text-decoration text-rendering unicode-bidi vert-adv-y vert-origin-x vert-origin-y visibility word-spacing writing-mode xml:base xml:lang xml:space],
- 'mpath' => %w[externalResourcesRequired id xlink:actuate xlink:arcrole xlink:href xlink:role xlink:show xlink:title xlink:type xml:base xml:lang xml:space],
- 'path' => %w[alignment-baseline baseline-shift class clip clip-path clip-rule color color-interpolation color-interpolation-filters color-profile color-rendering cursor d direction display dominant-baseline enable-background externalResourcesRequired fill fill-opacity fill-rule filter flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight glyph-orientation-horizontal glyph-orientation-vertical id image-rendering kerning letter-spacing lighting-color marker-end marker-mid marker-start mask onactivate onclick onfocusin onfocusout onload onmousedown onmousemove onmouseout onmouseover onmouseup opacity overflow pathLength pointer-events requiredExtensions requiredFeatures shape-rendering stop-color stop-opacity stroke stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width style systemLanguage text-anchor text-decoration text-rendering transform unicode-bidi visibility word-spacing writing-mode xml:base xml:lang xml:space],
- 'pattern' => %w[alignment-baseline baseline-shift class clip clip-path clip-rule color color-interpolation color-interpolation-filters color-profile color-rendering cursor direction display dominant-baseline enable-background externalResourcesRequired fill fill-opacity fill-rule filter flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight glyph-orientation-horizontal glyph-orientation-vertical height id image-rendering kerning letter-spacing lighting-color marker-end marker-mid marker-start mask opacity overflow patternContentUnits patternTransform patternUnits pointer-events preserveAspectRatio requiredExtensions requiredFeatures shape-rendering stop-color stop-opacity stroke stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width style systemLanguage text-anchor text-decoration text-rendering unicode-bidi viewBox visibility width word-spacing writing-mode x xlink:actuate xlink:arcrole xlink:href xlink:role xlink:show xlink:title xlink:type xml:base xml:lang xml:space y],
- 'polygon' => %w[alignment-baseline baseline-shift class clip clip-path clip-rule color color-interpolation color-interpolation-filters color-profile color-rendering cursor direction display dominant-baseline enable-background externalResourcesRequired fill fill-opacity fill-rule filter flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight glyph-orientation-horizontal glyph-orientation-vertical id image-rendering kerning letter-spacing lighting-color marker-end marker-mid marker-start mask onactivate onclick onfocusin onfocusout onload onmousedown onmousemove onmouseout onmouseover onmouseup opacity overflow pointer-events points requiredExtensions requiredFeatures shape-rendering stop-color stop-opacity stroke stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width style systemLanguage text-anchor text-decoration text-rendering transform unicode-bidi visibility word-spacing writing-mode xml:base xml:lang xml:space],
- 'polyline' => %w[alignment-baseline baseline-shift class clip clip-path clip-rule color color-interpolation color-interpolation-filters color-profile color-rendering cursor direction display dominant-baseline enable-background externalResourcesRequired fill fill-opacity fill-rule filter flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight glyph-orientation-horizontal glyph-orientation-vertical id image-rendering kerning letter-spacing lighting-color marker-end marker-mid marker-start mask onactivate onclick onfocusin onfocusout onload onmousedown onmousemove onmouseout onmouseover onmouseup opacity overflow pointer-events points requiredExtensions requiredFeatures shape-rendering stop-color stop-opacity stroke stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width style systemLanguage text-anchor text-decoration text-rendering transform unicode-bidi visibility word-spacing writing-mode xml:base xml:lang xml:space],
- 'radialGradient' => %w[alignment-baseline baseline-shift class clip clip-path clip-rule color color-interpolation color-interpolation-filters color-profile color-rendering cursor cx cy direction display dominant-baseline enable-background externalResourcesRequired fill fill-opacity fill-rule filter flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight fx fy glyph-orientation-horizontal glyph-orientation-vertical gradientTransform gradientUnits id image-rendering kerning letter-spacing lighting-color marker-end marker-mid marker-start mask opacity overflow pointer-events r shape-rendering spreadMethod stop-color stop-opacity stroke stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width style text-anchor text-decoration text-rendering unicode-bidi visibility word-spacing writing-mode xlink:arcrole xlink:href xlink:role xlink:title xlink:type xml:base xml:lang xml:space],
- 'rect' => %w[alignment-baseline baseline-shift class clip clip-path clip-rule color color-interpolation color-interpolation-filters color-profile color-rendering cursor direction display dominant-baseline enable-background externalResourcesRequired fill fill-opacity fill-rule filter flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight glyph-orientation-horizontal glyph-orientation-vertical height id image-rendering kerning letter-spacing lighting-color marker-end marker-mid marker-start mask onactivate onclick onfocusin onfocusout onload onmousedown onmousemove onmouseout onmouseover onmouseup opacity overflow pointer-events requiredExtensions requiredFeatures rx ry shape-rendering stop-color stop-opacity stroke stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width style systemLanguage text-anchor text-decoration text-rendering transform unicode-bidi visibility width word-spacing writing-mode x xml:base xml:lang xml:space y],
- 'script' => %w[externalResourcesRequired id type xlink:actuate xlink:arcrole xlink:href xlink:role xlink:show xlink:title xlink:type xml:base xml:lang xml:space],
- 'set' => %w[attributeName attributeType begin dur end externalResourcesRequired fill id max min onbegin onend onload onrepeat repeatCount repeatDur requiredExtensions requiredFeatures restart systemLanguage to xlink:actuate xlink:arcrole xlink:href xlink:role xlink:show xlink:title xlink:type xml:base xml:lang xml:space],
- 'stop' => %w[alignment-baseline baseline-shift class clip clip-path clip-rule color color-interpolation color-interpolation-filters color-profile color-rendering cursor direction display dominant-baseline enable-background fill fill-opacity fill-rule filter flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight glyph-orientation-horizontal glyph-orientation-vertical id image-rendering kerning letter-spacing lighting-color marker-end marker-mid marker-start mask offset opacity overflow pointer-events shape-rendering stop-color stop-opacity stroke stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width style text-anchor text-decoration text-rendering unicode-bidi visibility word-spacing writing-mode xml:base xml:lang xml:space],
- 'style' => %w[id media title type xml:base xml:lang xml:space],
- 'svg' => %w[alignment-baseline baseProfile baseline-shift class clip clip-path clip-rule color color-interpolation color-interpolation-filters color-profile color-rendering contentScriptType contentStyleType cursor direction display dominant-baseline enable-background externalResourcesRequired fill fill-opacity fill-rule filter flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight glyph-orientation-horizontal glyph-orientation-vertical height id image-rendering kerning letter-spacing lighting-color marker-end marker-mid marker-start mask onabort onactivate onclick onerror onfocusin onfocusout onload onmousedown onmousemove onmouseout onmouseover onmouseup onresize onscroll onunload onzoom opacity overflow pointer-events preserveAspectRatio requiredExtensions requiredFeatures shape-rendering stop-color stop-opacity stroke stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width style systemLanguage text-anchor text-decoration text-rendering unicode-bidi version viewBox visibility width word-spacing writing-mode x xml:base xml:lang xml:space xmlns y zoomAndPan],
- 'switch' => %w[alignment-baseline baseline-shift class clip clip-path clip-rule color color-interpolation color-interpolation-filters color-profile color-rendering cursor direction display dominant-baseline enable-background externalResourcesRequired fill fill-opacity fill-rule filter flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight glyph-orientation-horizontal glyph-orientation-vertical id image-rendering kerning letter-spacing lighting-color marker-end marker-mid marker-start mask onactivate onclick onfocusin onfocusout onload onmousedown onmousemove onmouseout onmouseover onmouseup opacity overflow pointer-events requiredExtensions requiredFeatures shape-rendering stop-color stop-opacity stroke stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width style systemLanguage text-anchor text-decoration text-rendering transform unicode-bidi visibility word-spacing writing-mode xml:base xml:lang xml:space],
- 'symbol' => %w[alignment-baseline baseline-shift class clip clip-path clip-rule color color-interpolation color-interpolation-filters color-profile color-rendering cursor direction display dominant-baseline enable-background externalResourcesRequired fill fill-opacity fill-rule filter flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight glyph-orientation-horizontal glyph-orientation-vertical id image-rendering kerning letter-spacing lighting-color marker-end marker-mid marker-start mask onactivate onclick onfocusin onfocusout onload onmousedown onmousemove onmouseout onmouseover onmouseup opacity overflow pointer-events preserveAspectRatio shape-rendering stop-color stop-opacity stroke stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width style text-anchor text-decoration text-rendering unicode-bidi viewBox visibility word-spacing writing-mode xml:base xml:lang xml:space],
- 'text' => %w[alignment-baseline baseline-shift class clip clip-path clip-rule color color-interpolation color-interpolation-filters color-profile color-rendering cursor direction display dominant-baseline dx dy enable-background externalResourcesRequired fill fill-opacity fill-rule filter flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight glyph-orientation-horizontal glyph-orientation-vertical id image-rendering kerning lengthAdjust letter-spacing lighting-color marker-end marker-mid marker-start mask onactivate onclick onfocusin onfocusout onload onmousedown onmousemove onmouseout onmouseover onmouseup opacity overflow pointer-events requiredExtensions requiredFeatures rotate shape-rendering stop-color stop-opacity stroke stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width style systemLanguage text-anchor text-decoration text-rendering textLength transform unicode-bidi visibility word-spacing writing-mode x xml:base xml:lang xml:space y],
- 'textPath' => %w[alignment-baseline baseline-shift class clip clip-path clip-rule color color-interpolation color-interpolation-filters color-profile color-rendering cursor direction display dominant-baseline enable-background externalResourcesRequired fill fill-opacity fill-rule filter flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight glyph-orientation-horizontal glyph-orientation-vertical id image-rendering kerning lengthAdjust letter-spacing lighting-color marker-end marker-mid marker-start mask method onactivate onclick onfocusin onfocusout onload onmousedown onmousemove onmouseout onmouseover onmouseup opacity overflow pointer-events requiredExtensions requiredFeatures shape-rendering spacing startOffset stop-color stop-opacity stroke stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width style systemLanguage text-anchor text-decoration text-rendering textLength unicode-bidi visibility word-spacing writing-mode xlink:arcrole xlink:href xlink:role xlink:title xlink:type xml:base xml:lang xml:space],
- 'title' => %w[class id style xml:base xml:lang xml:space],
- 'tref' => %w[alignment-baseline baseline-shift class clip clip-path clip-rule color color-interpolation color-interpolation-filters color-profile color-rendering cursor direction display dominant-baseline dx dy enable-background externalResourcesRequired fill fill-opacity fill-rule filter flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight glyph-orientation-horizontal glyph-orientation-vertical id image-rendering kerning lengthAdjust letter-spacing lighting-color marker-end marker-mid marker-start mask onactivate onclick onfocusin onfocusout onload onmousedown onmousemove onmouseout onmouseover onmouseup opacity overflow pointer-events requiredExtensions requiredFeatures rotate shape-rendering stop-color stop-opacity stroke stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width style systemLanguage text-anchor text-decoration text-rendering textLength unicode-bidi visibility word-spacing writing-mode x xlink:arcrole xlink:href xlink:role xlink:title xlink:type xml:base xml:lang xml:space y],
- 'tspan' => %w[alignment-baseline baseline-shift class clip clip-path clip-rule color color-interpolation color-interpolation-filters color-profile color-rendering cursor direction display dominant-baseline dx dy enable-background externalResourcesRequired fill fill-opacity fill-rule filter flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight glyph-orientation-horizontal glyph-orientation-vertical id image-rendering kerning lengthAdjust letter-spacing lighting-color marker-end marker-mid marker-start mask onactivate onclick onfocusin onfocusout onload onmousedown onmousemove onmouseout onmouseover onmouseup opacity overflow pointer-events requiredExtensions requiredFeatures rotate shape-rendering stop-color stop-opacity stroke stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width style systemLanguage text-anchor text-decoration text-rendering textLength unicode-bidi visibility word-spacing writing-mode x xml:base xml:lang xml:space y],
- 'use' => %w[alignment-baseline baseline-shift class clip clip-path clip-rule color color-interpolation color-interpolation-filters color-profile color-rendering cursor direction display dominant-baseline enable-background externalResourcesRequired fill fill-opacity fill-rule filter flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight glyph-orientation-horizontal glyph-orientation-vertical height id image-rendering kerning letter-spacing lighting-color marker-end marker-mid marker-start mask onactivate onclick onfocusin onfocusout onload onmousedown onmousemove onmouseout onmouseover onmouseup opacity overflow pointer-events requiredExtensions requiredFeatures shape-rendering stop-color stop-opacity stroke stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width style systemLanguage text-anchor text-decoration text-rendering transform unicode-bidi visibility width word-spacing writing-mode x xlink:actuate xlink:arcrole xlink:href xlink:role xlink:show xlink:title xlink:type xml:base xml:lang xml:space y],
- 'view' => %w[externalResourcesRequired id preserveAspectRatio viewBox viewTarget xml:base xml:lang xml:space zoomAndPan],
- 'vkern' => %w[g1 g2 id k u1 u2 xml:base xml:lang xml:space]
- }.freeze
+ ALLOWED_ATTRIBUTES = {
+ 'a' => %w[alignment-baseline baseline-shift class clip clip-path clip-rule color color-interpolation color-interpolation-filters color-profile color-rendering cursor direction display dominant-baseline enable-background externalResourcesRequired fill fill-opacity fill-rule filter flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight glyph-orientation-horizontal glyph-orientation-vertical id image-rendering kerning letter-spacing lighting-color marker-end marker-mid marker-start mask onactivate onclick onfocusin onfocusout onload onmousedown onmousemove onmouseout onmouseover onmouseup opacity overflow pointer-events requiredExtensions requiredFeatures shape-rendering stop-color stop-opacity stroke stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width style systemLanguage target text-anchor text-decoration text-rendering transform unicode-bidi visibility word-spacing writing-mode xlink:actuate xlink:arcrole xlink:href xlink:role xlink:show xlink:title xlink:type xml:base xml:lang xml:space],
+ 'altGlyph' => %w[alignment-baseline baseline-shift class clip clip-path clip-rule color color-interpolation color-interpolation-filters color-profile color-rendering cursor direction display dominant-baseline dx dy enable-background externalResourcesRequired fill fill-opacity fill-rule filter flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight format glyph-orientation-horizontal glyph-orientation-vertical glyphRef id image-rendering kerning letter-spacing lighting-color marker-end marker-mid marker-start mask onactivate onclick onfocusin onfocusout onload onmousedown onmousemove onmouseout onmouseover onmouseup opacity overflow pointer-events requiredExtensions requiredFeatures rotate shape-rendering stop-color stop-opacity stroke stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width style systemLanguage text-anchor text-decoration text-rendering unicode-bidi visibility word-spacing writing-mode x xlink:actuate xlink:arcrole xlink:href xlink:role xlink:show xlink:title xlink:type xml:base xml:lang xml:space y],
+ 'altGlyphDef' => %w[id xml:base xml:lang xml:space],
+ 'altGlyphItem' => %w[id xml:base xml:lang xml:space],
+ 'animate' => %w[accumulate additive alignment-baseline attributeName attributeType baseline-shift begin by calcMode clip clip-path clip-rule color color-interpolation color-interpolation-filters color-profile color-rendering cursor direction display dominant-baseline dur enable-background end externalResourcesRequired fill fill-opacity fill-rule filter flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight from glyph-orientation-horizontal glyph-orientation-vertical id image-rendering kerning keySplines keyTimes letter-spacing lighting-color marker-end marker-mid marker-start mask max min onbegin onend onload onrepeat opacity overflow pointer-events repeatCount repeatDur requiredExtensions requiredFeatures restart shape-rendering stop-color stop-opacity stroke stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width systemLanguage text-anchor text-decoration text-rendering to unicode-bidi values visibility word-spacing writing-mode xlink:actuate xlink:arcrole xlink:href xlink:role xlink:show xlink:title xlink:type xml:base xml:lang xml:space],
+ 'animateColor' => %w[accumulate additive alignment-baseline attributeName attributeType baseline-shift begin by calcMode clip clip-path clip-rule color color-interpolation color-interpolation-filters color-profile color-rendering cursor direction display dominant-baseline dur enable-background end externalResourcesRequired fill fill-opacity fill-rule filter flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight from glyph-orientation-horizontal glyph-orientation-vertical id image-rendering kerning keySplines keyTimes letter-spacing lighting-color marker-end marker-mid marker-start mask max min onbegin onend onload onrepeat opacity overflow pointer-events repeatCount repeatDur requiredExtensions requiredFeatures restart shape-rendering stop-color stop-opacity stroke stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width systemLanguage text-anchor text-decoration text-rendering to unicode-bidi values visibility word-spacing writing-mode xlink:actuate xlink:arcrole xlink:href xlink:role xlink:show xlink:title xlink:type xml:base xml:lang xml:space],
+ 'animateMotion' => %w[accumulate additive begin by calcMode dur end externalResourcesRequired fill from id keyPoints keySplines keyTimes max min onbegin onend onload onrepeat origin path repeatCount repeatDur requiredExtensions requiredFeatures restart rotate systemLanguage to values xlink:actuate xlink:arcrole xlink:href xlink:role xlink:show xlink:title xlink:type xml:base xml:lang xml:space],
+ 'animateTransform' => %w[accumulate additive attributeName attributeType begin by calcMode dur end externalResourcesRequired fill from id keySplines keyTimes max min onbegin onend onload onrepeat repeatCount repeatDur requiredExtensions requiredFeatures restart systemLanguage to type values xlink:actuate xlink:arcrole xlink:href xlink:role xlink:show xlink:title xlink:type xml:base xml:lang xml:space],
+ 'circle' => %w[alignment-baseline baseline-shift class clip clip-path clip-rule color color-interpolation color-interpolation-filters color-profile color-rendering cursor cx cy direction display dominant-baseline enable-background externalResourcesRequired fill fill-opacity fill-rule filter flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight glyph-orientation-horizontal glyph-orientation-vertical id image-rendering kerning letter-spacing lighting-color marker-end marker-mid marker-start mask onactivate onclick onfocusin onfocusout onload onmousedown onmousemove onmouseout onmouseover onmouseup opacity overflow pointer-events r requiredExtensions requiredFeatures shape-rendering stop-color stop-opacity stroke stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width style systemLanguage text-anchor text-decoration text-rendering transform unicode-bidi visibility word-spacing writing-mode xml:base xml:lang xml:space],
+ 'clipPath' => %w[alignment-baseline baseline-shift class clip clip-path clip-rule clipPathUnits color color-interpolation color-interpolation-filters color-profile color-rendering cursor direction display dominant-baseline enable-background externalResourcesRequired fill fill-opacity fill-rule filter flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight glyph-orientation-horizontal glyph-orientation-vertical id image-rendering kerning letter-spacing lighting-color marker-end marker-mid marker-start mask opacity overflow pointer-events requiredExtensions requiredFeatures shape-rendering stop-color stop-opacity stroke stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width style systemLanguage text-anchor text-decoration text-rendering transform unicode-bidi visibility word-spacing writing-mode xml:base xml:lang xml:space],
+ 'color-profile' => %w[id local name rendering-intent xlink:actuate xlink:arcrole xlink:href xlink:role xlink:show xlink:title xlink:type xml:base xml:lang xml:space],
+ 'cursor' => %w[externalResourcesRequired id requiredExtensions requiredFeatures systemLanguage x xlink:actuate xlink:arcrole xlink:href xlink:role xlink:show xlink:title xlink:type xml:base xml:lang xml:space y],
+ 'defs' => %w[alignment-baseline baseline-shift class clip clip-path clip-rule color color-interpolation color-interpolation-filters color-profile color-rendering cursor direction display dominant-baseline enable-background externalResourcesRequired fill fill-opacity fill-rule filter flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight glyph-orientation-horizontal glyph-orientation-vertical id image-rendering kerning letter-spacing lighting-color marker-end marker-mid marker-start mask onactivate onclick onfocusin onfocusout onload onmousedown onmousemove onmouseout onmouseover onmouseup opacity overflow pointer-events requiredExtensions requiredFeatures shape-rendering stop-color stop-opacity stroke stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width style systemLanguage text-anchor text-decoration text-rendering transform unicode-bidi visibility word-spacing writing-mode xml:base xml:lang xml:space],
+ 'desc' => %w[class id style xml:base xml:lang xml:space],
+ 'ellipse' => %w[alignment-baseline baseline-shift class clip clip-path clip-rule color color-interpolation color-interpolation-filters color-profile color-rendering cursor cx cy direction display dominant-baseline enable-background externalResourcesRequired fill fill-opacity fill-rule filter flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight glyph-orientation-horizontal glyph-orientation-vertical id image-rendering kerning letter-spacing lighting-color marker-end marker-mid marker-start mask onactivate onclick onfocusin onfocusout onload onmousedown onmousemove onmouseout onmouseover onmouseup opacity overflow pointer-events requiredExtensions requiredFeatures rx ry shape-rendering stop-color stop-opacity stroke stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width style systemLanguage text-anchor text-decoration text-rendering transform unicode-bidi visibility word-spacing writing-mode xml:base xml:lang xml:space],
+ 'feBlend' => %w[alignment-baseline baseline-shift class clip clip-path clip-rule color color-interpolation color-interpolation-filters color-profile color-rendering cursor direction display dominant-baseline enable-background fill fill-opacity fill-rule filter flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight glyph-orientation-horizontal glyph-orientation-vertical height id image-rendering in in2 kerning letter-spacing lighting-color marker-end marker-mid marker-start mask mode opacity overflow pointer-events result shape-rendering stop-color stop-opacity stroke stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width style text-anchor text-decoration text-rendering unicode-bidi visibility width word-spacing writing-mode x xml:base xml:lang xml:space y],
+ 'feColorMatrix' => %w[alignment-baseline baseline-shift class clip clip-path clip-rule color color-interpolation color-interpolation-filters color-profile color-rendering cursor direction display dominant-baseline enable-background fill fill-opacity fill-rule filter flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight glyph-orientation-horizontal glyph-orientation-vertical height id image-rendering in kerning letter-spacing lighting-color marker-end marker-mid marker-start mask opacity overflow pointer-events result shape-rendering stop-color stop-opacity stroke stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width style text-anchor text-decoration text-rendering type unicode-bidi values visibility width word-spacing writing-mode x xml:base xml:lang xml:space y],
+ 'feComponentTransfer' => %w[alignment-baseline baseline-shift class clip clip-path clip-rule color color-interpolation color-interpolation-filters color-profile color-rendering cursor direction display dominant-baseline enable-background fill fill-opacity fill-rule filter flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight glyph-orientation-horizontal glyph-orientation-vertical height id image-rendering in kerning letter-spacing lighting-color marker-end marker-mid marker-start mask opacity overflow pointer-events result shape-rendering stop-color stop-opacity stroke stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width style text-anchor text-decoration text-rendering unicode-bidi visibility width word-spacing writing-mode x xml:base xml:lang xml:space y],
+ 'feComposite' => %w[alignment-baseline baseline-shift class clip clip-path clip-rule color color-interpolation color-interpolation-filters color-profile color-rendering cursor direction display dominant-baseline enable-background fill fill-opacity fill-rule filter flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight glyph-orientation-horizontal glyph-orientation-vertical height id image-rendering in in2 k1 k2 k3 k4 kerning letter-spacing lighting-color marker-end marker-mid marker-start mask opacity operator overflow pointer-events result shape-rendering stop-color stop-opacity stroke stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width style text-anchor text-decoration text-rendering unicode-bidi visibility width word-spacing writing-mode x xml:base xml:lang xml:space y],
+ 'feConvolveMatrix' => %w[alignment-baseline baseline-shift bias class clip clip-path clip-rule color color-interpolation color-interpolation-filters color-profile color-rendering cursor direction display divisor dominant-baseline edgeMode enable-background fill fill-opacity fill-rule filter flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight glyph-orientation-horizontal glyph-orientation-vertical height id image-rendering in kernelMatrix kernelUnitLength kerning letter-spacing lighting-color marker-end marker-mid marker-start mask opacity order overflow pointer-events preserveAlpha result shape-rendering stop-color stop-opacity stroke stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width style targetX targetY text-anchor text-decoration text-rendering unicode-bidi visibility width word-spacing writing-mode x xml:base xml:lang xml:space y],
+ 'feDiffuseLighting' => %w[alignment-baseline baseline-shift class clip clip-path clip-rule color color-interpolation color-interpolation-filters color-profile color-rendering cursor diffuseConstant direction display dominant-baseline enable-background fill fill-opacity fill-rule filter flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight glyph-orientation-horizontal glyph-orientation-vertical height id image-rendering in kernelUnitLength kerning letter-spacing lighting-color marker-end marker-mid marker-start mask opacity overflow pointer-events result shape-rendering stop-color stop-opacity stroke stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width style surfaceScale text-anchor text-decoration text-rendering unicode-bidi visibility width word-spacing writing-mode x xml:base xml:lang xml:space y],
+ 'feDisplacementMap' => %w[alignment-baseline baseline-shift class clip clip-path clip-rule color color-interpolation color-interpolation-filters color-profile color-rendering cursor direction display dominant-baseline enable-background fill fill-opacity fill-rule filter flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight glyph-orientation-horizontal glyph-orientation-vertical height id image-rendering in in2 kerning letter-spacing lighting-color marker-end marker-mid marker-start mask opacity overflow pointer-events result scale shape-rendering stop-color stop-opacity stroke stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width style text-anchor text-decoration text-rendering unicode-bidi visibility width word-spacing writing-mode x xChannelSelector xml:base xml:lang xml:space y yChannelSelector],
+ 'feDistantLight' => %w[azimuth elevation id xml:base xml:lang xml:space],
+ 'feFlood' => %w[alignment-baseline baseline-shift class clip clip-path clip-rule color color-interpolation color-interpolation-filters color-profile color-rendering cursor direction display dominant-baseline enable-background fill fill-opacity fill-rule filter flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight glyph-orientation-horizontal glyph-orientation-vertical height id image-rendering kerning letter-spacing lighting-color marker-end marker-mid marker-start mask opacity overflow pointer-events result shape-rendering stop-color stop-opacity stroke stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width style text-anchor text-decoration text-rendering unicode-bidi visibility width word-spacing writing-mode x xml:base xml:lang xml:space y],
+ 'feFuncA' => %w[amplitude exponent id intercept offset slope tableValues type xml:base xml:lang xml:space],
+ 'feFuncB' => %w[amplitude exponent id intercept offset slope tableValues type xml:base xml:lang xml:space],
+ 'feFuncG' => %w[amplitude exponent id intercept offset slope tableValues type xml:base xml:lang xml:space],
+ 'feFuncR' => %w[amplitude exponent id intercept offset slope tableValues type xml:base xml:lang xml:space],
+ 'feGaussianBlur' => %w[alignment-baseline baseline-shift class clip clip-path clip-rule color color-interpolation color-interpolation-filters color-profile color-rendering cursor direction display dominant-baseline enable-background fill fill-opacity fill-rule filter flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight glyph-orientation-horizontal glyph-orientation-vertical height id image-rendering in kerning letter-spacing lighting-color marker-end marker-mid marker-start mask opacity overflow pointer-events result shape-rendering stdDeviation stop-color stop-opacity stroke stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width style text-anchor text-decoration text-rendering unicode-bidi visibility width word-spacing writing-mode x xml:base xml:lang xml:space y],
+ 'feImage' => %w[alignment-baseline baseline-shift class clip clip-path clip-rule color color-interpolation color-interpolation-filters color-profile color-rendering cursor direction display dominant-baseline enable-background externalResourcesRequired fill fill-opacity fill-rule filter flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight glyph-orientation-horizontal glyph-orientation-vertical height id image-rendering kerning letter-spacing lighting-color marker-end marker-mid marker-start mask opacity overflow pointer-events preserveAspectRatio result shape-rendering stop-color stop-opacity stroke stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width style text-anchor text-decoration text-rendering unicode-bidi visibility width word-spacing writing-mode x xlink:actuate xlink:arcrole xlink:href xlink:role xlink:show xlink:title xlink:type xml:base xml:lang xml:space y],
+ 'feMerge' => %w[alignment-baseline baseline-shift class clip clip-path clip-rule color color-interpolation color-interpolation-filters color-profile color-rendering cursor direction display dominant-baseline enable-background fill fill-opacity fill-rule filter flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight glyph-orientation-horizontal glyph-orientation-vertical height id image-rendering kerning letter-spacing lighting-color marker-end marker-mid marker-start mask opacity overflow pointer-events result shape-rendering stop-color stop-opacity stroke stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width style text-anchor text-decoration text-rendering unicode-bidi visibility width word-spacing writing-mode x xml:base xml:lang xml:space y],
+ 'feMergeNode' => %w[id xml:base xml:lang xml:space],
+ 'feMorphology' => %w[alignment-baseline baseline-shift class clip clip-path clip-rule color color-interpolation color-interpolation-filters color-profile color-rendering cursor direction display dominant-baseline enable-background fill fill-opacity fill-rule filter flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight glyph-orientation-horizontal glyph-orientation-vertical height id image-rendering in kerning letter-spacing lighting-color marker-end marker-mid marker-start mask opacity operator overflow pointer-events radius result shape-rendering stop-color stop-opacity stroke stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width style text-anchor text-decoration text-rendering unicode-bidi visibility width word-spacing writing-mode x xml:base xml:lang xml:space y],
+ 'feOffset' => %w[alignment-baseline baseline-shift class clip clip-path clip-rule color color-interpolation color-interpolation-filters color-profile color-rendering cursor direction display dominant-baseline dx dy enable-background fill fill-opacity fill-rule filter flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight glyph-orientation-horizontal glyph-orientation-vertical height id image-rendering in kerning letter-spacing lighting-color marker-end marker-mid marker-start mask opacity overflow pointer-events result shape-rendering stop-color stop-opacity stroke stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width style text-anchor text-decoration text-rendering unicode-bidi visibility width word-spacing writing-mode x xml:base xml:lang xml:space y],
+ 'fePointLight' => %w[id x xml:base xml:lang xml:space y z],
+ 'feSpecularLighting' => %w[alignment-baseline baseline-shift class clip clip-path clip-rule color color-interpolation color-interpolation-filters color-profile color-rendering cursor direction display dominant-baseline enable-background fill fill-opacity fill-rule filter flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight glyph-orientation-horizontal glyph-orientation-vertical height id image-rendering in kernelUnitLength kerning letter-spacing lighting-color marker-end marker-mid marker-start mask opacity overflow pointer-events result shape-rendering specularConstant specularExponent stop-color stop-opacity stroke stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width style surfaceScale text-anchor text-decoration text-rendering unicode-bidi visibility width word-spacing writing-mode x xml:base xml:lang xml:space y],
+ 'feSpotLight' => %w[id limitingConeAngle pointsAtX pointsAtY pointsAtZ specularExponent x xml:base xml:lang xml:space y z],
+ 'feTile' => %w[alignment-baseline baseline-shift class clip clip-path clip-rule color color-interpolation color-interpolation-filters color-profile color-rendering cursor direction display dominant-baseline enable-background fill fill-opacity fill-rule filter flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight glyph-orientation-horizontal glyph-orientation-vertical height id image-rendering in kerning letter-spacing lighting-color marker-end marker-mid marker-start mask opacity overflow pointer-events result shape-rendering stop-color stop-opacity stroke stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width style text-anchor text-decoration text-rendering unicode-bidi visibility width word-spacing writing-mode x xml:base xml:lang xml:space y],
+ 'feTurbulence' => %w[alignment-baseline baseFrequency baseline-shift class clip clip-path clip-rule color color-interpolation color-interpolation-filters color-profile color-rendering cursor direction display dominant-baseline enable-background fill fill-opacity fill-rule filter flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight glyph-orientation-horizontal glyph-orientation-vertical height id image-rendering kerning letter-spacing lighting-color marker-end marker-mid marker-start mask numOctaves opacity overflow pointer-events result seed shape-rendering stitchTiles stop-color stop-opacity stroke stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width style text-anchor text-decoration text-rendering type unicode-bidi visibility width word-spacing writing-mode x xml:base xml:lang xml:space y],
+ 'filter' => %w[alignment-baseline baseline-shift class clip clip-path clip-rule color color-interpolation color-interpolation-filters color-profile color-rendering cursor direction display dominant-baseline enable-background externalResourcesRequired fill fill-opacity fill-rule filter filterRes filterUnits flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight glyph-orientation-horizontal glyph-orientation-vertical height id image-rendering kerning letter-spacing lighting-color marker-end marker-mid marker-start mask opacity overflow pointer-events primitiveUnits shape-rendering stop-color stop-opacity stroke stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width style text-anchor text-decoration text-rendering unicode-bidi visibility width word-spacing writing-mode x xlink:actuate xlink:arcrole xlink:href xlink:role xlink:show xlink:title xlink:type xml:base xml:lang xml:space y],
+ 'font' => %w[alignment-baseline baseline-shift class clip clip-path clip-rule color color-interpolation color-interpolation-filters color-profile color-rendering cursor direction display dominant-baseline enable-background externalResourcesRequired fill fill-opacity fill-rule filter flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight glyph-orientation-horizontal glyph-orientation-vertical horiz-adv-x horiz-origin-x horiz-origin-y id image-rendering kerning letter-spacing lighting-color marker-end marker-mid marker-start mask opacity overflow pointer-events shape-rendering stop-color stop-opacity stroke stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width style text-anchor text-decoration text-rendering unicode-bidi vert-adv-y vert-origin-x vert-origin-y visibility word-spacing writing-mode xml:base xml:lang xml:space],
+ 'font-face' => %w[accent-height alphabetic ascent bbox cap-height descent font-family font-size font-stretch font-style font-variant font-weight hanging id ideographic mathematical overline-position overline-thickness panose-1 slope stemh stemv strikethrough-position strikethrough-thickness underline-position underline-thickness unicode-range units-per-em v-alphabetic v-hanging v-ideographic v-mathematical widths x-height xml:base xml:lang xml:space],
+ 'font-face-format' => %w[id string xml:base xml:lang xml:space],
+ 'font-face-name' => %w[id name xml:base xml:lang xml:space],
+ 'font-face-src' => %w[id xml:base xml:lang xml:space],
+ 'font-face-uri' => %w[id xlink:actuate xlink:arcrole xlink:href xlink:role xlink:show xlink:title xlink:type xml:base xml:lang xml:space],
+ 'foreignObject' => %w[alignment-baseline baseline-shift class clip clip-path clip-rule color color-interpolation color-interpolation-filters color-profile color-rendering cursor direction display dominant-baseline enable-background externalResourcesRequired fill fill-opacity fill-rule filter flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight glyph-orientation-horizontal glyph-orientation-vertical height id image-rendering kerning letter-spacing lighting-color marker-end marker-mid marker-start mask onactivate onclick onfocusin onfocusout onload onmousedown onmousemove onmouseout onmouseover onmouseup opacity overflow pointer-events requiredExtensions requiredFeatures shape-rendering stop-color stop-opacity stroke stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width style systemLanguage text-anchor text-decoration text-rendering transform unicode-bidi visibility width word-spacing writing-mode x xml:base xml:lang xml:space y],
+ 'g' => %w[alignment-baseline baseline-shift class clip clip-path clip-rule color color-interpolation color-interpolation-filters color-profile color-rendering cursor direction display dominant-baseline enable-background externalResourcesRequired fill fill-opacity fill-rule filter flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight glyph-orientation-horizontal glyph-orientation-vertical id image-rendering kerning letter-spacing lighting-color marker-end marker-mid marker-start mask onactivate onclick onfocusin onfocusout onload onmousedown onmousemove onmouseout onmouseover onmouseup opacity overflow pointer-events requiredExtensions requiredFeatures shape-rendering stop-color stop-opacity stroke stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width style systemLanguage text-anchor text-decoration text-rendering transform unicode-bidi visibility word-spacing writing-mode xml:base xml:lang xml:space],
+ 'glyph' => %w[alignment-baseline arabic-form baseline-shift class clip clip-path clip-rule color color-interpolation color-interpolation-filters color-profile color-rendering cursor d direction display dominant-baseline enable-background fill fill-opacity fill-rule filter flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight glyph-name glyph-orientation-horizontal glyph-orientation-vertical horiz-adv-x id image-rendering kerning lang letter-spacing lighting-color marker-end marker-mid marker-start mask opacity orientation overflow pointer-events shape-rendering stop-color stop-opacity stroke stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width style text-anchor text-decoration text-rendering unicode unicode-bidi vert-adv-y vert-origin-x vert-origin-y visibility word-spacing writing-mode xml:base xml:lang xml:space],
+ 'glyphRef' => %w[alignment-baseline baseline-shift class clip clip-path clip-rule color color-interpolation color-interpolation-filters color-profile color-rendering cursor direction display dominant-baseline dx dy enable-background fill fill-opacity fill-rule filter flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight format glyph-orientation-horizontal glyph-orientation-vertical glyphRef id image-rendering kerning letter-spacing lighting-color marker-end marker-mid marker-start mask opacity overflow pointer-events shape-rendering stop-color stop-opacity stroke stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width style text-anchor text-decoration text-rendering unicode-bidi visibility word-spacing writing-mode x xlink:actuate xlink:arcrole xlink:href xlink:role xlink:show xlink:title xlink:type xml:base xml:lang xml:space y],
+ 'hkern' => %w[g1 g2 id k u1 u2 xml:base xml:lang xml:space],
+ 'image' => %w[alignment-baseline baseline-shift class clip clip-path clip-rule color color-interpolation color-interpolation-filters color-profile color-rendering cursor direction display dominant-baseline enable-background externalResourcesRequired fill fill-opacity fill-rule filter flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight glyph-orientation-horizontal glyph-orientation-vertical height id image-rendering kerning letter-spacing lighting-color marker-end marker-mid marker-start mask onactivate onclick onfocusin onfocusout onload onmousedown onmousemove onmouseout onmouseover onmouseup opacity overflow pointer-events preserveAspectRatio requiredExtensions requiredFeatures shape-rendering stop-color stop-opacity stroke stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width style systemLanguage text-anchor text-decoration text-rendering transform unicode-bidi visibility width word-spacing writing-mode x xlink:actuate xlink:arcrole xlink:href xlink:role xlink:show xlink:title xlink:type xml:base xml:lang xml:space y],
+ 'line' => %w[alignment-baseline baseline-shift class clip clip-path clip-rule color color-interpolation color-interpolation-filters color-profile color-rendering cursor direction display dominant-baseline enable-background externalResourcesRequired fill fill-opacity fill-rule filter flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight glyph-orientation-horizontal glyph-orientation-vertical id image-rendering kerning letter-spacing lighting-color marker-end marker-mid marker-start mask onactivate onclick onfocusin onfocusout onload onmousedown onmousemove onmouseout onmouseover onmouseup opacity overflow pointer-events requiredExtensions requiredFeatures shape-rendering stop-color stop-opacity stroke stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width style systemLanguage text-anchor text-decoration text-rendering transform unicode-bidi visibility word-spacing writing-mode x1 x2 xml:base xml:lang xml:space y1 y2],
+ 'linearGradient' => %w[alignment-baseline baseline-shift class clip clip-path clip-rule color color-interpolation color-interpolation-filters color-profile color-rendering cursor direction display dominant-baseline enable-background externalResourcesRequired fill fill-opacity fill-rule filter flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight glyph-orientation-horizontal glyph-orientation-vertical gradientTransform gradientUnits id image-rendering kerning letter-spacing lighting-color marker-end marker-mid marker-start mask opacity overflow pointer-events shape-rendering spreadMethod stop-color stop-opacity stroke stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width style text-anchor text-decoration text-rendering unicode-bidi visibility word-spacing writing-mode x1 x2 xlink:arcrole xlink:href xlink:role xlink:title xlink:type xml:base xml:lang xml:space y1 y2],
+ 'marker' => %w[alignment-baseline baseline-shift class clip clip-path clip-rule color color-interpolation color-interpolation-filters color-profile color-rendering cursor direction display dominant-baseline enable-background externalResourcesRequired fill fill-opacity fill-rule filter flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight glyph-orientation-horizontal glyph-orientation-vertical id image-rendering kerning letter-spacing lighting-color marker-end marker-mid marker-start markerHeight markerUnits markerWidth mask opacity orient overflow pointer-events preserveAspectRatio refX refY shape-rendering stop-color stop-opacity stroke stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width style text-anchor text-decoration text-rendering unicode-bidi viewBox visibility word-spacing writing-mode xml:base xml:lang xml:space],
+ 'mask' => %w[alignment-baseline baseline-shift class clip clip-path clip-rule color color-interpolation color-interpolation-filters color-profile color-rendering cursor direction display dominant-baseline enable-background externalResourcesRequired fill fill-opacity fill-rule filter flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight glyph-orientation-horizontal glyph-orientation-vertical height id image-rendering kerning letter-spacing lighting-color marker-end marker-mid marker-start mask maskContentUnits maskUnits opacity overflow pointer-events requiredExtensions requiredFeatures shape-rendering stop-color stop-opacity stroke stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width style systemLanguage text-anchor text-decoration text-rendering unicode-bidi visibility width word-spacing writing-mode x xml:base xml:lang xml:space y],
+ 'metadata' => %w[id xml:base xml:lang xml:space],
+ 'missing-glyph' => %w[alignment-baseline baseline-shift class clip clip-path clip-rule color color-interpolation color-interpolation-filters color-profile color-rendering cursor d direction display dominant-baseline enable-background fill fill-opacity fill-rule filter flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight glyph-orientation-horizontal glyph-orientation-vertical horiz-adv-x id image-rendering kerning letter-spacing lighting-color marker-end marker-mid marker-start mask opacity overflow pointer-events shape-rendering stop-color stop-opacity stroke stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width style text-anchor text-decoration text-rendering unicode-bidi vert-adv-y vert-origin-x vert-origin-y visibility word-spacing writing-mode xml:base xml:lang xml:space],
+ 'mpath' => %w[externalResourcesRequired id xlink:actuate xlink:arcrole xlink:href xlink:role xlink:show xlink:title xlink:type xml:base xml:lang xml:space],
+ 'path' => %w[alignment-baseline baseline-shift class clip clip-path clip-rule color color-interpolation color-interpolation-filters color-profile color-rendering cursor d direction display dominant-baseline enable-background externalResourcesRequired fill fill-opacity fill-rule filter flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight glyph-orientation-horizontal glyph-orientation-vertical id image-rendering kerning letter-spacing lighting-color marker-end marker-mid marker-start mask onactivate onclick onfocusin onfocusout onload onmousedown onmousemove onmouseout onmouseover onmouseup opacity overflow pathLength pointer-events requiredExtensions requiredFeatures shape-rendering stop-color stop-opacity stroke stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width style systemLanguage text-anchor text-decoration text-rendering transform unicode-bidi visibility word-spacing writing-mode xml:base xml:lang xml:space],
+ 'pattern' => %w[alignment-baseline baseline-shift class clip clip-path clip-rule color color-interpolation color-interpolation-filters color-profile color-rendering cursor direction display dominant-baseline enable-background externalResourcesRequired fill fill-opacity fill-rule filter flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight glyph-orientation-horizontal glyph-orientation-vertical height id image-rendering kerning letter-spacing lighting-color marker-end marker-mid marker-start mask opacity overflow patternContentUnits patternTransform patternUnits pointer-events preserveAspectRatio requiredExtensions requiredFeatures shape-rendering stop-color stop-opacity stroke stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width style systemLanguage text-anchor text-decoration text-rendering unicode-bidi viewBox visibility width word-spacing writing-mode x xlink:actuate xlink:arcrole xlink:href xlink:role xlink:show xlink:title xlink:type xml:base xml:lang xml:space y],
+ 'polygon' => %w[alignment-baseline baseline-shift class clip clip-path clip-rule color color-interpolation color-interpolation-filters color-profile color-rendering cursor direction display dominant-baseline enable-background externalResourcesRequired fill fill-opacity fill-rule filter flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight glyph-orientation-horizontal glyph-orientation-vertical id image-rendering kerning letter-spacing lighting-color marker-end marker-mid marker-start mask onactivate onclick onfocusin onfocusout onload onmousedown onmousemove onmouseout onmouseover onmouseup opacity overflow pointer-events points requiredExtensions requiredFeatures shape-rendering stop-color stop-opacity stroke stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width style systemLanguage text-anchor text-decoration text-rendering transform unicode-bidi visibility word-spacing writing-mode xml:base xml:lang xml:space],
+ 'polyline' => %w[alignment-baseline baseline-shift class clip clip-path clip-rule color color-interpolation color-interpolation-filters color-profile color-rendering cursor direction display dominant-baseline enable-background externalResourcesRequired fill fill-opacity fill-rule filter flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight glyph-orientation-horizontal glyph-orientation-vertical id image-rendering kerning letter-spacing lighting-color marker-end marker-mid marker-start mask onactivate onclick onfocusin onfocusout onload onmousedown onmousemove onmouseout onmouseover onmouseup opacity overflow pointer-events points requiredExtensions requiredFeatures shape-rendering stop-color stop-opacity stroke stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width style systemLanguage text-anchor text-decoration text-rendering transform unicode-bidi visibility word-spacing writing-mode xml:base xml:lang xml:space],
+ 'radialGradient' => %w[alignment-baseline baseline-shift class clip clip-path clip-rule color color-interpolation color-interpolation-filters color-profile color-rendering cursor cx cy direction display dominant-baseline enable-background externalResourcesRequired fill fill-opacity fill-rule filter flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight fx fy glyph-orientation-horizontal glyph-orientation-vertical gradientTransform gradientUnits id image-rendering kerning letter-spacing lighting-color marker-end marker-mid marker-start mask opacity overflow pointer-events r shape-rendering spreadMethod stop-color stop-opacity stroke stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width style text-anchor text-decoration text-rendering unicode-bidi visibility word-spacing writing-mode xlink:arcrole xlink:href xlink:role xlink:title xlink:type xml:base xml:lang xml:space],
+ 'rect' => %w[alignment-baseline baseline-shift class clip clip-path clip-rule color color-interpolation color-interpolation-filters color-profile color-rendering cursor direction display dominant-baseline enable-background externalResourcesRequired fill fill-opacity fill-rule filter flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight glyph-orientation-horizontal glyph-orientation-vertical height id image-rendering kerning letter-spacing lighting-color marker-end marker-mid marker-start mask onactivate onclick onfocusin onfocusout onload onmousedown onmousemove onmouseout onmouseover onmouseup opacity overflow pointer-events requiredExtensions requiredFeatures rx ry shape-rendering stop-color stop-opacity stroke stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width style systemLanguage text-anchor text-decoration text-rendering transform unicode-bidi visibility width word-spacing writing-mode x xml:base xml:lang xml:space y],
+ 'script' => %w[externalResourcesRequired id type xlink:actuate xlink:arcrole xlink:href xlink:role xlink:show xlink:title xlink:type xml:base xml:lang xml:space],
+ 'set' => %w[attributeName attributeType begin dur end externalResourcesRequired fill id max min onbegin onend onload onrepeat repeatCount repeatDur requiredExtensions requiredFeatures restart systemLanguage to xlink:actuate xlink:arcrole xlink:href xlink:role xlink:show xlink:title xlink:type xml:base xml:lang xml:space],
+ 'stop' => %w[alignment-baseline baseline-shift class clip clip-path clip-rule color color-interpolation color-interpolation-filters color-profile color-rendering cursor direction display dominant-baseline enable-background fill fill-opacity fill-rule filter flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight glyph-orientation-horizontal glyph-orientation-vertical id image-rendering kerning letter-spacing lighting-color marker-end marker-mid marker-start mask offset opacity overflow pointer-events shape-rendering stop-color stop-opacity stroke stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width style text-anchor text-decoration text-rendering unicode-bidi visibility word-spacing writing-mode xml:base xml:lang xml:space],
+ 'style' => %w[id media title type xml:base xml:lang xml:space],
+ 'svg' => %w[alignment-baseline baseProfile baseline-shift class clip clip-path clip-rule color color-interpolation color-interpolation-filters color-profile color-rendering contentScriptType contentStyleType cursor direction display dominant-baseline enable-background externalResourcesRequired fill fill-opacity fill-rule filter flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight glyph-orientation-horizontal glyph-orientation-vertical height id image-rendering kerning letter-spacing lighting-color marker-end marker-mid marker-start mask onabort onactivate onclick onerror onfocusin onfocusout onload onmousedown onmousemove onmouseout onmouseover onmouseup onresize onscroll onunload onzoom opacity overflow pointer-events preserveAspectRatio requiredExtensions requiredFeatures shape-rendering stop-color stop-opacity stroke stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width style systemLanguage text-anchor text-decoration text-rendering unicode-bidi version viewBox visibility width word-spacing writing-mode x xml:base xml:lang xml:space xmlns y zoomAndPan],
+ 'switch' => %w[alignment-baseline baseline-shift class clip clip-path clip-rule color color-interpolation color-interpolation-filters color-profile color-rendering cursor direction display dominant-baseline enable-background externalResourcesRequired fill fill-opacity fill-rule filter flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight glyph-orientation-horizontal glyph-orientation-vertical id image-rendering kerning letter-spacing lighting-color marker-end marker-mid marker-start mask onactivate onclick onfocusin onfocusout onload onmousedown onmousemove onmouseout onmouseover onmouseup opacity overflow pointer-events requiredExtensions requiredFeatures shape-rendering stop-color stop-opacity stroke stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width style systemLanguage text-anchor text-decoration text-rendering transform unicode-bidi visibility word-spacing writing-mode xml:base xml:lang xml:space],
+ 'symbol' => %w[alignment-baseline baseline-shift class clip clip-path clip-rule color color-interpolation color-interpolation-filters color-profile color-rendering cursor direction display dominant-baseline enable-background externalResourcesRequired fill fill-opacity fill-rule filter flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight glyph-orientation-horizontal glyph-orientation-vertical id image-rendering kerning letter-spacing lighting-color marker-end marker-mid marker-start mask onactivate onclick onfocusin onfocusout onload onmousedown onmousemove onmouseout onmouseover onmouseup opacity overflow pointer-events preserveAspectRatio shape-rendering stop-color stop-opacity stroke stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width style text-anchor text-decoration text-rendering unicode-bidi viewBox visibility word-spacing writing-mode xml:base xml:lang xml:space],
+ 'text' => %w[alignment-baseline baseline-shift class clip clip-path clip-rule color color-interpolation color-interpolation-filters color-profile color-rendering cursor direction display dominant-baseline dx dy enable-background externalResourcesRequired fill fill-opacity fill-rule filter flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight glyph-orientation-horizontal glyph-orientation-vertical id image-rendering kerning lengthAdjust letter-spacing lighting-color marker-end marker-mid marker-start mask onactivate onclick onfocusin onfocusout onload onmousedown onmousemove onmouseout onmouseover onmouseup opacity overflow pointer-events requiredExtensions requiredFeatures rotate shape-rendering stop-color stop-opacity stroke stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width style systemLanguage text-anchor text-decoration text-rendering textLength transform unicode-bidi visibility word-spacing writing-mode x xml:base xml:lang xml:space y],
+ 'textPath' => %w[alignment-baseline baseline-shift class clip clip-path clip-rule color color-interpolation color-interpolation-filters color-profile color-rendering cursor direction display dominant-baseline enable-background externalResourcesRequired fill fill-opacity fill-rule filter flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight glyph-orientation-horizontal glyph-orientation-vertical id image-rendering kerning lengthAdjust letter-spacing lighting-color marker-end marker-mid marker-start mask method onactivate onclick onfocusin onfocusout onload onmousedown onmousemove onmouseout onmouseover onmouseup opacity overflow pointer-events requiredExtensions requiredFeatures shape-rendering spacing startOffset stop-color stop-opacity stroke stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width style systemLanguage text-anchor text-decoration text-rendering textLength unicode-bidi visibility word-spacing writing-mode xlink:arcrole xlink:href xlink:role xlink:title xlink:type xml:base xml:lang xml:space],
+ 'title' => %w[class id style xml:base xml:lang xml:space],
+ 'tref' => %w[alignment-baseline baseline-shift class clip clip-path clip-rule color color-interpolation color-interpolation-filters color-profile color-rendering cursor direction display dominant-baseline dx dy enable-background externalResourcesRequired fill fill-opacity fill-rule filter flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight glyph-orientation-horizontal glyph-orientation-vertical id image-rendering kerning lengthAdjust letter-spacing lighting-color marker-end marker-mid marker-start mask onactivate onclick onfocusin onfocusout onload onmousedown onmousemove onmouseout onmouseover onmouseup opacity overflow pointer-events requiredExtensions requiredFeatures rotate shape-rendering stop-color stop-opacity stroke stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width style systemLanguage text-anchor text-decoration text-rendering textLength unicode-bidi visibility word-spacing writing-mode x xlink:arcrole xlink:href xlink:role xlink:title xlink:type xml:base xml:lang xml:space y],
+ 'tspan' => %w[alignment-baseline baseline-shift class clip clip-path clip-rule color color-interpolation color-interpolation-filters color-profile color-rendering cursor direction display dominant-baseline dx dy enable-background externalResourcesRequired fill fill-opacity fill-rule filter flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight glyph-orientation-horizontal glyph-orientation-vertical id image-rendering kerning lengthAdjust letter-spacing lighting-color marker-end marker-mid marker-start mask onactivate onclick onfocusin onfocusout onload onmousedown onmousemove onmouseout onmouseover onmouseup opacity overflow pointer-events requiredExtensions requiredFeatures rotate shape-rendering stop-color stop-opacity stroke stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width style systemLanguage text-anchor text-decoration text-rendering textLength unicode-bidi visibility word-spacing writing-mode x xml:base xml:lang xml:space y],
+ 'use' => %w[alignment-baseline baseline-shift class clip clip-path clip-rule color color-interpolation color-interpolation-filters color-profile color-rendering cursor direction display dominant-baseline enable-background externalResourcesRequired fill fill-opacity fill-rule filter flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight glyph-orientation-horizontal glyph-orientation-vertical height id image-rendering kerning letter-spacing lighting-color marker-end marker-mid marker-start mask onactivate onclick onfocusin onfocusout onload onmousedown onmousemove onmouseout onmouseover onmouseup opacity overflow pointer-events requiredExtensions requiredFeatures shape-rendering stop-color stop-opacity stroke stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width style systemLanguage text-anchor text-decoration text-rendering transform unicode-bidi visibility width word-spacing writing-mode x xlink:actuate xlink:arcrole xlink:href xlink:role xlink:show xlink:title xlink:type xml:base xml:lang xml:space y],
+ 'view' => %w[externalResourcesRequired id preserveAspectRatio viewBox viewTarget xml:base xml:lang xml:space zoomAndPan],
+ 'vkern' => %w[g1 g2 id k u1 u2 xml:base xml:lang xml:space]
+ }.freeze
+ end
end
end
end
diff --git a/lib/gitlab/import_url.rb b/lib/gitlab/url_sanitizer.rb
index 3cfbc17b89b..c59d53b941a 100644
--- a/lib/gitlab/import_url.rb
+++ b/lib/gitlab/url_sanitizer.rb
@@ -1,7 +1,13 @@
module Gitlab
- class ImportUrl
+ class UrlSanitizer
+ def self.sanitize(content)
+ regexp = URI::Parser.new.make_regexp(['http', 'https', 'ssh', 'git'])
+
+ content.gsub(regexp) { |url| new(url).masked_url }
+ end
+
def initialize(url, credentials: nil)
- @url = URI.parse(url)
+ @url = Addressable::URI.parse(URI.encode(url))
@credentials = credentials
end
@@ -9,6 +15,13 @@ module Gitlab
@sanitized_url ||= safe_url.to_s
end
+ def masked_url
+ url = @url.dup
+ url.password = "*****" unless url.password.nil?
+ url.user = "*****" unless url.user.nil?
+ url.to_s
+ end
+
def credentials
@credentials ||= { user: @url.user, password: @url.password }
end
diff --git a/lib/support/nginx/registry-ssl b/lib/support/nginx/registry-ssl
new file mode 100644
index 00000000000..92511e26861
--- /dev/null
+++ b/lib/support/nginx/registry-ssl
@@ -0,0 +1,53 @@
+## Lines starting with two hashes (##) are comments with information.
+## Lines starting with one hash (#) are configuration parameters that can be uncommented.
+##
+###################################
+## configuration ##
+###################################
+
+## Redirects all HTTP traffic to the HTTPS host
+server {
+ listen *:80;
+ server_name registry.gitlab.example.com;
+ server_tokens off; ## Don't show the nginx version number, a security best practice
+ return 301 https://$http_host:$request_uri;
+ access_log /var/log/nginx/gitlab_registry_access.log gitlab_access;
+ error_log /var/log/nginx/gitlab_registry_error.log;
+}
+
+server {
+ # If a different port is specified in https://gitlab.com/gitlab-org/gitlab-ce/blob/8-8-stable/config/gitlab.yml.example#L182,
+ # it should be declared here as well
+ listen *:443 ssl http2;
+ server_name registry.gitlab.example.com;
+ server_tokens off; ## Don't show the nginx version number, a security best practice
+
+ client_max_body_size 0;
+ chunked_transfer_encoding on;
+
+ ## Strong SSL Security
+ ## https://raymii.org/s/tutorials/Strong_SSL_Security_On_nginx.html & https://cipherli.st/
+ ssl on;
+ ssl_certificate /etc/gitlab/ssl/registry.gitlab.example.com.crt
+ ssl_certificate_key /etc/gitlab/ssl/registry.gitlab.example.com.key
+
+ ssl_ciphers 'ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA:ECDHE-RSA-AES128-SHA:ECDHE-RSA-DES-CBC3-SHA:AES256-GCM-SHA384:AES128-GCM-SHA256:AES256-SHA256:AES128-SHA256:AES256-SHA:AES128-SHA:DES-CBC3-SHA:!aNULL:!eNULL:!EXPORT:!DES:!MD5:!PSK:!RC4';
+ ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
+ ssl_prefer_server_ciphers on;
+ ssl_session_cache builtin:1000 shared:SSL:10m;
+ ssl_session_timeout 5m;
+
+ access_log /var/log/gitlab/nginx/gitlab_registry_access.log gitlab_access;
+ error_log /var/log/gitlab/nginx/gitlab_registry_error.log;
+
+ location / {
+ proxy_set_header Host $http_host; # required for docker client's sake
+ proxy_set_header X-Real-IP $remote_addr; # pass on real client's IP
+ proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
+ proxy_set_header X-Forwarded-Proto $scheme;
+ proxy_read_timeout 900;
+
+ proxy_pass http://localhost:5000;
+ }
+
+}
diff --git a/lib/tasks/gitlab/backup.rake b/lib/tasks/gitlab/backup.rake
index 402bb338f27..d97d974ec20 100644
--- a/lib/tasks/gitlab/backup.rake
+++ b/lib/tasks/gitlab/backup.rake
@@ -14,6 +14,7 @@ namespace :gitlab do
Rake::Task["gitlab:backup:builds:create"].invoke
Rake::Task["gitlab:backup:artifacts:create"].invoke
Rake::Task["gitlab:backup:lfs:create"].invoke
+ Rake::Task["gitlab:backup:registry:create"].invoke
backup = Backup::Manager.new
backup.pack
@@ -54,6 +55,7 @@ namespace :gitlab do
Rake::Task['gitlab:backup:builds:restore'].invoke unless backup.skipped?('builds')
Rake::Task['gitlab:backup:artifacts:restore'].invoke unless backup.skipped?('artifacts')
Rake::Task['gitlab:backup:lfs:restore'].invoke unless backup.skipped?('lfs')
+ Rake::Task['gitlab:backup:registry:restore'].invoke unless backup.skipped?('registry')
Rake::Task['gitlab:shell:setup'].invoke
backup.cleanup
@@ -173,6 +175,25 @@ namespace :gitlab do
end
end
+ namespace :registry do
+ task create: :environment do
+ $progress.puts "Dumping container registry images ... ".blue
+
+ if ENV["SKIP"] && ENV["SKIP"].include?("registry")
+ $progress.puts "[SKIPPED]".cyan
+ else
+ Backup::Registry.new.dump
+ $progress.puts "done".green
+ end
+ end
+
+ task restore: :environment do
+ $progress.puts "Restoring container registry images ... ".blue
+ Backup::Registry.new.restore
+ $progress.puts "done".green
+ end
+ end
+
def configure_cron_mode
if ENV['CRON']
# We need an object we can say 'puts' and 'print' to; let's use a
diff --git a/lib/tasks/gitlab/check.rake b/lib/tasks/gitlab/check.rake
index effb8eb6001..fad89c73762 100644
--- a/lib/tasks/gitlab/check.rake
+++ b/lib/tasks/gitlab/check.rake
@@ -303,7 +303,7 @@ namespace :gitlab do
else
puts "no".red
try_fixing_it(
- "sudo find #{upload_path} -type d -not -path #{upload_path} -exec chmod 0700 {} \\;"
+ "sudo chmod 700 #{upload_path}"
)
for_more_information(
see_installation_guide_section "GitLab"
diff --git a/lib/tasks/gitlab/update_gitignore.rake b/lib/tasks/gitlab/update_gitignore.rake
new file mode 100644
index 00000000000..84aa312002b
--- /dev/null
+++ b/lib/tasks/gitlab/update_gitignore.rake
@@ -0,0 +1,46 @@
+namespace :gitlab do
+ desc "GitLab | Update gitignore"
+ task :update_gitignore do
+ unless clone_gitignores
+ puts "Cloning the gitignores failed".red
+ return
+ end
+
+ remove_unneeded_files(gitignore_directory)
+ remove_unneeded_files(global_directory)
+
+ puts "Done".green
+ end
+
+ def clone_gitignores
+ FileUtils.rm_rf(gitignore_directory) if Dir.exist?(gitignore_directory)
+ FileUtils.cd vendor_directory
+
+ system('git clone --depth=1 --branch=master https://github.com/github/gitignore.git')
+ end
+
+ # Retain only certain files:
+ # - The LICENSE, because we have to
+ # - The sub dir global
+ # - The gitignores themself
+ # - Dir.entires returns also the entries '.' and '..'
+ def remove_unneeded_files(path)
+ Dir.foreach(path) do |file|
+ FileUtils.rm_rf(File.join(path, file)) unless file =~ /(\.{1,2}|LICENSE|Global|\.gitignore)\z/
+ end
+ end
+
+ private
+
+ def vendor_directory
+ Rails.root.join('vendor')
+ end
+
+ def gitignore_directory
+ File.join(vendor_directory, 'gitignore')
+ end
+
+ def global_directory
+ File.join(gitignore_directory, 'Global')
+ end
+end
diff --git a/shared/registry/.gitkeep b/shared/registry/.gitkeep
new file mode 100644
index 00000000000..e69de29bb2d
--- /dev/null
+++ b/shared/registry/.gitkeep
diff --git a/spec/controllers/projects/notification_settings_controller_spec.rb b/spec/controllers/projects/notification_settings_controller_spec.rb
index 4908b545648..c5d17d97ec9 100644
--- a/spec/controllers/projects/notification_settings_controller_spec.rb
+++ b/spec/controllers/projects/notification_settings_controller_spec.rb
@@ -34,5 +34,19 @@ describe Projects::NotificationSettingsController do
expect(response.status).to eq 200
end
end
+
+ context 'not authorized' do
+ let(:private_project) { create(:project, :private) }
+ before { sign_in(user) }
+
+ it 'returns 404' do
+ put :update,
+ namespace_id: private_project.namespace.to_param,
+ project_id: private_project.to_param,
+ notification_setting: { level: :participating }
+
+ expect(response.status).to eq(404)
+ end
+ end
end
end
diff --git a/spec/controllers/projects/raw_controller_spec.rb b/spec/controllers/projects/raw_controller_spec.rb
index 1caa476d37d..fb29274c687 100644
--- a/spec/controllers/projects/raw_controller_spec.rb
+++ b/spec/controllers/projects/raw_controller_spec.rb
@@ -42,7 +42,7 @@ describe Projects::RawController do
before do
public_project.lfs_objects << lfs_object
allow_any_instance_of(LfsObjectUploader).to receive(:exists?).and_return(true)
- allow(controller).to receive(:send_file) { controller.render nothing: true }
+ allow(controller).to receive(:send_file) { controller.head :ok }
end
it 'serves the file' do
diff --git a/spec/controllers/projects_controller_spec.rb b/spec/controllers/projects_controller_spec.rb
index 069cd917e5a..91b46c4d65c 100644
--- a/spec/controllers/projects_controller_spec.rb
+++ b/spec/controllers/projects_controller_spec.rb
@@ -8,6 +8,40 @@ describe ProjectsController do
let(:txt) { fixture_file_upload(Rails.root + 'spec/fixtures/doc_sample.txt', 'text/plain') }
describe "GET show" do
+ context "user not project member" do
+ before { sign_in(user) }
+
+ context "user does not have access to project" do
+ let(:private_project) { create(:project, :private) }
+
+ it "does not initialize notification setting" do
+ get :show, namespace_id: private_project.namespace.path, id: private_project.path
+ expect(assigns(:notification_setting)).to be_nil
+ end
+ end
+
+ context "user has access to project" do
+ context "and does not have notification setting" do
+ it "initializes notification as disabled" do
+ get :show, namespace_id: public_project.namespace.path, id: public_project.path
+ expect(assigns(:notification_setting).level).to eq("global")
+ end
+ end
+
+ context "and has notification setting" do
+ before do
+ setting = user.notification_settings_for(public_project)
+ setting.level = :watch
+ setting.save
+ end
+
+ it "shows current notification setting" do
+ get :show, namespace_id: public_project.namespace.path, id: public_project.path
+ expect(assigns(:notification_setting).level).to eq("watch")
+ end
+ end
+ end
+ end
context "rendering default project view" do
render_views
diff --git a/spec/factories/todos.rb b/spec/factories/todos.rb
index e3681ae93a5..f426e27afed 100644
--- a/spec/factories/todos.rb
+++ b/spec/factories/todos.rb
@@ -18,5 +18,9 @@ FactoryGirl.define do
commit_id RepoHelpers.sample_commit.id
target_type "Commit"
end
+
+ trait :build_failed do
+ action { Todo::BUILD_FAILED }
+ end
end
end
diff --git a/spec/features/container_registry_spec.rb b/spec/features/container_registry_spec.rb
new file mode 100644
index 00000000000..53b4f027117
--- /dev/null
+++ b/spec/features/container_registry_spec.rb
@@ -0,0 +1,44 @@
+require 'spec_helper'
+
+describe "Container Registry" do
+ let(:project) { create(:empty_project) }
+ let(:repository) { project.container_registry_repository }
+ let(:tag_name) { 'latest' }
+ let(:tags) { [tag_name] }
+
+ before do
+ login_as(:user)
+ project.team << [@user, :developer]
+ stub_container_registry_tags(*tags)
+ stub_container_registry_config(enabled: true)
+ allow(Auth::ContainerRegistryAuthenticationService).to receive(:full_access_token).and_return('token')
+ end
+
+ describe 'GET /:project/container_registry' do
+ before do
+ visit namespace_project_container_registry_index_path(project.namespace, project)
+ end
+
+ context 'when no tags' do
+ let(:tags) { [] }
+
+ it { expect(page).to have_content('No images in Container Registry for this project') }
+ end
+
+ context 'when there are tags' do
+ it { expect(page).to have_content(tag_name)}
+ end
+ end
+
+ describe 'DELETE /:project/container_registry/tag' do
+ before do
+ visit namespace_project_container_registry_index_path(project.namespace, project)
+ end
+
+ it do
+ expect_any_instance_of(::ContainerRegistry::Tag).to receive(:delete).and_return(true)
+
+ click_on 'Remove'
+ end
+ end
+end
diff --git a/spec/features/issues_spec.rb b/spec/features/issues_spec.rb
index d5755c293c5..dd114db7e88 100644
--- a/spec/features/issues_spec.rb
+++ b/spec/features/issues_spec.rb
@@ -64,6 +64,64 @@ describe 'Issues', feature: true do
end
end
+ describe 'due date', js: true do
+ context 'on new form' do
+ before do
+ visit new_namespace_project_issue_path(project.namespace, project)
+ end
+
+ it 'should save with due date' do
+ date = Date.today.at_beginning_of_month
+
+ fill_in 'issue_title', with: 'bug 345'
+ fill_in 'issue_description', with: 'bug description'
+
+ page.within '.datepicker' do
+ click_link date.day
+ end
+
+ expect(find('#issuable-due-date', visible: false).value).to eq date.to_s
+
+ click_button 'Submit issue'
+
+ page.within '.issuable-sidebar' do
+ expect(page).to have_content date.to_s(:medium)
+ end
+ end
+ end
+
+ context 'on edit form' do
+ let(:issue) { create(:issue, author: @user,project: project, due_date: Date.today.at_beginning_of_month.to_s) }
+
+ before do
+ visit edit_namespace_project_issue_path(project.namespace, project, issue)
+ end
+
+ it 'should save with due date' do
+ date = Date.today.at_beginning_of_month
+
+ expect(find('#issuable-due-date', visible: false).value).to eq date.to_s
+
+ date = date.tomorrow
+
+ fill_in 'issue_title', with: 'bug 345'
+ fill_in 'issue_description', with: 'bug description'
+
+ page.within '.datepicker' do
+ click_link date.day
+ end
+
+ expect(find('#issuable-due-date', visible: false).value).to eq date.to_s
+
+ click_button 'Save changes'
+
+ page.within '.issuable-sidebar' do
+ expect(page).to have_content date.to_s(:medium)
+ end
+ end
+ end
+ end
+
describe 'Issue info' do
it 'excludes award_emoji from comment count' do
issue = create(:issue, author: @user, assignee: @user, project: project, title: 'foobar')
@@ -331,7 +389,7 @@ describe 'Issues', feature: true do
page.within '.assignee' do
click_link 'Edit'
end
-
+
page.within '.dropdown-menu-user' do
click_link @user.name
end
diff --git a/spec/features/markdown_spec.rb b/spec/features/markdown_spec.rb
index 0148c87084a..1d892fe1a55 100644
--- a/spec/features/markdown_spec.rb
+++ b/spec/features/markdown_spec.rb
@@ -278,6 +278,10 @@ describe 'GitLab Markdown', feature: true do
it 'includes GollumTagsFilter' do
expect(doc).to parse_gollum_tags
end
+
+ it 'includes InlineDiffFilter' do
+ expect(doc).to parse_inline_diffs
+ end
end
# Fake a `current_user` helper
diff --git a/spec/features/pipelines_spec.rb b/spec/features/pipelines_spec.rb
new file mode 100644
index 00000000000..1d6f4485c81
--- /dev/null
+++ b/spec/features/pipelines_spec.rb
@@ -0,0 +1,159 @@
+require 'spec_helper'
+
+describe "Pipelines" do
+ include GitlabRoutingHelper
+
+ let(:project) { create(:empty_project) }
+ let(:user) { create(:user) }
+
+ before do
+ login_as(user)
+ project.team << [user, :developer]
+ end
+
+ describe 'GET /:project/pipelines' do
+ let!(:pipeline) { create(:ci_commit, project: project, ref: 'master', status: 'running') }
+
+ [:all, :running, :branches].each do |scope|
+ context "displaying #{scope}" do
+ let(:project) { create(:project) }
+
+ before { visit namespace_project_pipelines_path(project.namespace, project, scope: scope) }
+
+ it { expect(page).to have_content(pipeline.short_sha) }
+ end
+ end
+
+ context 'anonymous access' do
+ before { visit namespace_project_pipelines_path(project.namespace, project) }
+
+ it { expect(page).to have_http_status(:success) }
+ end
+
+ context 'cancelable pipeline' do
+ let!(:running) { create(:ci_build, :running, commit: pipeline, stage: 'test', commands: 'test') }
+
+ before { visit namespace_project_pipelines_path(project.namespace, project) }
+
+ it { expect(page).to have_link('Cancel') }
+ it { expect(page).to have_selector('.ci-running') }
+
+ context 'when canceling' do
+ before { click_link('Cancel') }
+
+ it { expect(page).to_not have_link('Cancel') }
+ it { expect(page).to have_selector('.ci-canceled') }
+ end
+ end
+
+ context 'retryable pipelines' do
+ let!(:failed) { create(:ci_build, :failed, commit: pipeline, stage: 'test', commands: 'test') }
+
+ before { visit namespace_project_pipelines_path(project.namespace, project) }
+
+ it { expect(page).to have_link('Retry') }
+ it { expect(page).to have_selector('.ci-failed') }
+
+ context 'when retrying' do
+ before { click_link('Retry') }
+
+ it { expect(page).to_not have_link('Retry') }
+ it { expect(page).to have_selector('.ci-pending') }
+ end
+ end
+
+ context 'downloadable pipelines' do
+ context 'with artifacts' do
+ let!(:with_artifacts) { create(:ci_build, :artifacts, :success, commit: pipeline, name: 'rspec tests', stage: 'test') }
+
+ before { visit namespace_project_pipelines_path(project.namespace, project) }
+
+ it { expect(page).to have_selector('.build-artifacts') }
+ it { expect(page).to have_link(with_artifacts.name) }
+ end
+
+ context 'without artifacts' do
+ let!(:without_artifacts) { create(:ci_build, :success, commit: pipeline, name: 'rspec', stage: 'test') }
+
+ it { expect(page).to_not have_selector('.build-artifacts') }
+ end
+ end
+ end
+
+ describe 'GET /:project/pipelines/:id' do
+ let(:pipeline) { create(:ci_commit, project: project, ref: 'master') }
+
+ before do
+ @success = create(:ci_build, :success, commit: pipeline, stage: 'build', name: 'build')
+ @failed = create(:ci_build, :failed, commit: pipeline, stage: 'test', name: 'test', commands: 'test')
+ @running = create(:ci_build, :running, commit: pipeline, stage: 'deploy', name: 'deploy')
+ @external = create(:generic_commit_status, status: 'success', commit: pipeline, name: 'jenkins', stage: 'external')
+ end
+
+ before { visit namespace_project_pipeline_path(project.namespace, project, pipeline) }
+
+ it 'showing a list of builds' do
+ expect(page).to have_content('Tests')
+ expect(page).to have_content(@success.id)
+ expect(page).to have_content('Deploy')
+ expect(page).to have_content(@failed.id)
+ expect(page).to have_content(@running.id)
+ expect(page).to have_content(@external.id)
+ expect(page).to have_content('Retry failed')
+ expect(page).to have_content('Cancel running')
+ end
+
+ context 'retrying builds' do
+ it { expect(page).to_not have_content('retried') }
+
+ context 'when retrying' do
+ before { click_on 'Retry failed' }
+
+ it { expect(page).to_not have_content('Retry failed') }
+ it { expect(page).to have_content('retried') }
+ end
+ end
+
+ context 'canceling builds' do
+ it { expect(page).to_not have_selector('.ci-canceled') }
+
+ context 'when canceling' do
+ before { click_on 'Cancel running' }
+
+ it { expect(page).to_not have_content('Cancel running') }
+ it { expect(page).to have_selector('.ci-canceled') }
+ end
+ end
+ end
+
+ describe 'POST /:project/pipelines' do
+ let(:project) { create(:project) }
+
+ before { visit new_namespace_project_pipeline_path(project.namespace, project) }
+
+ context 'for valid commit' do
+ before { fill_in('Create for', with: 'master') }
+
+ context 'with gitlab-ci.yml' do
+ before { stub_ci_commit_to_return_yaml_file }
+
+ it { expect{ click_on 'Create pipeline' }.to change{ Ci::Commit.count }.by(1) }
+ end
+
+ context 'without gitlab-ci.yml' do
+ before { click_on 'Create pipeline' }
+
+ it { expect(page).to have_content('Missing .gitlab-ci.yml file') }
+ end
+ end
+
+ context 'for invalid commit' do
+ before do
+ fill_in('Create for', with: 'invalid reference')
+ click_on 'Create pipeline'
+ end
+
+ it { expect(page).to have_content('Reference not found') }
+ end
+ end
+end
diff --git a/spec/features/projects/files/gitignore_dropdown_spec.rb b/spec/features/projects/files/gitignore_dropdown_spec.rb
new file mode 100644
index 00000000000..073a83b6896
--- /dev/null
+++ b/spec/features/projects/files/gitignore_dropdown_spec.rb
@@ -0,0 +1,30 @@
+require 'spec_helper'
+
+feature 'User wants to add a .gitignore file', feature: true do
+ include WaitForAjax
+
+ before do
+ user = create(:user)
+ project = create(:project)
+ project.team << [user, :master]
+ login_as user
+ visit namespace_project_new_blob_path(project.namespace, project, 'master', file_name: '.gitignore')
+ end
+
+ scenario 'user can see .gitignore dropdown' do
+ expect(page).to have_css('.gitignore-selector')
+ end
+
+ scenario 'user can pick a .gitignore file from the dropdown', js: true do
+ find('.js-gitignore-selector').click
+ wait_for_ajax
+ within '.gitignore-selector' do
+ find('.dropdown-input-field').set('rails')
+ find('.dropdown-content li', text: 'Rails').click
+ end
+ wait_for_ajax
+
+ expect(page).to have_content('/.bundle')
+ expect(page).to have_content('# Gemfile.lock, .ruby-version, .ruby-gemset')
+ end
+end
diff --git a/spec/features/projects/files/project_owner_creates_license_file_spec.rb b/spec/features/projects/files/project_owner_creates_license_file_spec.rb
index 3d6ffbc4c6b..ecc818eb1e1 100644
--- a/spec/features/projects/files/project_owner_creates_license_file_spec.rb
+++ b/spec/features/projects/files/project_owner_creates_license_file_spec.rb
@@ -25,7 +25,7 @@ feature 'project owner creates a license file', feature: true, js: true do
file_content = find('.file-content')
expect(file_content).to have_content('The MIT License (MIT)')
- expect(file_content).to have_content("Copyright (c) 2016 #{project.namespace.human_name}")
+ expect(file_content).to have_content("Copyright (c) #{Time.now.year} #{project.namespace.human_name}")
fill_in :commit_message, with: 'Add a LICENSE file', visible: true
click_button 'Commit Changes'
@@ -33,7 +33,7 @@ feature 'project owner creates a license file', feature: true, js: true do
expect(current_path).to eq(
namespace_project_blob_path(project.namespace, project, 'master/LICENSE'))
expect(page).to have_content('The MIT License (MIT)')
- expect(page).to have_content("Copyright (c) 2016 #{project.namespace.human_name}")
+ expect(page).to have_content("Copyright (c) #{Time.now.year} #{project.namespace.human_name}")
end
scenario 'project master creates a license file from the "Add license" link' do
@@ -48,7 +48,7 @@ feature 'project owner creates a license file', feature: true, js: true do
file_content = find('.file-content')
expect(file_content).to have_content('The MIT License (MIT)')
- expect(file_content).to have_content("Copyright (c) 2016 #{project.namespace.human_name}")
+ expect(file_content).to have_content("Copyright (c) #{Time.now.year} #{project.namespace.human_name}")
fill_in :commit_message, with: 'Add a LICENSE file', visible: true
click_button 'Commit Changes'
@@ -56,6 +56,6 @@ feature 'project owner creates a license file', feature: true, js: true do
expect(current_path).to eq(
namespace_project_blob_path(project.namespace, project, 'master/LICENSE'))
expect(page).to have_content('The MIT License (MIT)')
- expect(page).to have_content("Copyright (c) 2016 #{project.namespace.human_name}")
+ expect(page).to have_content("Copyright (c) #{Time.now.year} #{project.namespace.human_name}")
end
end
diff --git a/spec/features/projects/files/project_owner_sees_link_to_create_license_file_in_empty_project_spec.rb b/spec/features/projects/files/project_owner_sees_link_to_create_license_file_in_empty_project_spec.rb
index 3268e240200..34eda29c285 100644
--- a/spec/features/projects/files/project_owner_sees_link_to_create_license_file_in_empty_project_spec.rb
+++ b/spec/features/projects/files/project_owner_sees_link_to_create_license_file_in_empty_project_spec.rb
@@ -24,7 +24,7 @@ feature 'project owner sees a link to create a license file in empty project', f
file_content = find('.file-content')
expect(file_content).to have_content('The MIT License (MIT)')
- expect(file_content).to have_content("Copyright (c) 2016 #{project.namespace.human_name}")
+ expect(file_content).to have_content("Copyright (c) #{Time.now.year} #{project.namespace.human_name}")
fill_in :commit_message, with: 'Add a LICENSE file', visible: true
# Remove pre-receive hook so we can push without auth
@@ -34,6 +34,6 @@ feature 'project owner sees a link to create a license file in empty project', f
expect(current_path).to eq(
namespace_project_blob_path(project.namespace, project, 'master/LICENSE'))
expect(page).to have_content('The MIT License (MIT)')
- expect(page).to have_content("Copyright (c) 2016 #{project.namespace.human_name}")
+ expect(page).to have_content("Copyright (c) #{Time.now.year} #{project.namespace.human_name}")
end
end
diff --git a/spec/features/runners_spec.rb b/spec/features/runners_spec.rb
index 8edeb8d18af..49156130ad3 100644
--- a/spec/features/runners_spec.rb
+++ b/spec/features/runners_spec.rb
@@ -110,4 +110,37 @@ describe "Runners" do
expect(page).to have_content(@specific_runner.platform)
end
end
+
+ feature 'configuring runners ability to picking untagged jobs' do
+ given(:project) { create(:empty_project) }
+ given(:runner) { create(:ci_runner) }
+
+ background do
+ project.team << [user, :master]
+ project.runners << runner
+ end
+
+ scenario 'user checks default configuration' do
+ visit namespace_project_runner_path(project.namespace, project, runner)
+
+ expect(page).to have_content 'Can run untagged jobs Yes'
+ end
+
+ context 'when runner has tags' do
+ before { runner.update_attribute(:tag_list, ['tag']) }
+
+ scenario 'user wants to prevent runner from running untagged job' do
+ visit runners_path(project)
+ page.within('.activated-specific-runners') do
+ first('small > a').click
+ end
+
+ uncheck 'runner_run_untagged'
+ click_button 'Save changes'
+
+ expect(page).to have_content 'Can run untagged jobs No'
+ expect(runner.reload.run_untagged?).to eq false
+ end
+ end
+ end
end
diff --git a/spec/features/variables_spec.rb b/spec/features/variables_spec.rb
index afea1840cd7..48e2dae4884 100644
--- a/spec/features/variables_spec.rb
+++ b/spec/features/variables_spec.rb
@@ -1,24 +1,53 @@
require 'spec_helper'
-describe "Variables" do
- let(:user) { create(:user) }
- before { login_as(user) }
-
- describe "specific runners" do
- before do
- @project = FactoryGirl.create :empty_project
- @project.team << [user, :master]
+describe 'Project variables', js: true do
+ let(:user) { create(:user) }
+ let(:project) { create(:project) }
+ let(:variable) { create(:ci_variable, key: 'test') }
+
+ before do
+ login_as(user)
+ project.team << [user, :master]
+ project.variables << variable
+
+ visit namespace_project_variables_path(project.namespace, project)
+ end
+
+ it 'should show list of variables' do
+ page.within('.variables-table') do
+ expect(page).to have_content(variable.key)
+ end
+ end
+
+ it 'should add new variable' do
+ fill_in('variable_key', with: 'key')
+ fill_in('variable_value', with: 'key value')
+ click_button('Add new variable')
+
+ page.within('.variables-table') do
+ expect(page).to have_content('key')
+ end
+ end
+
+ it 'should delete variable' do
+ page.within('.variables-table') do
+ find('.btn-variable-delete').click
+ end
+
+ expect(page).to_not have_selector('variables-table')
+ end
+
+ it 'should edit variable' do
+ page.within('.variables-table') do
+ find('.btn-variable-edit').click
end
- it "creates variable", js: true do
- visit namespace_project_variables_path(@project.namespace, @project)
- click_on "Add a variable"
- fill_in "Key", with: "SECRET_KEY"
- fill_in "Value", with: "SECRET_VALUE"
- click_on "Save changes"
+ fill_in('variable_key', with: 'key')
+ fill_in('variable_value', with: 'key value')
+ click_button('Save variable')
- expect(page).to have_content("Variables were successfully updated.")
- expect(@project.variables.count).to eq(1)
+ page.within('.variables-table') do
+ expect(page).to have_content('key')
end
end
end
diff --git a/spec/fixtures/container_registry/config_blob.json b/spec/fixtures/container_registry/config_blob.json
new file mode 100644
index 00000000000..1028c994a24
--- /dev/null
+++ b/spec/fixtures/container_registry/config_blob.json
@@ -0,0 +1 @@
+{"architecture":"amd64","config":{"Hostname":"b14cd8298755","Domainname":"","User":"","AttachStdin":false,"AttachStdout":false,"AttachStderr":false,"Tty":false,"OpenStdin":false,"StdinOnce":false,"Env":null,"Cmd":null,"Image":"","Volumes":null,"WorkingDir":"","Entrypoint":null,"OnBuild":null,"Labels":null},"container":"b14cd82987550b01af9a666a2f4c996280a6152e66873134fae5a0f223dc5976","container_config":{"Hostname":"b14cd8298755","Domainname":"","User":"","AttachStdin":false,"AttachStdout":false,"AttachStderr":false,"Tty":false,"OpenStdin":false,"StdinOnce":false,"Env":null,"Cmd":["/bin/sh","-c","#(nop) ADD file:033ab063740d9ff4dcfb1c69eccf25f91d88729f57cd5a73050e014e3e094aa0 in /"],"Image":"","Volumes":null,"WorkingDir":"","Entrypoint":null,"OnBuild":null,"Labels":null},"created":"2016-04-01T20:53:00.160300546Z","docker_version":"1.9.1","history":[{"created":"2016-04-01T20:53:00.160300546Z","created_by":"/bin/sh -c #(nop) ADD file:033ab063740d9ff4dcfb1c69eccf25f91d88729f57cd5a73050e014e3e094aa0 in /"}],"os":"linux","rootfs":{"type":"layers","diff_ids":["sha256:c56b7dabbc7aa730eeab07668bdcbd7e3d40855047ca9a0cc1bfed23a2486111"]}}
diff --git a/spec/fixtures/container_registry/tag_manifest.json b/spec/fixtures/container_registry/tag_manifest.json
new file mode 100644
index 00000000000..1b6008e2872
--- /dev/null
+++ b/spec/fixtures/container_registry/tag_manifest.json
@@ -0,0 +1 @@
+{"schemaVersion":2,"mediaType":"application/vnd.docker.distribution.manifest.v2+json","config":{"mediaType":"application/octet-stream","size":1145,"digest":"sha256:d7a513a663c1a6dcdba9ed832ca53c02ac2af0c333322cd6ca92936d1d9917ac"},"layers":[{"mediaType":"application/vnd.docker.image.rootfs.diff.tar.gzip","size":2319870,"digest":"sha256:420890c9e918b6668faaedd9000e220190f2493b0693ee563ebd7b4cc754a57d"}]}
diff --git a/spec/fixtures/markdown.md.erb b/spec/fixtures/markdown.md.erb
index 1772cc3f6a4..34ce7c4f033 100644
--- a/spec/fixtures/markdown.md.erb
+++ b/spec/fixtures/markdown.md.erb
@@ -216,10 +216,14 @@ References should be parseable even inside _<%= merge_request.to_reference %>_ e
#### MilestoneReferenceFilter
-- Milestone: <%= milestone.to_reference %>
+- Milestone by ID: <%= simple_milestone.to_reference %>
+- Milestone by name: <%= Milestone.reference_prefix %><%= simple_milestone.name %>
+- Milestone by name in quotes: <%= milestone.to_reference(format: :name) %>
- Milestone in another project: <%= xmilestone.to_reference(project) %>
-- Ignored in code: `<%= milestone.to_reference %>`
-- Link to milestone by URL: [Milestone](<%= urls.namespace_project_milestone_url(milestone.project.namespace, milestone.project, milestone) %>)
+- Ignored in code: `<%= simple_milestone.to_reference %>`
+- Ignored in links: [Link to <%= simple_milestone.to_reference %>](#milestone-link)
+- Milestone by URL: <%= urls.namespace_project_milestone_url(milestone.project.namespace, milestone.project, milestone) %>
+- Link to milestone by URL: [Milestone](<%= milestone.to_reference %>)
### Task Lists
@@ -239,3 +243,16 @@ References should be parseable even inside _<%= merge_request.to_reference %>_ e
- [[link-text|http://example.com/pdfs/gollum.pdf]]
- [[images/example.jpg]]
- [[http://example.com/images/example.jpg]]
+
+### Inline Diffs
+
+With inline diffs tags you can display {+ additions +} or [- deletions -].
+
+The wrapping tags can be either curly braces or square brackets [+ additions +] or {- deletions -}.
+
+However the wrapping tags can not be mixed as such -
+
+- {+ additions +]
+- [+ additions +}
+- {- delletions -]
+- [- delletions -}
diff --git a/spec/helpers/diff_helper_spec.rb b/spec/helpers/diff_helper_spec.rb
index b7810185d16..52764f41e0d 100644
--- a/spec/helpers/diff_helper_spec.rb
+++ b/spec/helpers/diff_helper_spec.rb
@@ -93,9 +93,9 @@ describe DiffHelper do
it "returns strings with marked inline diffs" do
marked_old_line, marked_new_line = mark_inline_diffs(old_line, new_line)
- expect(marked_old_line).to eq("abc <span class='idiff left right'>&#39;def&#39;</span>")
+ expect(marked_old_line).to eq("abc <span class='idiff left right deletion'>&#39;def&#39;</span>")
expect(marked_old_line).to be_html_safe
- expect(marked_new_line).to eq("abc <span class='idiff left right'>&quot;def&quot;</span>")
+ expect(marked_new_line).to eq("abc <span class='idiff left right addition'>&quot;def&quot;</span>")
expect(marked_new_line).to be_html_safe
end
end
diff --git a/spec/javascripts/project_title_spec.js.coffee b/spec/javascripts/project_title_spec.js.coffee
index 3d8de2ff989..1cf34d4d2d3 100644
--- a/spec/javascripts/project_title_spec.js.coffee
+++ b/spec/javascripts/project_title_spec.js.coffee
@@ -1,5 +1,6 @@
#= require bootstrap
#= require select2
+#= require lib/type_utility
#= require gl_dropdown
#= require api
#= require project_select
diff --git a/spec/lib/banzai/filter/inline_diff_filter_spec.rb b/spec/lib/banzai/filter/inline_diff_filter_spec.rb
new file mode 100644
index 00000000000..9e526371294
--- /dev/null
+++ b/spec/lib/banzai/filter/inline_diff_filter_spec.rb
@@ -0,0 +1,68 @@
+require 'spec_helper'
+
+describe Banzai::Filter::InlineDiffFilter, lib: true do
+ include FilterSpecHelper
+
+ it 'adds inline diff span tags for deletions when using square brackets' do
+ doc = "START [-something deleted-] END"
+ expect(filter(doc).to_html).to eq('START <span class="idiff left right deletion">something deleted</span> END')
+ end
+
+ it 'adds inline diff span tags for deletions when using curley braces' do
+ doc = "START {-something deleted-} END"
+ expect(filter(doc).to_html).to eq('START <span class="idiff left right deletion">something deleted</span> END')
+ end
+
+ it 'does not add inline diff span tags when a closing tag is not provided' do
+ doc = "START [- END"
+ expect(filter(doc).to_html).to eq(doc)
+ end
+
+ it 'adds inline span tags for additions when using square brackets' do
+ doc = "START [+something added+] END"
+ expect(filter(doc).to_html).to eq('START <span class="idiff left right addition">something added</span> END')
+ end
+
+ it 'adds inline span tags for additions when using curley braces' do
+ doc = "START {+something added+} END"
+ expect(filter(doc).to_html).to eq('START <span class="idiff left right addition">something added</span> END')
+ end
+
+ it 'does not add inline diff span tags when a closing addition tag is not provided' do
+ doc = "START {+ END"
+ expect(filter(doc).to_html).to eq(doc)
+ end
+
+ it 'does not add inline diff span tags when the tags do not match' do
+ examples = [
+ "{+ additions +]",
+ "[+ additions +}",
+ "{- delletions -]",
+ "[- delletions -}"
+ ]
+
+ examples.each do |doc|
+ expect(filter(doc).to_html).to eq(doc)
+ end
+ end
+
+ it 'prevents user-land html being injected' do
+ doc = "START {+&lt;script&gt;alert('I steal cookies')&lt;/script&gt;+} END"
+ expect(filter(doc).to_html).to eq("START <span class=\"idiff left right addition\">&lt;script&gt;alert('I steal cookies')&lt;/script&gt;</span> END")
+ end
+
+ it 'preserves content inside pre tags' do
+ doc = "<pre>START {+something added+} END</pre>"
+ expect(filter(doc).to_html).to eq(doc)
+ end
+
+ it 'preserves content inside code tags' do
+ doc = "<code>START {+something added+} END</code>"
+ expect(filter(doc).to_html).to eq(doc)
+ end
+
+ it 'preserves content inside tt tags' do
+ doc = "<tt>START {+something added+} END</tt>"
+ expect(filter(doc).to_html).to eq(doc)
+ end
+end
diff --git a/spec/lib/banzai/filter/milestone_reference_filter_spec.rb b/spec/lib/banzai/filter/milestone_reference_filter_spec.rb
index 5beb61dac5c..bdf48eabb0e 100644
--- a/spec/lib/banzai/filter/milestone_reference_filter_spec.rb
+++ b/spec/lib/banzai/filter/milestone_reference_filter_spec.rb
@@ -3,8 +3,9 @@ require 'spec_helper'
describe Banzai::Filter::MilestoneReferenceFilter, lib: true do
include FilterSpecHelper
- let(:project) { create(:project, :public) }
- let(:milestone) { create(:milestone, project: project) }
+ let(:project) { create(:project, :public) }
+ let(:milestone) { create(:milestone, project: project) }
+ let(:reference) { milestone.to_reference }
it 'requires project context' do
expect { described_class.call('') }.to raise_error(ArgumentError, /:project/)
@@ -17,11 +18,42 @@ describe Banzai::Filter::MilestoneReferenceFilter, lib: true do
end
end
- context 'internal reference' do
- # Convert the Markdown link to only the URL, since these tests aren't run through the regular Markdown pipeline.
- # Milestone reference behavior in the full Markdown pipeline is tested elsewhere.
- let(:reference) { milestone.to_reference.gsub(/\[([^\]]+)\]\(([^)]+)\)/, '\2') }
+ it 'includes default classes' do
+ doc = reference_filter("Milestone #{reference}")
+ expect(doc.css('a').first.attr('class')).to eq 'gfm gfm-milestone'
+ end
+
+ it 'includes a data-project attribute' do
+ doc = reference_filter("Milestone #{reference}")
+ link = doc.css('a').first
+
+ expect(link).to have_attribute('data-project')
+ expect(link.attr('data-project')).to eq project.id.to_s
+ end
+
+ it 'includes a data-milestone attribute' do
+ doc = reference_filter("See #{reference}")
+ link = doc.css('a').first
+
+ expect(link).to have_attribute('data-milestone')
+ expect(link.attr('data-milestone')).to eq milestone.id.to_s
+ end
+
+ it 'supports an :only_path context' do
+ doc = reference_filter("Milestone #{reference}", only_path: true)
+ link = doc.css('a').first.attr('href')
+ expect(link).not_to match %r(https?://)
+ expect(link).to eq urls.
+ namespace_project_milestone_path(project.namespace, project, milestone)
+ end
+
+ it 'adds to the results hash' do
+ result = reference_pipeline_result("Milestone #{reference}")
+ expect(result[:references][:milestone]).to eq [milestone]
+ end
+
+ context 'Integer-based references' do
it 'links to a valid reference' do
doc = reference_filter("See #{reference}")
@@ -30,29 +62,82 @@ describe Banzai::Filter::MilestoneReferenceFilter, lib: true do
end
it 'links with adjacent text' do
- doc = reference_filter("milestone (#{reference}.)")
- expect(doc.to_html).to match(/\(<a.+>#{Regexp.escape(milestone.title)}<\/a>\.\)/)
+ doc = reference_filter("Milestone (#{reference}.)")
+ expect(doc.to_html).to match(%r(\(<a.+>#{milestone.name}</a>\.\)))
end
- it 'includes a title attribute' do
- doc = reference_filter("milestone #{reference}")
- expect(doc.css('a').first.attr('title')).to eq "Milestone: #{milestone.title}"
+ it 'ignores invalid milestone IIDs' do
+ exp = act = "Milestone #{invalidate_reference(reference)}"
+
+ expect(reference_filter(act).to_html).to eq exp
end
+ end
+
+ context 'String-based single-word references' do
+ let(:milestone) { create(:milestone, name: 'gfm', project: project) }
+ let(:reference) { "#{Milestone.reference_prefix}#{milestone.name}" }
- it 'escapes the title attribute' do
- milestone.update_attribute(:title, %{"></a>whatever<a title="})
+ it 'links to a valid reference' do
+ doc = reference_filter("See #{reference}")
+
+ expect(doc.css('a').first.attr('href')).to eq urls.
+ namespace_project_milestone_url(project.namespace, project, milestone)
+ expect(doc.text).to eq 'See gfm'
+ end
- doc = reference_filter("milestone #{reference}")
- expect(doc.text).to eq "milestone \">whatever"
+ it 'links with adjacent text' do
+ doc = reference_filter("Milestone (#{reference}.)")
+ expect(doc.to_html).to match(%r(\(<a.+>#{milestone.name}</a>\.\)))
end
- it 'includes default classes' do
- doc = reference_filter("milestone #{reference}")
- expect(doc.css('a').first.attr('class')).to eq 'gfm gfm-milestone'
+ it 'ignores invalid milestone names' do
+ exp = act = "Milestone #{Milestone.reference_prefix}#{milestone.name.reverse}"
+
+ expect(reference_filter(act).to_html).to eq exp
+ end
+ end
+
+ context 'String-based multi-word references in quotes' do
+ let(:milestone) { create(:milestone, name: 'gfm references', project: project) }
+ let(:reference) { milestone.to_reference(format: :name) }
+
+ it 'links to a valid reference' do
+ doc = reference_filter("See #{reference}")
+
+ expect(doc.css('a').first.attr('href')).to eq urls.
+ namespace_project_milestone_url(project.namespace, project, milestone)
+ expect(doc.text).to eq 'See gfm references'
+ end
+
+ it 'links with adjacent text' do
+ doc = reference_filter("Milestone (#{reference}.)")
+ expect(doc.to_html).to match(%r(\(<a.+>#{milestone.name}</a>\.\)))
+ end
+
+ it 'ignores invalid milestone names' do
+ exp = act = %(Milestone #{Milestone.reference_prefix}"#{milestone.name.reverse}")
+
+ expect(reference_filter(act).to_html).to eq exp
+ end
+ end
+
+ describe 'referencing a milestone in a link href' do
+ let(:reference) { %Q{<a href="#{milestone.to_reference}">Milestone</a>} }
+
+ it 'links to a valid reference' do
+ doc = reference_filter("See #{reference}")
+
+ expect(doc.css('a').first.attr('href')).to eq urls.
+ namespace_project_milestone_url(project.namespace, project, milestone)
+ end
+
+ it 'links with adjacent text' do
+ doc = reference_filter("Milestone (#{reference}.)")
+ expect(doc.to_html).to match(%r(\(<a.+>Milestone</a>\.\)))
end
it 'includes a data-project attribute' do
- doc = reference_filter("milestone #{reference}")
+ doc = reference_filter("Milestone #{reference}")
link = doc.css('a').first
expect(link).to have_attribute('data-project')
@@ -68,8 +153,34 @@ describe Banzai::Filter::MilestoneReferenceFilter, lib: true do
end
it 'adds to the results hash' do
- result = reference_pipeline_result("milestone #{reference}")
+ result = reference_pipeline_result("Milestone #{reference}")
expect(result[:references][:milestone]).to eq [milestone]
end
end
+
+ describe 'cross project milestone references' do
+ let(:another_project) { create(:empty_project, :public) }
+ let(:project_path) { another_project.path_with_namespace }
+ let(:milestone) { create(:milestone, project: another_project) }
+ let(:reference) { milestone.to_reference(project) }
+
+ let!(:result) { reference_filter("See #{reference}") }
+
+ it 'points to referenced project milestone page' do
+ expect(result.css('a').first.attr('href')).to eq urls.
+ namespace_project_milestone_url(another_project.namespace,
+ another_project,
+ milestone)
+ end
+
+ it 'contains cross project content' do
+ expect(result.css('a').first.text).to eq "#{milestone.name} in #{project_path}"
+ end
+
+ it 'escapes the name attribute' do
+ allow_any_instance_of(Milestone).to receive(:title).and_return(%{"></a>whatever<a title="})
+ doc = reference_filter("See #{reference}")
+ expect(doc.css('a').first.text).to eq "#{milestone.name} in #{project_path}"
+ end
+ end
end
diff --git a/spec/lib/container_registry/blob_spec.rb b/spec/lib/container_registry/blob_spec.rb
new file mode 100644
index 00000000000..4d8cb787dde
--- /dev/null
+++ b/spec/lib/container_registry/blob_spec.rb
@@ -0,0 +1,61 @@
+require 'spec_helper'
+
+describe ContainerRegistry::Blob do
+ let(:digest) { 'sha256:0123456789012345' }
+ let(:config) do
+ {
+ 'digest' => digest,
+ 'mediaType' => 'binary',
+ 'size' => 1000
+ }
+ end
+
+ let(:registry) { ContainerRegistry::Registry.new('http://example.com') }
+ let(:repository) { registry.repository('group/test') }
+ let(:blob) { repository.blob(config) }
+
+ it { expect(blob).to respond_to(:repository) }
+ it { expect(blob).to delegate_method(:registry).to(:repository) }
+ it { expect(blob).to delegate_method(:client).to(:repository) }
+
+ context '#path' do
+ subject { blob.path }
+
+ it { is_expected.to eq('example.com/group/test@sha256:0123456789012345') }
+ end
+
+ context '#digest' do
+ subject { blob.digest }
+
+ it { is_expected.to eq(digest) }
+ end
+
+ context '#type' do
+ subject { blob.type }
+
+ it { is_expected.to eq('binary') }
+ end
+
+ context '#revision' do
+ subject { blob.revision }
+
+ it { is_expected.to eq('0123456789012345') }
+ end
+
+ context '#short_revision' do
+ subject { blob.short_revision }
+
+ it { is_expected.to eq('012345678') }
+ end
+
+ context '#delete' do
+ before do
+ stub_request(:delete, 'http://example.com/v2/group/test/blobs/sha256:0123456789012345').
+ to_return(status: 200)
+ end
+
+ subject { blob.delete }
+
+ it { is_expected.to be_truthy }
+ end
+end
diff --git a/spec/lib/container_registry/registry_spec.rb b/spec/lib/container_registry/registry_spec.rb
new file mode 100644
index 00000000000..2638401ae6e
--- /dev/null
+++ b/spec/lib/container_registry/registry_spec.rb
@@ -0,0 +1,28 @@
+require 'spec_helper'
+
+describe ContainerRegistry::Registry do
+ let(:path) { nil }
+ let(:registry) { described_class.new('http://example.com', path: path) }
+
+ subject { registry }
+
+ it { is_expected.to respond_to(:client) }
+ it { is_expected.to respond_to(:uri) }
+ it { is_expected.to respond_to(:path) }
+
+ it { expect(subject.repository('test')).to_not be_nil }
+
+ context '#path' do
+ subject { registry.path }
+
+ context 'path from URL' do
+ it { is_expected.to eq('example.com') }
+ end
+
+ context 'custom path' do
+ let(:path) { 'registry.example.com' }
+
+ it { is_expected.to eq(path) }
+ end
+ end
+end
diff --git a/spec/lib/container_registry/repository_spec.rb b/spec/lib/container_registry/repository_spec.rb
new file mode 100644
index 00000000000..e6d66b11e4e
--- /dev/null
+++ b/spec/lib/container_registry/repository_spec.rb
@@ -0,0 +1,65 @@
+require 'spec_helper'
+
+describe ContainerRegistry::Repository do
+ let(:registry) { ContainerRegistry::Registry.new('http://example.com') }
+ let(:repository) { registry.repository('group/test') }
+
+ it { expect(repository).to respond_to(:registry) }
+ it { expect(repository).to delegate_method(:client).to(:registry) }
+ it { expect(repository.tag('test')).to_not be_nil }
+
+ context '#path' do
+ subject { repository.path }
+
+ it { is_expected.to eq('example.com/group/test') }
+ end
+
+ context 'manifest processing' do
+ before do
+ stub_request(:get, 'http://example.com/v2/group/test/tags/list').
+ with(headers: { 'Accept' => 'application/vnd.docker.distribution.manifest.v2+json' }).
+ to_return(
+ status: 200,
+ body: JSON.dump(tags: ['test']),
+ headers: { 'Content-Type' => 'application/vnd.docker.distribution.manifest.v2+json' })
+ end
+
+ context '#manifest' do
+ subject { repository.manifest }
+
+ it { is_expected.to_not be_nil }
+ end
+
+ context '#valid?' do
+ subject { repository.valid? }
+
+ it { is_expected.to be_truthy }
+ end
+
+ context '#tags' do
+ subject { repository.tags }
+
+ it { is_expected.to_not be_empty }
+ end
+ end
+
+ context '#delete_tags' do
+ let(:tag) { ContainerRegistry::Tag.new(repository, 'tag') }
+
+ before { expect(repository).to receive(:tags).twice.and_return([tag]) }
+
+ subject { repository.delete_tags }
+
+ context 'succeeds' do
+ before { expect(tag).to receive(:delete).and_return(true) }
+
+ it { is_expected.to be_truthy }
+ end
+
+ context 'any fails' do
+ before { expect(tag).to receive(:delete).and_return(false) }
+
+ it { is_expected.to be_falsey }
+ end
+ end
+end
diff --git a/spec/lib/container_registry/tag_spec.rb b/spec/lib/container_registry/tag_spec.rb
new file mode 100644
index 00000000000..12cf91127ed
--- /dev/null
+++ b/spec/lib/container_registry/tag_spec.rb
@@ -0,0 +1,89 @@
+require 'spec_helper'
+
+describe ContainerRegistry::Tag do
+ let(:registry) { ContainerRegistry::Registry.new('http://example.com') }
+ let(:repository) { registry.repository('group/test') }
+ let(:tag) { repository.tag('tag') }
+ let(:headers) { { 'Accept' => 'application/vnd.docker.distribution.manifest.v2+json' } }
+
+ it { expect(tag).to respond_to(:repository) }
+ it { expect(tag).to delegate_method(:registry).to(:repository) }
+ it { expect(tag).to delegate_method(:client).to(:repository) }
+
+ context '#path' do
+ subject { tag.path }
+
+ it { is_expected.to eq('example.com/group/test:tag') }
+ end
+
+ context 'manifest processing' do
+ before do
+ stub_request(:get, 'http://example.com/v2/group/test/manifests/tag').
+ with(headers: headers).
+ to_return(
+ status: 200,
+ body: File.read(Rails.root + 'spec/fixtures/container_registry/tag_manifest.json'),
+ headers: { 'Content-Type' => 'application/vnd.docker.distribution.manifest.v2+json' })
+ end
+
+ context '#layers' do
+ subject { tag.layers }
+
+ it { expect(subject.length).to eq(1) }
+ end
+
+ context '#total_size' do
+ subject { tag.total_size }
+
+ it { is_expected.to eq(2319870) }
+ end
+
+ context 'config processing' do
+ before do
+ stub_request(:get, 'http://example.com/v2/group/test/blobs/sha256:d7a513a663c1a6dcdba9ed832ca53c02ac2af0c333322cd6ca92936d1d9917ac').
+ with(headers: { 'Accept' => 'application/octet-stream' }).
+ to_return(
+ status: 200,
+ body: File.read(Rails.root + 'spec/fixtures/container_registry/config_blob.json'))
+ end
+
+ context '#config' do
+ subject { tag.config }
+
+ it { is_expected.to_not be_nil }
+ end
+
+ context '#created_at' do
+ subject { tag.created_at }
+
+ it { is_expected.to_not be_nil }
+ end
+ end
+ end
+
+ context 'manifest digest' do
+ before do
+ stub_request(:head, 'http://example.com/v2/group/test/manifests/tag').
+ with(headers: headers).
+ to_return(status: 200, headers: { 'Docker-Content-Digest' => 'sha256:digest' })
+ end
+
+ context '#digest' do
+ subject { tag.digest }
+
+ it { is_expected.to eq('sha256:digest') }
+ end
+
+ context '#delete' do
+ before do
+ stub_request(:delete, 'http://example.com/v2/group/test/manifests/sha256:digest').
+ with(headers: headers).
+ to_return(status: 200)
+ end
+
+ subject { tag.delete }
+
+ it { is_expected.to be_truthy }
+ end
+ end
+end
diff --git a/spec/lib/gitlab/database/migration_helpers_spec.rb b/spec/lib/gitlab/database/migration_helpers_spec.rb
new file mode 100644
index 00000000000..35ade7a2be0
--- /dev/null
+++ b/spec/lib/gitlab/database/migration_helpers_spec.rb
@@ -0,0 +1,128 @@
+require 'spec_helper'
+
+describe Gitlab::Database::MigrationHelpers, lib: true do
+ let(:model) do
+ ActiveRecord::Migration.new.extend(
+ Gitlab::Database::MigrationHelpers
+ )
+ end
+
+ before { allow(model).to receive(:puts) }
+
+ describe '#add_concurrent_index' do
+ context 'outside a transaction' do
+ before do
+ expect(model).to receive(:transaction_open?).and_return(false)
+ end
+
+ context 'using PostgreSQL' do
+ it 'creates the index concurrently' do
+ expect(Gitlab::Database).to receive(:postgresql?).and_return(true)
+
+ expect(model).to receive(:add_index).
+ with(:users, :foo, algorithm: :concurrently)
+
+ model.add_concurrent_index(:users, :foo)
+ end
+ end
+
+ context 'using MySQL' do
+ it 'creates a regular index' do
+ expect(Gitlab::Database).to receive(:postgresql?).and_return(false)
+
+ expect(model).to receive(:add_index).
+ with(:users, :foo)
+
+ model.add_concurrent_index(:users, :foo)
+ end
+ end
+ end
+
+ context 'inside a transaction' do
+ it 'raises RuntimeError' do
+ expect(model).to receive(:transaction_open?).and_return(true)
+
+ expect { model.add_concurrent_index(:users, :foo) }.
+ to raise_error(RuntimeError)
+ end
+ end
+ end
+
+ describe '#update_column_in_batches' do
+ before do
+ create_list(:empty_project, 5)
+ end
+
+ it 'updates all the rows in a table' do
+ model.update_column_in_batches(:projects, :import_error, 'foo')
+
+ expect(Project.where(import_error: 'foo').count).to eq(5)
+ end
+
+ it 'updates boolean values correctly' do
+ model.update_column_in_batches(:projects, :archived, true)
+
+ expect(Project.where(archived: true).count).to eq(5)
+ end
+ end
+
+ describe '#add_column_with_default' do
+ context 'outside of a transaction' do
+ before do
+ expect(model).to receive(:transaction_open?).and_return(false)
+
+ expect(model).to receive(:transaction).twice.and_yield
+
+ expect(model).to receive(:add_column).
+ with(:projects, :foo, :integer, default: nil)
+
+ 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)
+
+ expect(model).not_to receive(:change_column_null)
+
+ 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)
+
+ expect(model).to receive(:change_column_null).
+ with(:projects, :foo, false)
+
+ 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)
+
+ 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
+
+ context 'inside a transaction' do
+ it 'raises RuntimeError' do
+ expect(model).to receive(:transaction_open?).and_return(true)
+
+ expect do
+ model.add_column_with_default(:projects, :foo, :integer, default: 10)
+ end.to raise_error(RuntimeError)
+ end
+ end
+ end
+end
diff --git a/spec/lib/gitlab/email/message/repository_push_spec.rb b/spec/lib/gitlab/email/message/repository_push_spec.rb
index 7d6cce6daec..c19f33e2224 100644
--- a/spec/lib/gitlab/email/message/repository_push_spec.rb
+++ b/spec/lib/gitlab/email/message/repository_push_spec.rb
@@ -57,7 +57,7 @@ describe Gitlab::Email::Message::RepositoryPush do
describe '#diffs' do
subject { message.diffs }
- it { is_expected.to all(be_an_instance_of Gitlab::Git::Diff) }
+ it { is_expected.to all(be_an_instance_of Gitlab::Diff::File) }
end
describe '#diffs_count' do
diff --git a/spec/lib/gitlab/gitignore_spec.rb b/spec/lib/gitlab/gitignore_spec.rb
new file mode 100644
index 00000000000..72baa516cc4
--- /dev/null
+++ b/spec/lib/gitlab/gitignore_spec.rb
@@ -0,0 +1,40 @@
+require 'spec_helper'
+
+describe Gitlab::Gitignore do
+ subject { Gitlab::Gitignore }
+
+ describe '.all' do
+ it 'strips the gitignore suffix' do
+ expect(subject.all.first.name).not_to end_with('.gitignore')
+ end
+
+ it 'combines the globals and rest' do
+ all = subject.all.map(&:name)
+
+ expect(all).to include('Vim')
+ expect(all).to include('Ruby')
+ end
+ end
+
+ describe '.find' do
+ it 'returns nil if the file does not exist' do
+ expect(subject.find('mepmep-yadida')).to be nil
+ end
+
+ it 'returns the Gitignore object of a valid file' do
+ ruby = subject.find('Ruby')
+
+ expect(ruby).to be_a Gitlab::Gitignore
+ expect(ruby.name).to eq('Ruby')
+ end
+ end
+
+ describe '#content' do
+ it 'loads the full file' do
+ gitignore = subject.new(Rails.root.join('vendor/gitignore/Ruby.gitignore'))
+
+ expect(gitignore.name).to eq 'Ruby'
+ expect(gitignore.content).to start_with('*.gem')
+ end
+ end
+end
diff --git a/spec/lib/gitlab/import_url_spec.rb b/spec/lib/gitlab/import_url_spec.rb
deleted file mode 100644
index 7948386b0e6..00000000000
--- a/spec/lib/gitlab/import_url_spec.rb
+++ /dev/null
@@ -1,22 +0,0 @@
-require 'spec_helper'
-
-describe Gitlab::ImportUrl do
-
- let(:credentials) { { user: 'blah', password: 'password' } }
- let(:url) { "https://github.com/me/project.git" }
- let(:import_url) do
- described_class.new(url, credentials: credentials)
- end
-
- describe 'full_url' do
- it { expect(import_url.full_url).to eq("https://blah:password@github.com/me/project.git") }
- end
-
- describe 'sanitized_url' do
- it { expect(import_url.sanitized_url).to eq("https://github.com/me/project.git") }
- end
-
- describe 'credentials' do
- it { expect(import_url.credentials).to eq(credentials) }
- end
-end
diff --git a/spec/lib/gitlab/url_sanitizer_spec.rb b/spec/lib/gitlab/url_sanitizer_spec.rb
new file mode 100644
index 00000000000..de55334118f
--- /dev/null
+++ b/spec/lib/gitlab/url_sanitizer_spec.rb
@@ -0,0 +1,68 @@
+require 'spec_helper'
+
+describe Gitlab::UrlSanitizer, lib: true do
+ let(:credentials) { { user: 'blah', password: 'password' } }
+ let(:url_sanitizer) do
+ described_class.new("https://github.com/me/project.git", credentials: credentials)
+ end
+
+ describe '.sanitize' do
+ def sanitize_url(url)
+ # We want to try with multi-line content because is how error messages are formatted
+ described_class.sanitize(%Q{
+ remote: Not Found
+ fatal: repository '#{url}' not found
+ })
+ end
+
+ it 'mask the credentials from HTTP URLs' do
+ filtered_content = sanitize_url('http://user:pass@test.com/root/repoC.git/')
+
+ expect(filtered_content).to include("http://*****:*****@test.com/root/repoC.git/")
+ end
+
+ it 'mask the credentials from HTTPS URLs' do
+ filtered_content = sanitize_url('https://user:pass@test.com/root/repoA.git/')
+
+ expect(filtered_content).to include("https://*****:*****@test.com/root/repoA.git/")
+ end
+
+ it 'mask credentials from SSH URLs' do
+ filtered_content = sanitize_url('ssh://user@host.test/path/to/repo.git')
+
+ expect(filtered_content).to include("ssh://*****@host.test/path/to/repo.git")
+ end
+
+ it 'does not modify Git URLs' do
+ # git protocol does not support authentication
+ filtered_content = sanitize_url('git://host.test/path/to/repo.git')
+
+ expect(filtered_content).to include("git://host.test/path/to/repo.git")
+ end
+
+ it 'does not modify scp-like URLs' do
+ filtered_content = sanitize_url('user@server:project.git')
+
+ expect(filtered_content).to include("user@server:project.git")
+ end
+ end
+
+ describe '#sanitized_url' do
+ it { expect(url_sanitizer.sanitized_url).to eq("https://github.com/me/project.git") }
+ end
+
+ describe '#credentials' do
+ it { expect(url_sanitizer.credentials).to eq(credentials) }
+ end
+
+ describe '#full_url' do
+ it { expect(url_sanitizer.full_url).to eq("https://blah:password@github.com/me/project.git") }
+
+ it 'supports scp-like URLs' do
+ sanitizer = described_class.new('user@server:project.git')
+
+ expect(sanitizer.full_url).to eq('user@server:project.git')
+ end
+ end
+
+end
diff --git a/spec/mailers/notify_spec.rb b/spec/mailers/notify_spec.rb
index 5f7e4a526e6..b963a3e0324 100644
--- a/spec/mailers/notify_spec.rb
+++ b/spec/mailers/notify_spec.rb
@@ -693,8 +693,9 @@ describe Notify do
let(:commits) { Commit.decorate(compare.commits, nil) }
let(:diff_path) { namespace_project_compare_path(project.namespace, project, from: Commit.new(compare.base, project), to: Commit.new(compare.head, project)) }
let(:send_from_committer_email) { false }
+ let(:diff_refs) { [project.merge_base_commit(sample_image_commit.id, sample_commit.id), project.commit(sample_commit.id)] }
- subject { Notify.repository_push_email(project.id, author_id: user.id, ref: 'refs/heads/master', action: :push, compare: compare, reverse_compare: false, send_from_committer_email: send_from_committer_email) }
+ subject { Notify.repository_push_email(project.id, author_id: user.id, ref: 'refs/heads/master', action: :push, compare: compare, reverse_compare: false, diff_refs: diff_refs, send_from_committer_email: send_from_committer_email) }
it_behaves_like 'it should not have Gmail Actions links'
it_behaves_like "a user cannot unsubscribe through footer link"
@@ -715,15 +716,15 @@ describe Notify do
is_expected.to have_body_text /Change some files/
end
- it 'includes diffs' do
- is_expected.to have_body_text /def archive_formats_regex/
+ it 'includes diffs with character-level highlighting' do
+ is_expected.to have_body_text /def<\/span> <span class=\"nf\">archive_formats_regex/
end
it 'contains a link to the diff' do
is_expected.to have_body_text /#{diff_path}/
end
- it 'doesn not contain the misleading footer' do
+ it 'does not contain the misleading footer' do
is_expected.not_to have_body_text /you are a member of/
end
@@ -797,8 +798,9 @@ describe Notify do
let(:compare) { Gitlab::Git::Compare.new(project.repository.raw_repository, sample_commit.parent_id, sample_commit.id) }
let(:commits) { Commit.decorate(compare.commits, nil) }
let(:diff_path) { namespace_project_commit_path(project.namespace, project, commits.first) }
+ let(:diff_refs) { [project.merge_base_commit(sample_commit.parent_id, sample_commit.id), project.commit(sample_commit.id)] }
- subject { Notify.repository_push_email(project.id, author_id: user.id, ref: 'refs/heads/master', action: :push, compare: compare) }
+ subject { Notify.repository_push_email(project.id, author_id: user.id, ref: 'refs/heads/master', action: :push, compare: compare, diff_refs: diff_refs) }
it_behaves_like 'it should show Gmail Actions View Commit link'
it_behaves_like "a user cannot unsubscribe through footer link"
@@ -819,8 +821,8 @@ describe Notify do
is_expected.to have_body_text /Change some files/
end
- it 'includes diffs' do
- is_expected.to have_body_text /def archive_formats_regex/
+ it 'includes diffs with character-level highlighting' do
+ is_expected.to have_body_text /def<\/span> <span class=\"nf\">archive_formats_regex/
end
it 'contains a link to the diff' do
diff --git a/spec/models/build_spec.rb b/spec/models/build_spec.rb
index b5d356aa066..abae3271a5c 100644
--- a/spec/models/build_spec.rb
+++ b/spec/models/build_spec.rb
@@ -259,11 +259,11 @@ describe Ci::Build, models: true do
end
describe '#can_be_served?' do
- let(:runner) { FactoryGirl.create :ci_runner }
+ let(:runner) { create(:ci_runner) }
before { build.project.runners << runner }
- context 'runner without tags' do
+ context 'when runner does not have tags' do
it 'can handle builds without tags' do
expect(build.can_be_served?(runner)).to be_truthy
end
@@ -274,25 +274,53 @@ describe Ci::Build, models: true do
end
end
- context 'runner with tags' do
+ context 'when runner has tags' do
before { runner.tag_list = ['bb', 'cc'] }
- it 'can handle builds without tags' do
- expect(build.can_be_served?(runner)).to be_truthy
+ shared_examples 'tagged build picker' do
+ it 'can handle build with matching tags' do
+ build.tag_list = ['bb']
+ expect(build.can_be_served?(runner)).to be_truthy
+ end
+
+ it 'cannot handle build without matching tags' do
+ build.tag_list = ['aa']
+ expect(build.can_be_served?(runner)).to be_falsey
+ end
end
- it 'can handle build with matching tags' do
- build.tag_list = ['bb']
- expect(build.can_be_served?(runner)).to be_truthy
+ context 'when runner can pick untagged jobs' do
+ it 'can handle builds without tags' do
+ expect(build.can_be_served?(runner)).to be_truthy
+ end
+
+ it_behaves_like 'tagged build picker'
end
- it 'cannot handle build with not matching tags' do
- build.tag_list = ['aa']
- expect(build.can_be_served?(runner)).to be_falsey
+ context 'when runner can not pick untagged jobs' do
+ before { runner.run_untagged = false }
+
+ it 'can not handle builds without tags' do
+ expect(build.can_be_served?(runner)).to be_falsey
+ end
+
+ it_behaves_like 'tagged build picker'
end
end
end
+ describe '#has_tags?' do
+ context 'when build has tags' do
+ subject { create(:ci_build, tag_list: ['tag']) }
+ it { is_expected.to have_tags }
+ end
+
+ context 'when build does not have tags' do
+ subject { create(:ci_build, tag_list: []) }
+ it { is_expected.to_not have_tags }
+ end
+ end
+
describe '#any_runners_online?' do
subject { build.any_runners_online? }
diff --git a/spec/models/ci/commit_spec.rb b/spec/models/ci/commit_spec.rb
index dc071ad1c90..1b5940ad5a8 100644
--- a/spec/models/ci/commit_spec.rb
+++ b/spec/models/ci/commit_spec.rb
@@ -10,7 +10,6 @@ describe Ci::Commit, models: true do
it { is_expected.to have_many(:builds) }
it { is_expected.to validate_presence_of :sha }
it { is_expected.to validate_presence_of :status }
- it { is_expected.to delegate_method(:stages).to(:statuses) }
it { is_expected.to respond_to :git_author_name }
it { is_expected.to respond_to :git_author_email }
diff --git a/spec/models/ci/runner_spec.rb b/spec/models/ci/runner_spec.rb
index eaa94228922..7c6e39419ed 100644
--- a/spec/models/ci/runner_spec.rb
+++ b/spec/models/ci/runner_spec.rb
@@ -1,6 +1,24 @@
require 'spec_helper'
describe Ci::Runner, models: true do
+ describe 'validation' do
+ context 'when runner is not allowed to pick untagged jobs' do
+ context 'when runner does not have tags' do
+ it 'is not valid' do
+ runner = build(:ci_runner, tag_list: [], run_untagged: false)
+ expect(runner).to be_invalid
+ end
+ end
+
+ context 'when runner has tags' do
+ it 'is valid' do
+ runner = build(:ci_runner, tag_list: ['tag'], run_untagged: false)
+ expect(runner).to be_valid
+ end
+ end
+ end
+ end
+
describe '#display_name' do
it 'should return the description if it has a value' do
runner = FactoryGirl.build(:ci_runner, description: 'Linux/Ruby-1.9.3-p448')
@@ -114,7 +132,19 @@ describe Ci::Runner, models: true do
end
end
- describe '#search' do
+ describe '#has_tags?' do
+ context 'when runner has tags' do
+ subject { create(:ci_runner, tag_list: ['tag']) }
+ it { is_expected.to have_tags }
+ end
+
+ context 'when runner does not have tags' do
+ subject { create(:ci_runner, tag_list: []) }
+ it { is_expected.to_not have_tags }
+ end
+ end
+
+ describe '.search' do
let(:runner) { create(:ci_runner, token: '123abc') }
it 'returns runners with a matching token' do
diff --git a/spec/models/merge_request_spec.rb b/spec/models/merge_request_spec.rb
index 9eef08c6d00..e269ff26a04 100644
--- a/spec/models/merge_request_spec.rb
+++ b/spec/models/merge_request_spec.rb
@@ -260,13 +260,18 @@ describe MergeRequest, models: true do
end
describe "#reset_merge_when_build_succeeds" do
- let(:merge_if_green) { create :merge_request, merge_when_build_succeeds: true, merge_user: create(:user) }
+ let(:merge_if_green) do
+ create :merge_request, merge_when_build_succeeds: true, merge_user: create(:user),
+ merge_params: { "should_remove_source_branch" => "1", "commit_message" => "msg" }
+ end
it "sets the item to false" do
merge_if_green.reset_merge_when_build_succeeds
merge_if_green.reload
expect(merge_if_green.merge_when_build_succeeds).to be_falsey
+ expect(merge_if_green.merge_params["should_remove_source_branch"]).to be_nil
+ expect(merge_if_green.merge_params["commit_message"]).to be_nil
end
end
diff --git a/spec/models/namespace_spec.rb b/spec/models/namespace_spec.rb
index 4074f966299..4e68ac5e63a 100644
--- a/spec/models/namespace_spec.rb
+++ b/spec/models/namespace_spec.rb
@@ -70,6 +70,20 @@ describe Namespace, models: true do
allow(@namespace).to receive(:path).and_return(new_path)
expect(@namespace.move_dir).to be_truthy
end
+
+ context "when any project has container tags" do
+ before do
+ stub_container_registry_config(enabled: true)
+ stub_container_registry_tags('tag')
+
+ create(:empty_project, namespace: @namespace)
+
+ allow(@namespace).to receive(:path_was).and_return(@namespace.path)
+ allow(@namespace).to receive(:path).and_return('new_path')
+ end
+
+ it { expect { @namespace.move_dir }.to raise_error('Namespace cannot be moved, because at least one project has tags in container registry') }
+ end
end
describe :rm_dir do
diff --git a/spec/models/project_services/slack_service/issue_message_spec.rb b/spec/models/project_services/slack_service/issue_message_spec.rb
index f648cbe2dee..0f8889bdf3c 100644
--- a/spec/models/project_services/slack_service/issue_message_spec.rb
+++ b/spec/models/project_services/slack_service/issue_message_spec.rb
@@ -25,7 +25,7 @@ describe SlackService::IssueMessage, models: true do
}
end
- let(:color) { '#345' }
+ let(:color) { '#C95823' }
context '#initialize' do
before do
@@ -40,10 +40,11 @@ describe SlackService::IssueMessage, models: true do
context 'open' do
it 'returns a message regarding opening of issues' do
expect(subject.pretext).to eq(
- 'Test User opened <url|issue #100> in <somewhere.com|project_name>: '\
- '*Issue title*')
+ '<somewhere.com|[project_name>] Issue opened by Test User')
expect(subject.attachments).to eq([
{
+ title: "#100 Issue title",
+ title_link: "url",
text: "issue description",
color: color,
}
@@ -56,10 +57,10 @@ describe SlackService::IssueMessage, models: true do
args[:object_attributes][:action] = 'close'
args[:object_attributes][:state] = 'closed'
end
+
it 'returns a message regarding closing of issues' do
expect(subject.pretext). to eq(
- 'Test User closed <url|issue #100> in <somewhere.com|project_name>: '\
- '*Issue title*')
+ '<somewhere.com|[project_name>] Issue <url|#100 Issue title> closed by Test User')
expect(subject.attachments).to be_empty
end
end
diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb
index f6e5b132643..60e1ec43f2b 100644
--- a/spec/models/project_spec.rb
+++ b/spec/models/project_spec.rb
@@ -634,11 +634,11 @@ describe Project, models: true do
# Project#gitlab_shell returns a new instance of Gitlab::Shell on every
# call. This makes testing a bit easier.
allow(project).to receive(:gitlab_shell).and_return(gitlab_shell)
- end
- it 'renames a repository' do
allow(project).to receive(:previous_changes).and_return('path' => ['foo'])
+ end
+ it 'renames a repository' do
ns = project.namespace_dir
expect(gitlab_shell).to receive(:mv_repository).
@@ -663,6 +663,17 @@ describe Project, models: true do
project.rename_repo
end
+
+ context 'container registry with tags' do
+ before do
+ stub_container_registry_config(enabled: true)
+ stub_container_registry_tags('tag')
+ end
+
+ subject { project.rename_repo }
+
+ it { expect{subject}.to raise_error(Exception) }
+ end
end
describe '#expire_caches_before_rename' do
@@ -772,4 +783,71 @@ describe Project, models: true do
expect(project.protected_branch?('foo')).to eq(false)
end
end
+
+ describe '#container_registry_repository' do
+ let(:project) { create(:empty_project) }
+
+ before { stub_container_registry_config(enabled: true) }
+
+ subject { project.container_registry_repository }
+
+ it { is_expected.to_not be_nil }
+ end
+
+ describe '#container_registry_repository_url' do
+ let(:project) { create(:empty_project) }
+
+ subject { project.container_registry_repository_url }
+
+ before { stub_container_registry_config(**registry_settings) }
+
+ context 'for enabled registry' do
+ let(:registry_settings) do
+ {
+ enabled: true,
+ host_port: 'example.com',
+ }
+ end
+
+ it { is_expected.to_not be_nil }
+ end
+
+ context 'for disabled registry' do
+ let(:registry_settings) do
+ {
+ enabled: false
+ }
+ end
+
+ it { is_expected.to be_nil }
+ end
+ end
+
+ describe '#has_container_registry_tags?' do
+ let(:project) { create(:empty_project) }
+
+ subject { project.has_container_registry_tags? }
+
+ context 'for enabled registry' do
+ before { stub_container_registry_config(enabled: true) }
+
+ context 'with tags' do
+ before { stub_container_registry_tags('test', 'test2') }
+
+ it { is_expected.to be_truthy }
+ end
+
+ context 'when no tags' do
+ before { stub_container_registry_tags }
+
+ it { is_expected.to be_falsey }
+ end
+ end
+
+ context 'for disabled registry' do
+ before { stub_container_registry_config(enabled: false) }
+
+ it { is_expected.to be_falsey }
+ end
+ end
end
diff --git a/spec/models/repository_spec.rb b/spec/models/repository_spec.rb
index 34a13f9b5c9..583151023b6 100644
--- a/spec/models/repository_spec.rb
+++ b/spec/models/repository_spec.rb
@@ -100,6 +100,12 @@ describe Repository, models: true do
expect(results.first).not_to start_with('fatal:')
end
+ it 'properly handles an unmatched parenthesis' do
+ results = repository.search_files("test(", 'master')
+
+ expect(results.first).not_to start_with('fatal:')
+ end
+
describe 'result' do
subject { results.first }
@@ -176,6 +182,15 @@ describe Repository, models: true do
repository.remove_file(user, 'LICENSE', 'Remove LICENSE', 'master')
end
+ it 'handles when HEAD points to non-existent ref' do
+ repository.commit_file(user, 'LICENSE', 'Copyright!', 'Add LICENSE', 'master', false)
+ rugged = double('rugged')
+ expect(rugged).to receive(:head_unborn?).and_return(true)
+ expect(repository).to receive(:rugged).and_return(rugged)
+
+ expect(repository.license_blob).to be_nil
+ end
+
it 'looks in the root_ref only' do
repository.remove_file(user, 'LICENSE', 'Remove LICENSE', 'markdown')
repository.commit_file(user, 'LICENSE', Licensee::License.new('mit').content, 'Add LICENSE', 'markdown', false)
@@ -204,6 +219,15 @@ describe Repository, models: true do
repository.remove_file(user, 'LICENSE', 'Remove LICENSE', 'master')
end
+ it 'handles when HEAD points to non-existent ref' do
+ repository.commit_file(user, 'LICENSE', 'Copyright!', 'Add LICENSE', 'master', false)
+ rugged = double('rugged')
+ expect(rugged).to receive(:head_unborn?).and_return(true)
+ expect(repository).to receive(:rugged).and_return(rugged)
+
+ expect(repository.license_key).to be_nil
+ end
+
it 'returns nil when no license is detected' do
expect(repository.license_key).to be_nil
end
diff --git a/spec/requests/api/gitignores_spec.rb b/spec/requests/api/gitignores_spec.rb
new file mode 100644
index 00000000000..aab2d8c81b9
--- /dev/null
+++ b/spec/requests/api/gitignores_spec.rb
@@ -0,0 +1,29 @@
+require 'spec_helper'
+
+describe API::Gitignores, api: true do
+ include ApiHelpers
+
+ describe 'Entity Gitignore' do
+ before { get api('/gitignores/Ruby') }
+
+ it { expect(json_response['name']).to eq('Ruby') }
+ it { expect(json_response['content']).to include('*.gem') }
+ end
+
+ describe 'Entity GitignoresList' do
+ before { get api('/gitignores') }
+
+ it { expect(json_response.first['name']).not_to be_nil }
+ it { expect(json_response.first['content']).to be_nil }
+ end
+
+ describe 'GET /gitignores' do
+ it 'returns a list of available license templates' do
+ get api('/gitignores')
+
+ expect(response.status).to eq(200)
+ expect(json_response).to be_an Array
+ expect(json_response.size).to be > 15
+ end
+ end
+end
diff --git a/spec/requests/api/licenses_spec.rb b/spec/requests/api/licenses_spec.rb
index c17dcb222a9..3726b2f5688 100644
--- a/spec/requests/api/licenses_spec.rb
+++ b/spec/requests/api/licenses_spec.rb
@@ -57,7 +57,7 @@ describe API::Licenses, api: true do
end
it 'replaces placeholder values' do
- expect(json_response['content']).to include('Copyright (c) 2016 Anton')
+ expect(json_response['content']).to include("Copyright (c) #{Time.now.year} Anton")
end
end
@@ -70,7 +70,7 @@ describe API::Licenses, api: true do
it 'replaces placeholder values' do
expect(json_response['content']).to include('My Awesome Project')
- expect(json_response['content']).to include('Copyright (C) 2016 Anton')
+ expect(json_response['content']).to include("Copyright (C) #{Time.now.year} Anton")
end
end
@@ -83,7 +83,7 @@ describe API::Licenses, api: true do
it 'replaces placeholder values' do
expect(json_response['content']).to include('My Awesome Project')
- expect(json_response['content']).to include('Copyright (C) 2016 Anton')
+ expect(json_response['content']).to include("Copyright (C) #{Time.now.year} Anton")
end
end
@@ -96,7 +96,7 @@ describe API::Licenses, api: true do
it 'replaces placeholder values' do
expect(json_response['content']).to include('My Awesome Project')
- expect(json_response['content']).to include('Copyright (C) 2016 Anton')
+ expect(json_response['content']).to include("Copyright (C) #{Time.now.year} Anton")
end
end
@@ -108,7 +108,7 @@ describe API::Licenses, api: true do
end
it 'replaces placeholder values' do
- expect(json_response['content']).to include('Copyright 2016 Anton')
+ expect(json_response['content']).to include("Copyright #{Time.now.year} Anton")
end
end
@@ -128,7 +128,7 @@ describe API::Licenses, api: true do
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) 2016 #{user.name}")
+ expect(json_response['content']).to include("Copyright (c) #{Time.now.year} #{user.name}")
end
end
end
diff --git a/spec/requests/api/notes_spec.rb b/spec/requests/api/notes_spec.rb
index 49091fc0f49..ed1ed5aeb95 100644
--- a/spec/requests/api/notes_spec.rb
+++ b/spec/requests/api/notes_spec.rb
@@ -3,7 +3,7 @@ require 'spec_helper'
describe API::API, api: true do
include ApiHelpers
let(:user) { create(:user) }
- let!(:project) { create(:project, namespace: user.namespace) }
+ let!(:project) { create(:project, :public, namespace: user.namespace) }
let!(:issue) { create(:issue, project: project, author: user) }
let!(:merge_request) { create(:merge_request, source_project: project, target_project: project, author: user) }
let!(:snippet) { create(:project_snippet, project: project, author: user) }
@@ -39,6 +39,7 @@ describe API::API, api: true do
context "when noteable is an Issue" do
it "should return an array of issue notes" do
get api("/projects/#{project.id}/issues/#{issue.id}/notes", user)
+
expect(response.status).to eq(200)
expect(json_response).to be_an Array
expect(json_response.first['body']).to eq(issue_note.note)
@@ -46,20 +47,33 @@ describe API::API, api: true do
it "should return a 404 error when issue id not found" do
get api("/projects/#{project.id}/issues/12345/notes", user)
+
expect(response.status).to eq(404)
end
- context "that references a private issue" do
+ context "and current user cannot view the notes" do
it "should return an empty array" do
get api("/projects/#{ext_proj.id}/issues/#{ext_issue.id}/notes", user)
+
expect(response.status).to eq(200)
expect(json_response).to be_an Array
expect(json_response).to be_empty
end
+ context "and issue is confidential" do
+ before { ext_issue.update_attributes(confidential: true) }
+
+ it "returns 404" do
+ get api("/projects/#{ext_proj.id}/issues/#{ext_issue.id}/notes", user)
+
+ expect(response.status).to eq(404)
+ end
+ end
+
context "and current user can view the note" do
it "should return an empty array" do
get api("/projects/#{ext_proj.id}/issues/#{ext_issue.id}/notes", private_user)
+
expect(response.status).to eq(200)
expect(json_response).to be_an Array
expect(json_response.first['body']).to eq(cross_reference_note.note)
@@ -71,6 +85,7 @@ describe API::API, api: true do
context "when noteable is a Snippet" do
it "should return an array of snippet notes" do
get api("/projects/#{project.id}/snippets/#{snippet.id}/notes", user)
+
expect(response.status).to eq(200)
expect(json_response).to be_an Array
expect(json_response.first['body']).to eq(snippet_note.note)
@@ -78,6 +93,13 @@ describe API::API, api: true do
it "should return a 404 error when snippet id not found" do
get api("/projects/#{project.id}/snippets/42/notes", user)
+
+ expect(response.status).to eq(404)
+ end
+
+ it "returns 404 when not authorized" do
+ get api("/projects/#{project.id}/snippets/#{snippet.id}/notes", private_user)
+
expect(response.status).to eq(404)
end
end
@@ -85,6 +107,7 @@ describe API::API, api: true do
context "when noteable is a Merge Request" do
it "should return an array of merge_requests notes" do
get api("/projects/#{project.id}/merge_requests/#{merge_request.id}/notes", user)
+
expect(response.status).to eq(200)
expect(json_response).to be_an Array
expect(json_response.first['body']).to eq(merge_request_note.note)
@@ -92,6 +115,13 @@ describe API::API, api: true do
it "should return a 404 error if merge request id not found" do
get api("/projects/#{project.id}/merge_requests/4444/notes", user)
+
+ expect(response.status).to eq(404)
+ end
+
+ it "returns 404 when not authorized" do
+ get api("/projects/#{project.id}/merge_requests/4444/notes", private_user)
+
expect(response.status).to eq(404)
end
end
@@ -101,24 +131,39 @@ describe API::API, api: true do
context "when noteable is an Issue" do
it "should return an issue note by id" do
get api("/projects/#{project.id}/issues/#{issue.id}/notes/#{issue_note.id}", user)
+
expect(response.status).to eq(200)
expect(json_response['body']).to eq(issue_note.note)
end
it "should return a 404 error if issue note not found" do
get api("/projects/#{project.id}/issues/#{issue.id}/notes/12345", user)
+
expect(response.status).to eq(404)
end
- context "that references a private issue" do
+ context "and current user cannot view the note" do
it "should return a 404 error" do
get api("/projects/#{ext_proj.id}/issues/#{ext_issue.id}/notes/#{cross_reference_note.id}", user)
+
expect(response.status).to eq(404)
end
+ context "when issue is confidential" do
+ before { issue.update_attributes(confidential: true) }
+
+ it "returns 404" do
+ get api("/projects/#{project.id}/issues/#{issue.id}/notes/#{issue_note.id}", private_user)
+
+ expect(response.status).to eq(404)
+ end
+ end
+
+
context "and current user can view the note" do
it "should return an issue note by id" do
get api("/projects/#{ext_proj.id}/issues/#{ext_issue.id}/notes/#{cross_reference_note.id}", private_user)
+
expect(response.status).to eq(200)
expect(json_response['body']).to eq(cross_reference_note.note)
end
@@ -129,12 +174,14 @@ describe API::API, api: true do
context "when noteable is a Snippet" do
it "should return a snippet note by id" do
get api("/projects/#{project.id}/snippets/#{snippet.id}/notes/#{snippet_note.id}", user)
+
expect(response.status).to eq(200)
expect(json_response['body']).to eq(snippet_note.note)
end
it "should return a 404 error if snippet note not found" do
get api("/projects/#{project.id}/snippets/#{snippet.id}/notes/12345", user)
+
expect(response.status).to eq(404)
end
end
@@ -144,6 +191,7 @@ describe API::API, api: true do
context "when noteable is an Issue" do
it "should create a new issue note" do
post api("/projects/#{project.id}/issues/#{issue.id}/notes", user), body: 'hi!'
+
expect(response.status).to eq(201)
expect(json_response['body']).to eq('hi!')
expect(json_response['author']['username']).to eq(user.username)
@@ -151,11 +199,13 @@ describe API::API, api: true do
it "should return a 400 bad request error if body not given" do
post api("/projects/#{project.id}/issues/#{issue.id}/notes", user)
+
expect(response.status).to eq(400)
end
it "should return a 401 unauthorized error if user not authenticated" do
post api("/projects/#{project.id}/issues/#{issue.id}/notes"), body: 'hi!'
+
expect(response.status).to eq(401)
end
@@ -164,6 +214,7 @@ describe API::API, api: true do
creation_time = 2.weeks.ago
post api("/projects/#{project.id}/issues/#{issue.id}/notes", user),
body: 'hi!', created_at: creation_time
+
expect(response.status).to eq(201)
expect(json_response['body']).to eq('hi!')
expect(json_response['author']['username']).to eq(user.username)
@@ -176,6 +227,7 @@ describe API::API, api: true do
context "when noteable is a Snippet" do
it "should create a new snippet note" do
post api("/projects/#{project.id}/snippets/#{snippet.id}/notes", user), body: 'hi!'
+
expect(response.status).to eq(201)
expect(json_response['body']).to eq('hi!')
expect(json_response['author']['username']).to eq(user.username)
@@ -183,11 +235,13 @@ describe API::API, api: true do
it "should return a 400 bad request error if body not given" do
post api("/projects/#{project.id}/snippets/#{snippet.id}/notes", user)
+
expect(response.status).to eq(400)
end
it "should return a 401 unauthorized error if user not authenticated" do
post api("/projects/#{project.id}/snippets/#{snippet.id}/notes"), body: 'hi!'
+
expect(response.status).to eq(401)
end
end
@@ -227,6 +281,7 @@ describe API::API, api: true do
it 'should return modified note' do
put api("/projects/#{project.id}/issues/#{issue.id}/"\
"notes/#{issue_note.id}", user), body: 'Hello!'
+
expect(response.status).to eq(200)
expect(json_response['body']).to eq('Hello!')
end
@@ -234,12 +289,14 @@ describe API::API, api: true do
it 'should return a 404 error when note id not found' do
put api("/projects/#{project.id}/issues/#{issue.id}/notes/12345", user),
body: 'Hello!'
+
expect(response.status).to eq(404)
end
it 'should return a 400 bad request error if body not given' do
put api("/projects/#{project.id}/issues/#{issue.id}/"\
"notes/#{issue_note.id}", user)
+
expect(response.status).to eq(400)
end
end
@@ -248,6 +305,7 @@ describe API::API, api: true do
it 'should return modified note' do
put api("/projects/#{project.id}/snippets/#{snippet.id}/"\
"notes/#{snippet_note.id}", user), body: 'Hello!'
+
expect(response.status).to eq(200)
expect(json_response['body']).to eq('Hello!')
end
@@ -255,6 +313,7 @@ describe API::API, api: true do
it 'should return a 404 error when note id not found' do
put api("/projects/#{project.id}/snippets/#{snippet.id}/"\
"notes/12345", user), body: "Hello!"
+
expect(response.status).to eq(404)
end
end
@@ -263,6 +322,7 @@ describe API::API, api: true do
it 'should return modified note' do
put api("/projects/#{project.id}/merge_requests/#{merge_request.id}/"\
"notes/#{merge_request_note.id}", user), body: 'Hello!'
+
expect(response.status).to eq(200)
expect(json_response['body']).to eq('Hello!')
end
@@ -270,6 +330,7 @@ describe API::API, api: true do
it 'should return a 404 error when note id not found' do
put api("/projects/#{project.id}/merge_requests/#{merge_request.id}/"\
"notes/12345", user), body: "Hello!"
+
expect(response.status).to eq(404)
end
end
diff --git a/spec/requests/api/runners_spec.rb b/spec/requests/api/runners_spec.rb
index 3af61d4b335..73ae8ef631c 100644
--- a/spec/requests/api/runners_spec.rb
+++ b/spec/requests/api/runners_spec.rb
@@ -184,21 +184,24 @@ describe API::Runners, api: true do
description = shared_runner.description
active = shared_runner.active
- put api("/runners/#{shared_runner.id}", admin), description: "#{description}_updated", active: !active,
- tag_list: ['ruby2.1', 'pgsql', 'mysql']
+ update_runner(shared_runner.id, admin, description: "#{description}_updated",
+ active: !active,
+ tag_list: ['ruby2.1', 'pgsql', 'mysql'],
+ run_untagged: 'false')
shared_runner.reload
expect(response.status).to eq(200)
expect(shared_runner.description).to eq("#{description}_updated")
expect(shared_runner.active).to eq(!active)
expect(shared_runner.tag_list).to include('ruby2.1', 'pgsql', 'mysql')
+ expect(shared_runner.run_untagged?).to be false
end
end
context 'when runner is not shared' do
it 'should update runner' do
description = specific_runner.description
- put api("/runners/#{specific_runner.id}", admin), description: 'test'
+ update_runner(specific_runner.id, admin, description: 'test')
specific_runner.reload
expect(response.status).to eq(200)
@@ -208,10 +211,14 @@ describe API::Runners, api: true do
end
it 'should return 404 if runner does not exists' do
- put api('/runners/9999', admin), description: 'test'
+ update_runner(9999, admin, description: 'test')
expect(response.status).to eq(404)
end
+
+ def update_runner(id, user, args)
+ put api("/runners/#{id}", user), args
+ end
end
context 'authorized user' do
diff --git a/spec/requests/ci/api/builds_spec.rb b/spec/requests/ci/api/builds_spec.rb
index cae4656010f..7ebf8e41f3b 100644
--- a/spec/requests/ci/api/builds_spec.rb
+++ b/spec/requests/ci/api/builds_spec.rb
@@ -128,6 +128,38 @@ describe Ci::API::API do
end
end
end
+
+ context 'when build has no tags' do
+ before do
+ commit = create(:ci_commit, project: project)
+ create(:ci_build, commit: commit, tags: [])
+ end
+
+ context 'when runner is allowed to pick untagged builds' do
+ before { runner.update_column(:run_untagged, true) }
+
+ it 'picks build' do
+ register_builds
+
+ expect(response).to have_http_status 201
+ end
+ end
+
+ context 'when runner is not allowed to pick untagged builds' do
+ before { runner.update_column(:run_untagged, false) }
+
+ it 'does not pick build' do
+ register_builds
+
+ expect(response).to have_http_status 404
+ end
+ end
+
+ def register_builds
+ post ci_api("/builds/register"), token: runner.token,
+ info: { platform: :darwin }
+ end
+ end
end
describe "PUT /builds/:id" do
diff --git a/spec/requests/ci/api/runners_spec.rb b/spec/requests/ci/api/runners_spec.rb
index db8189ffb79..43596f07cb5 100644
--- a/spec/requests/ci/api/runners_spec.rb
+++ b/spec/requests/ci/api/runners_spec.rb
@@ -12,44 +12,85 @@ describe Ci::API::API do
end
describe "POST /runners/register" do
- describe "should create a runner if token provided" do
+ context 'when runner token is provided' do
before { post ci_api("/runners/register"), token: registration_token }
- it { expect(response.status).to eq(201) }
+ it 'creates runner with default values' do
+ expect(response).to have_http_status 201
+ expect(Ci::Runner.first.run_untagged).to be true
+ end
end
- describe "should create a runner with description" do
- before { post ci_api("/runners/register"), token: registration_token, description: "server.hostname" }
+ context 'when runner description is provided' do
+ before do
+ post ci_api("/runners/register"), token: registration_token,
+ description: "server.hostname"
+ end
- it { expect(response.status).to eq(201) }
- it { expect(Ci::Runner.first.description).to eq("server.hostname") }
+ it 'creates runner' do
+ expect(response).to have_http_status 201
+ expect(Ci::Runner.first.description).to eq("server.hostname")
+ end
end
- describe "should create a runner with tags" do
- before { post ci_api("/runners/register"), token: registration_token, tag_list: "tag1, tag2" }
+ context 'when runner tags are provided' do
+ before do
+ post ci_api("/runners/register"), token: registration_token,
+ tag_list: "tag1, tag2"
+ end
- it { expect(response.status).to eq(201) }
- it { expect(Ci::Runner.first.tag_list.sort).to eq(["tag1", "tag2"]) }
+ it 'creates runner' do
+ expect(response).to have_http_status 201
+ expect(Ci::Runner.first.tag_list.sort).to eq(["tag1", "tag2"])
+ end
end
- describe "should create a runner if project token provided" do
+ context 'when option for running untagged jobs is provided' do
+ context 'when tags are provided' do
+ it 'creates runner' do
+ post ci_api("/runners/register"), token: registration_token,
+ run_untagged: false,
+ tag_list: ['tag']
+
+ expect(response).to have_http_status 201
+ expect(Ci::Runner.first.run_untagged).to be false
+ end
+ end
+
+ context 'when tags are not provided' do
+ it 'does not create runner' do
+ post ci_api("/runners/register"), token: registration_token,
+ run_untagged: false
+
+ expect(response).to have_http_status 404
+ end
+ end
+ end
+
+ context 'when project token is provided' do
let(:project) { FactoryGirl.create(:empty_project) }
before { post ci_api("/runners/register"), token: project.runners_token }
- it { expect(response.status).to eq(201) }
- it { expect(project.runners.size).to eq(1) }
+ it 'creates runner' do
+ expect(response).to have_http_status 201
+ expect(project.runners.size).to eq(1)
+ end
end
- it "should return 403 error if token is invalid" do
- post ci_api("/runners/register"), token: 'invalid'
+ context 'when token is invalid' do
+ it 'returns 403 error' do
+ post ci_api("/runners/register"), token: 'invalid'
- expect(response.status).to eq(403)
+ expect(response).to have_http_status 403
+ end
end
- it "should return 400 error if no token" do
- post ci_api("/runners/register")
+ context 'when no token provided' do
+ it 'returns 400 error' do
+ post ci_api("/runners/register")
- expect(response.status).to eq(400)
+ expect(response).to have_http_status 400
+ end
end
%w(name version revision platform architecture).each do |param|
@@ -60,7 +101,7 @@ describe Ci::API::API do
it do
post ci_api("/runners/register"), token: registration_token, info: { param => value }
- expect(response.status).to eq(201)
+ expect(response).to have_http_status 201
is_expected.to eq(value)
end
end
@@ -71,7 +112,7 @@ describe Ci::API::API do
let!(:runner) { FactoryGirl.create(:ci_runner) }
before { delete ci_api("/runners/delete"), token: runner.token }
- it { expect(response.status).to eq(200) }
+ it { expect(response).to have_http_status 200 }
it { expect(Ci::Runner.count).to eq(0) }
end
end
diff --git a/spec/requests/jwt_controller_spec.rb b/spec/requests/jwt_controller_spec.rb
index 7bb71365a48..d006ff195cf 100644
--- a/spec/requests/jwt_controller_spec.rb
+++ b/spec/requests/jwt_controller_spec.rb
@@ -23,7 +23,7 @@ describe JwtController do
context 'when using authorized request' do
context 'using CI token' do
let(:project) { create(:empty_project, runners_token: 'token', builds_enabled: builds_enabled) }
- let(:headers) { { authorization: credentials('gitlab_ci_token', project.runners_token) } }
+ let(:headers) { { authorization: credentials('gitlab-ci-token', project.runners_token) } }
subject! { get '/jwt/auth', parameters, headers }
diff --git a/spec/services/auth/container_registry_authentication_service_spec.rb b/spec/services/auth/container_registry_authentication_service_spec.rb
index 3ea252ed44f..3f4a1ced2b6 100644
--- a/spec/services/auth/container_registry_authentication_service_spec.rb
+++ b/spec/services/auth/container_registry_authentication_service_spec.rb
@@ -5,19 +5,12 @@ describe Auth::ContainerRegistryAuthenticationService, services: true do
let(:current_user) { nil }
let(:current_params) { {} }
let(:rsa_key) { OpenSSL::PKey::RSA.generate(512) }
- let(:registry_settings) do
- {
- enabled: true,
- issuer: 'rspec',
- key: nil
- }
- end
let(:payload) { JWT.decode(subject[:token], rsa_key).first }
subject { described_class.new(current_project, current_user, current_params).execute }
before do
- allow(Gitlab.config.registry).to receive_messages(registry_settings)
+ allow(Gitlab.config.registry).to receive_messages(enabled: true, issuer: 'rspec', key: nil)
allow_any_instance_of(JSONWebToken::RSAToken).to receive(:key).and_return(rsa_key)
end
@@ -57,11 +50,27 @@ describe Auth::ContainerRegistryAuthenticationService, services: true do
end
end
+ shared_examples 'an unauthorized' do
+ it { is_expected.to include(http_status: 401) }
+ it { is_expected.to_not include(:token) }
+ end
+
shared_examples 'a forbidden' do
it { is_expected.to include(http_status: 403) }
it { is_expected.to_not include(:token) }
end
+ describe '#full_access_token' do
+ let(:project) { create(:empty_project) }
+ let(:token) { described_class.full_access_token(project.path_with_namespace) }
+
+ subject { { token: token } }
+
+ it_behaves_like 'a accessible' do
+ let(:actions) { ['*'] }
+ end
+ end
+
context 'user authorization' do
let(:project) { create(:project) }
let(:current_user) { create(:user) }
@@ -118,12 +127,12 @@ describe Auth::ContainerRegistryAuthenticationService, services: true do
context 'project authorization' do
let(:current_project) { create(:empty_project) }
- context 'disallow to use offline_token' do
+ context 'allow to use offline_token' do
let(:current_params) do
{ offline_token: true }
end
- it_behaves_like 'a forbidden'
+ it_behaves_like 'an authenticated'
end
context 'allow to pull and push images' do
@@ -164,6 +173,20 @@ describe Auth::ContainerRegistryAuthenticationService, services: true do
end
end
end
+
+ context 'for project without container registry' do
+ let(:project) { create(:empty_project, :public, container_registry_enabled: false) }
+
+ before { project.update(container_registry_enabled: false) }
+
+ context 'disallow when pulling' do
+ let(:current_params) do
+ { scope: "repository:#{project.path_with_namespace}:pull" }
+ end
+
+ it_behaves_like 'a forbidden'
+ end
+ end
end
context 'unauthorized' do
@@ -172,7 +195,7 @@ describe Auth::ContainerRegistryAuthenticationService, services: true do
{ offline_token: true }
end
- it_behaves_like 'a forbidden'
+ it_behaves_like 'an unauthorized'
end
context 'for invalid scope' do
diff --git a/spec/services/issues/update_service_spec.rb b/spec/services/issues/update_service_spec.rb
index 52f69306994..be19be17151 100644
--- a/spec/services/issues/update_service_spec.rb
+++ b/spec/services/issues/update_service_spec.rb
@@ -27,11 +27,6 @@ describe Issues::UpdateService, services: true do
end
end
- def update_issue(opts)
- @issue = Issues::UpdateService.new(project, user, opts).execute(issue)
- @issue.reload
- end
-
context "valid params" do
before do
opts = {
@@ -39,7 +34,8 @@ describe Issues::UpdateService, services: true do
description: 'Also please fix',
assignee_id: user2.id,
state_event: 'close',
- label_ids: [label.id]
+ label_ids: [label.id],
+ confidential: true
}
perform_enqueued_jobs do
@@ -79,13 +75,25 @@ describe Issues::UpdateService, services: true do
end
it 'creates system note about title change' do
- note = find_note('Title changed')
+ note = find_note('Changed title:')
+
+ expect(note).not_to be_nil
+ expect(note.note).to eq 'Changed title: **{-Old-} title** → **{+New+} title**'
+ end
+
+ it 'creates system note about confidentiality change' do
+ note = find_note('Made the issue confidential')
expect(note).not_to be_nil
- expect(note.note).to eq 'Title changed from **Old title** to **New title**'
+ expect(note.note).to eq 'Made the issue confidential'
end
end
+ def update_issue(opts)
+ @issue = Issues::UpdateService.new(project, user, opts).execute(issue)
+ @issue.reload
+ end
+
context 'todos' do
let!(:todo) { create(:todo, :assigned, user: user, project: project, target: issue, author: user2) }
diff --git a/spec/services/merge_requests/add_todo_when_build_fails_service_spec.rb b/spec/services/merge_requests/add_todo_when_build_fails_service_spec.rb
new file mode 100644
index 00000000000..f70716c9d19
--- /dev/null
+++ b/spec/services/merge_requests/add_todo_when_build_fails_service_spec.rb
@@ -0,0 +1,81 @@
+require 'spec_helper'
+
+# Write specs in this file.
+describe MergeRequests::AddTodoWhenBuildFailsService do
+ let(:user) { create(:user) }
+ let(:merge_request) { create(:merge_request) }
+ let(:project) { create(:project) }
+ let(:sha) { '1234567890abcdef1234567890abcdef12345678' }
+ let(:ci_commit) { create(:ci_commit_with_one_job, ref: merge_request.source_branch, project: project, sha: sha) }
+ let(:service) { MergeRequests::AddTodoWhenBuildFailsService.new(project, user, commit_message: 'Awesome message') }
+ let(:todo_service) { TodoService.new }
+
+ let(:merge_request) do
+ create(:merge_request, merge_user: user, source_branch: 'master',
+ target_branch: 'feature', source_project: project, target_project: project,
+ state: 'opened')
+ end
+
+ before do
+ allow_any_instance_of(MergeRequest).to receive(:ci_commit).and_return(ci_commit)
+ allow(service).to receive(:todo_service).and_return(todo_service)
+ end
+
+ describe '#execute' do
+ context 'commit status with ref' do
+ let(:commit_status) { create(:generic_commit_status, ref: merge_request.source_branch, commit: ci_commit) }
+
+ it 'notifies the todo service' do
+ expect(todo_service).to receive(:merge_request_build_failed).with(merge_request)
+ service.execute(commit_status)
+ end
+ end
+
+ context 'commit status with non-HEAD ref' do
+ let(:commit_status) { create(:generic_commit_status, ref: merge_request.source_branch) }
+
+ it 'does not notify the todo service' do
+ expect(todo_service).not_to receive(:merge_request_build_failed)
+ service.execute(commit_status)
+ end
+ end
+
+ context 'commit status without ref' do
+ let(:commit_status) { create(:generic_commit_status) }
+
+ it 'does not notify the todo service' do
+ expect(todo_service).not_to receive(:merge_request_build_failed)
+ service.execute(commit_status)
+ end
+ end
+ end
+
+ describe '#close' do
+ context 'commit status with ref' do
+ let(:commit_status) { create(:generic_commit_status, ref: merge_request.source_branch, commit: ci_commit) }
+
+ it 'notifies the todo service' do
+ expect(todo_service).to receive(:merge_request_build_retried).with(merge_request)
+ service.close(commit_status)
+ end
+ end
+
+ context 'commit status with non-HEAD ref' do
+ let(:commit_status) { create(:generic_commit_status, ref: merge_request.source_branch) }
+
+ it 'does not notify the todo service' do
+ expect(todo_service).not_to receive(:merge_request_build_retried)
+ service.close(commit_status)
+ end
+ end
+
+ context 'commit status without ref' do
+ let(:commit_status) { create(:generic_commit_status) }
+
+ it 'does not notify the todo service' do
+ expect(todo_service).not_to receive(:merge_request_build_retried)
+ service.close(commit_status)
+ end
+ end
+ end
+end
diff --git a/spec/services/merge_requests/create_service_spec.rb b/spec/services/merge_requests/create_service_spec.rb
index 120f4d6a669..e433f49872d 100644
--- a/spec/services/merge_requests/create_service_spec.rb
+++ b/spec/services/merge_requests/create_service_spec.rb
@@ -12,7 +12,8 @@ describe MergeRequests::CreateService, services: true do
title: 'Awesome merge_request',
description: 'please fix',
source_branch: 'feature',
- target_branch: 'master'
+ target_branch: 'master',
+ force_remove_source_branch: '1'
}
end
@@ -29,6 +30,7 @@ describe MergeRequests::CreateService, services: true do
it { expect(@merge_request).to be_valid }
it { expect(@merge_request.title).to eq('Awesome merge_request') }
it { expect(@merge_request.assignee).to be_nil }
+ it { expect(@merge_request.merge_params['force_remove_source_branch']).to eq('1') }
it 'should execute hooks with default action' do
expect(service).to have_received(:execute_hooks).with(@merge_request)
diff --git a/spec/services/merge_requests/merge_service_spec.rb b/spec/services/merge_requests/merge_service_spec.rb
index ceb3f97280e..1b0396eb686 100644
--- a/spec/services/merge_requests/merge_service_spec.rb
+++ b/spec/services/merge_requests/merge_service_spec.rb
@@ -38,6 +38,21 @@ describe MergeRequests::MergeService, services: true do
end
end
+ context 'remove source branch by author' do
+ let(:service) do
+ merge_request.merge_params['force_remove_source_branch'] = '1'
+ merge_request.save!
+ MergeRequests::MergeService.new(project, user, commit_message: 'Awesome message')
+ end
+
+ it 'removes the source branch' do
+ expect(DeleteBranchService).to receive(:new).
+ with(merge_request.source_project, merge_request.author).
+ and_call_original
+ service.execute(merge_request)
+ end
+ end
+
context "error handling" do
let(:service) { MergeRequests::MergeService.new(project, user, commit_message: 'Awesome message') }
diff --git a/spec/services/merge_requests/refresh_service_spec.rb b/spec/services/merge_requests/refresh_service_spec.rb
index fea8182bd30..31b93850c7c 100644
--- a/spec/services/merge_requests/refresh_service_spec.rb
+++ b/spec/services/merge_requests/refresh_service_spec.rb
@@ -27,6 +27,20 @@ describe MergeRequests::RefreshService, services: true do
target_branch: 'feature',
target_project: @project)
+ @build_failed_todo = create(:todo,
+ :build_failed,
+ user: @user,
+ project: @project,
+ target: @merge_request,
+ author: @user)
+
+ @fork_build_failed_todo = create(:todo,
+ :build_failed,
+ user: @user,
+ project: @project,
+ target: @merge_request,
+ author: @user)
+
@commits = @merge_request.commits
@oldrev = @commits.last.id
@@ -51,6 +65,8 @@ describe MergeRequests::RefreshService, services: true do
it { expect(@merge_request.merge_when_build_succeeds).to be_falsey}
it { expect(@fork_merge_request).to be_open }
it { expect(@fork_merge_request.notes).to be_empty }
+ it { expect(@build_failed_todo).to be_done }
+ it { expect(@fork_build_failed_todo).to be_done }
end
context 'push to origin repo target branch' do
@@ -63,6 +79,8 @@ describe MergeRequests::RefreshService, services: true do
it { expect(@merge_request).to be_merged }
it { expect(@fork_merge_request).to be_merged }
it { expect(@fork_merge_request.notes.last.note).to include('changed to merged') }
+ it { expect(@build_failed_todo).to be_pending }
+ it { expect(@fork_build_failed_todo).to be_pending }
end
context 'manual merge of source branch' do
@@ -82,6 +100,8 @@ describe MergeRequests::RefreshService, services: true do
it { expect(@merge_request.diffs.size).to be > 0 }
it { expect(@fork_merge_request).to be_merged }
it { expect(@fork_merge_request.notes.last.note).to include('changed to merged') }
+ it { expect(@build_failed_todo).to be_pending }
+ it { expect(@fork_build_failed_todo).to be_pending }
end
context 'push to fork repo source branch' do
@@ -101,6 +121,8 @@ describe MergeRequests::RefreshService, services: true do
it { expect(@merge_request).to be_open }
it { expect(@fork_merge_request.notes.last.note).to include('Added 4 commits') }
it { expect(@fork_merge_request).to be_open }
+ it { expect(@build_failed_todo).to be_pending }
+ it { expect(@fork_build_failed_todo).to be_pending }
end
context 'push to fork repo target branch' do
@@ -113,6 +135,8 @@ describe MergeRequests::RefreshService, services: true do
it { expect(@merge_request).to be_open }
it { expect(@fork_merge_request.notes).to be_empty }
it { expect(@fork_merge_request).to be_open }
+ it { expect(@build_failed_todo).to be_pending }
+ it { expect(@fork_build_failed_todo).to be_pending }
end
context 'push to origin repo target branch after fork project was removed' do
@@ -126,6 +150,8 @@ describe MergeRequests::RefreshService, services: true do
it { expect(@merge_request).to be_merged }
it { expect(@fork_merge_request).to be_open }
it { expect(@fork_merge_request.notes).to be_empty }
+ it { expect(@build_failed_todo).to be_pending }
+ it { expect(@fork_build_failed_todo).to be_pending }
end
context 'push new branch that exists in a merge request' do
@@ -153,6 +179,8 @@ describe MergeRequests::RefreshService, services: true do
def reload_mrs
@merge_request.reload
@fork_merge_request.reload
+ @build_failed_todo.reload
+ @fork_build_failed_todo.reload
end
end
end
diff --git a/spec/services/merge_requests/update_service_spec.rb b/spec/services/merge_requests/update_service_spec.rb
index 213e8c2eb3a..d4ebe28c276 100644
--- a/spec/services/merge_requests/update_service_spec.rb
+++ b/spec/services/merge_requests/update_service_spec.rb
@@ -39,7 +39,8 @@ describe MergeRequests::UpdateService, services: true do
assignee_id: user2.id,
state_event: 'close',
label_ids: [label.id],
- target_branch: 'target'
+ target_branch: 'target',
+ force_remove_source_branch: '1'
}
end
@@ -61,6 +62,7 @@ describe MergeRequests::UpdateService, services: true do
it { expect(@merge_request.labels.count).to eq(1) }
it { expect(@merge_request.labels.first.title).to eq(label.name) }
it { expect(@merge_request.target_branch).to eq('target') }
+ it { expect(@merge_request.merge_params['force_remove_source_branch']).to eq('1') }
it 'should execute hooks with update action' do
expect(service).to have_received(:execute_hooks).
@@ -90,10 +92,10 @@ describe MergeRequests::UpdateService, services: true do
end
it 'creates system note about title change' do
- note = find_note('Title changed')
+ note = find_note('Changed title:')
expect(note).not_to be_nil
- expect(note.note).to eq 'Title changed from **Old title** to **New title**'
+ expect(note.note).to eq 'Changed title: **{-Old-} title** → **{+New+} title**'
end
it 'creates system note about branch change' do
diff --git a/spec/services/notification_service_spec.rb b/spec/services/notification_service_spec.rb
index 4bbc4ddc3ab..cef5e0d8659 100644
--- a/spec/services/notification_service_spec.rb
+++ b/spec/services/notification_service_spec.rb
@@ -66,6 +66,7 @@ describe NotificationService, services: true do
should_email(@subscriber)
should_email(@watcher_and_subscriber)
should_email(@subscribed_participant)
+ should_not_email(@u_guest_watcher)
should_not_email(note.author)
should_not_email(@u_participating)
should_not_email(@u_disabled)
@@ -100,6 +101,7 @@ describe NotificationService, services: true do
should_email(note.noteable.author)
should_email(note.noteable.assignee)
should_email(@u_mentioned)
+ should_not_email(@u_guest_watcher)
should_not_email(@u_watcher)
should_not_email(note.author)
should_not_email(@u_participating)
@@ -160,6 +162,7 @@ describe NotificationService, services: true do
should_email(member)
end
+ should_email(@u_guest_watcher)
should_email(note.noteable.author)
should_email(note.noteable.assignee)
should_not_email(note.author)
@@ -201,6 +204,7 @@ describe NotificationService, services: true do
should_email(member)
end
+ should_email(@u_guest_watcher)
should_email(note.noteable.author)
should_not_email(note.author)
should_email(@u_mentioned)
@@ -224,6 +228,7 @@ describe NotificationService, services: true do
it do
notification.new_note(note)
+ should_email(@u_guest_watcher)
should_email(@u_committer)
should_email(@u_watcher)
should_not_email(@u_mentioned)
@@ -236,6 +241,7 @@ describe NotificationService, services: true do
note.update_attribute(:note, '@mention referenced')
notification.new_note(note)
+ should_email(@u_guest_watcher)
should_email(@u_committer)
should_email(@u_watcher)
should_email(@u_mentioned)
@@ -269,6 +275,7 @@ describe NotificationService, services: true do
should_email(issue.assignee)
should_email(@u_watcher)
+ should_email(@u_guest_watcher)
should_email(@u_participant_mentioned)
should_not_email(@u_mentioned)
should_not_email(@u_participating)
@@ -328,6 +335,7 @@ describe NotificationService, services: true do
should_email(issue.assignee)
should_email(@u_watcher)
+ should_email(@u_guest_watcher)
should_email(@u_participant_mentioned)
should_email(@subscriber)
should_not_email(@unsubscriber)
@@ -342,6 +350,7 @@ describe NotificationService, services: true do
should_email(@u_mentioned)
should_email(@u_watcher)
+ should_email(@u_guest_watcher)
should_email(@u_participant_mentioned)
should_email(@subscriber)
should_not_email(@unsubscriber)
@@ -356,6 +365,7 @@ describe NotificationService, services: true do
expect(issue.assignee).to be @u_mentioned
should_email(issue.assignee)
should_email(@u_watcher)
+ should_email(@u_guest_watcher)
should_email(@u_participant_mentioned)
should_email(@subscriber)
should_not_email(@unsubscriber)
@@ -370,6 +380,7 @@ describe NotificationService, services: true do
expect(issue.assignee).to be @u_mentioned
should_email(issue.assignee)
should_email(@u_watcher)
+ should_email(@u_guest_watcher)
should_email(@u_participant_mentioned)
should_email(@subscriber)
should_not_email(@unsubscriber)
@@ -383,6 +394,7 @@ describe NotificationService, services: true do
expect(issue.assignee).to be @u_mentioned
should_email(@u_watcher)
+ should_email(@u_guest_watcher)
should_email(@u_participant_mentioned)
should_email(@subscriber)
should_not_email(issue.assignee)
@@ -411,6 +423,7 @@ describe NotificationService, services: true do
should_not_email(issue.assignee)
should_not_email(issue.author)
should_not_email(@u_watcher)
+ should_not_email(@u_guest_watcher)
should_not_email(@u_participant_mentioned)
should_not_email(@subscriber)
should_not_email(@watcher_and_subscriber)
@@ -459,6 +472,7 @@ describe NotificationService, services: true do
should_email(issue.assignee)
should_email(issue.author)
should_email(@u_watcher)
+ should_email(@u_guest_watcher)
should_email(@u_participant_mentioned)
should_email(@subscriber)
should_email(@watcher_and_subscriber)
@@ -475,6 +489,7 @@ describe NotificationService, services: true do
should_email(issue.assignee)
should_email(issue.author)
should_email(@u_watcher)
+ should_email(@u_guest_watcher)
should_email(@u_participant_mentioned)
should_email(@subscriber)
should_email(@watcher_and_subscriber)
@@ -502,6 +517,7 @@ describe NotificationService, services: true do
should_email(@u_watcher)
should_email(@watcher_and_subscriber)
should_email(@u_participant_mentioned)
+ should_email(@u_guest_watcher)
should_not_email(@u_participating)
should_not_email(@u_disabled)
end
@@ -525,6 +541,7 @@ describe NotificationService, services: true do
should_email(@u_participant_mentioned)
should_email(@subscriber)
should_email(@watcher_and_subscriber)
+ should_email(@u_guest_watcher)
should_not_email(@unsubscriber)
should_not_email(@u_participating)
should_not_email(@u_disabled)
@@ -566,6 +583,7 @@ describe NotificationService, services: true do
should_email(merge_request.assignee)
should_email(@u_watcher)
+ should_email(@u_guest_watcher)
should_email(@u_participant_mentioned)
should_email(@subscriber)
should_email(@watcher_and_subscriber)
@@ -584,6 +602,7 @@ describe NotificationService, services: true do
should_email(@u_participant_mentioned)
should_email(@subscriber)
should_email(@watcher_and_subscriber)
+ should_email(@u_guest_watcher)
should_not_email(@unsubscriber)
should_not_email(@u_participating)
should_not_email(@u_disabled)
@@ -599,6 +618,7 @@ describe NotificationService, services: true do
should_email(@u_participant_mentioned)
should_email(@subscriber)
should_email(@watcher_and_subscriber)
+ should_email(@u_guest_watcher)
should_not_email(@unsubscriber)
should_not_email(@u_participating)
should_not_email(@u_disabled)
@@ -620,6 +640,7 @@ describe NotificationService, services: true do
should_email(@u_watcher)
should_email(@u_participating)
+ should_not_email(@u_guest_watcher)
should_not_email(@u_disabled)
end
end
@@ -635,6 +656,8 @@ describe NotificationService, services: true do
@u_not_mentioned = create(:user, username: 'regular', notification_level: :participating)
@u_outsider_mentioned = create(:user, username: 'outsider')
+ create_guest_watcher
+
project.team << [@u_watcher, :master]
project.team << [@u_participating, :master]
project.team << [@u_participant_mentioned, :master]
@@ -644,6 +667,13 @@ describe NotificationService, services: true do
project.team << [@u_not_mentioned, :master]
end
+ def create_guest_watcher
+ @u_guest_watcher = create(:user, username: 'guest_watching')
+ setting = @u_guest_watcher.notification_settings_for(project)
+ setting.level = :watch
+ setting.save
+ end
+
def add_users_with_subscription(project, issuable)
@subscriber = create :user
@unsubscriber = create :user
diff --git a/spec/services/projects/destroy_service_spec.rb b/spec/services/projects/destroy_service_spec.rb
index a5cb6f382e4..29341c5e57e 100644
--- a/spec/services/projects/destroy_service_spec.rb
+++ b/spec/services/projects/destroy_service_spec.rb
@@ -28,6 +28,29 @@ describe Projects::DestroyService, services: true do
it { expect(Dir.exist?(remove_path)).to be_truthy }
end
+ context 'container registry' do
+ before do
+ stub_container_registry_config(enabled: true)
+ stub_container_registry_tags('tag')
+ end
+
+ context 'tags deletion succeeds' do
+ it do
+ expect_any_instance_of(ContainerRegistry::Tag).to receive(:delete).and_return(true)
+
+ destroy_project(project, user, {})
+ end
+ end
+
+ context 'tags deletion fails' do
+ before { expect_any_instance_of(ContainerRegistry::Tag).to receive(:delete).and_return(false) }
+
+ subject { destroy_project(project, user, {}) }
+
+ it { expect{subject}.to raise_error(Projects::DestroyService::DestroyError) }
+ end
+ end
+
def destroy_project(project, user, params)
Projects::DestroyService.new(project, user, params).execute
end
diff --git a/spec/services/projects/transfer_service_spec.rb b/spec/services/projects/transfer_service_spec.rb
index 06017317339..d5aa115a074 100644
--- a/spec/services/projects/transfer_service_spec.rb
+++ b/spec/services/projects/transfer_service_spec.rb
@@ -26,6 +26,17 @@ describe Projects::TransferService, services: true do
it { expect(project.namespace).to eq(user.namespace) }
end
+ context 'disallow transfering of project with tags' do
+ before do
+ stub_container_registry_config(enabled: true)
+ stub_container_registry_tags('tag')
+ end
+
+ subject { transfer_project(project, user, group) }
+
+ it { is_expected.to be_falsey }
+ end
+
context 'namespace -> not allowed namespace' do
before do
@result = transfer_project(project, user, group)
diff --git a/spec/services/system_note_service_spec.rb b/spec/services/system_note_service_spec.rb
index 5fbf2ae5247..ee976eb2926 100644
--- a/spec/services/system_note_service_spec.rb
+++ b/spec/services/system_note_service_spec.rb
@@ -241,15 +241,19 @@ describe SystemNoteService, services: true do
it 'sets the note text' do
expect(subject.note).
- to eq "Title changed from **Old title** to **#{noteable.title}**"
+ to eq "Changed title: **{-Old title-}** → **{+#{noteable.title}+}**"
end
end
+ end
- context 'when noteable does not respond to `title' do
- let(:noteable) { double('noteable') }
+ describe '.change_issue_confidentiality' do
+ subject { described_class.change_issue_confidentiality(noteable, project, author) }
- it 'returns nil' do
- expect(subject).to be_nil
+ context 'when noteable responds to `confidential`' do
+ it_behaves_like 'a system note'
+
+ it 'sets the note text' do
+ expect(subject.note).to eq 'Made the issue visible'
end
end
end
diff --git a/spec/services/todo_service_spec.rb b/spec/services/todo_service_spec.rb
index a075496ee63..42147736532 100644
--- a/spec/services/todo_service_spec.rb
+++ b/spec/services/todo_service_spec.rb
@@ -305,6 +305,25 @@ describe TodoService, services: true do
expect(second_todo.reload).to be_done
end
end
+
+ describe '#merge_request_build_failed' do
+ it 'creates a pending todo for the merge request author' do
+ service.merge_request_build_failed(mr_unassigned)
+
+ should_create_todo(user: author, target: mr_unassigned, action: Todo::BUILD_FAILED)
+ end
+ end
+
+ describe '#merge_request_push' do
+ it 'marks related pending todos to the target for the user as done' do
+ first_todo = create(:todo, :build_failed, user: author, project: project, target: mr_assigned, author: john_doe)
+ second_todo = create(:todo, :build_failed, user: john_doe, project: project, target: mr_assigned, author: john_doe)
+ service.merge_request_push(mr_assigned, author)
+
+ expect(first_todo.reload).to be_done
+ expect(second_todo.reload).not_to be_done
+ end
+ end
end
def should_create_todo(attributes = {})
diff --git a/spec/support/markdown_feature.rb b/spec/support/markdown_feature.rb
index b87cd6bbca2..7fc6d6fcc5e 100644
--- a/spec/support/markdown_feature.rb
+++ b/spec/support/markdown_feature.rb
@@ -63,8 +63,12 @@ class MarkdownFeature
@label ||= create(:label, name: 'awaiting feedback', project: project)
end
+ def simple_milestone
+ @simple_milestone ||= create(:milestone, name: 'gfm-milestone', project: project)
+ end
+
def milestone
- @milestone ||= create(:milestone, project: project)
+ @milestone ||= create(:milestone, name: 'next goal', project: project)
end
# Cross-references -----------------------------------------------------------
diff --git a/spec/support/matchers/markdown_matchers.rb b/spec/support/matchers/markdown_matchers.rb
index 43cb6ef43f2..e005058ba5b 100644
--- a/spec/support/matchers/markdown_matchers.rb
+++ b/spec/support/matchers/markdown_matchers.rb
@@ -154,7 +154,7 @@ module MarkdownMatchers
set_default_markdown_messages
match do |actual|
- expect(actual).to have_selector('a.gfm.gfm-milestone', count: 3)
+ expect(actual).to have_selector('a.gfm.gfm-milestone', count: 6)
end
end
@@ -168,6 +168,16 @@ module MarkdownMatchers
expect(actual).to have_selector('input[checked]', count: 3)
end
end
+
+ # InlineDiffFilter
+ matcher :parse_inline_diffs do
+ set_default_markdown_messages
+
+ match do |actual|
+ expect(actual).to have_selector('span.idiff.addition', count: 2)
+ expect(actual).to have_selector('span.idiff.deletion', count: 2)
+ end
+ end
end
# Monkeypatch the matcher DSL so that we can reduce some noisy duplication for
diff --git a/spec/support/stub_gitlab_calls.rb b/spec/support/stub_gitlab_calls.rb
index b5ca34bc028..f73416a3d0f 100644
--- a/spec/support/stub_gitlab_calls.rb
+++ b/spec/support/stub_gitlab_calls.rb
@@ -25,6 +25,23 @@ module StubGitlabCalls
allow_any_instance_of(Project).to receive(:builds_enabled?).and_return(false)
end
+ def stub_container_registry_config(registry_settings)
+ allow(Gitlab.config.registry).to receive_messages(registry_settings)
+ allow(Auth::ContainerRegistryAuthenticationService).to receive(:full_access_token).and_return('token')
+ end
+
+ def stub_container_registry_tags(*tags)
+ allow_any_instance_of(ContainerRegistry::Client).to receive(:repository_tags).and_return(
+ { "tags" => tags }
+ )
+ allow_any_instance_of(ContainerRegistry::Client).to receive(:repository_manifest).and_return(
+ JSON.load(File.read(Rails.root + 'spec/fixtures/container_registry/tag_manifest.json'))
+ )
+ allow_any_instance_of(ContainerRegistry::Client).to receive(:blob).and_return(
+ File.read(Rails.root + 'spec/fixtures/container_registry/config_blob.json')
+ )
+ end
+
private
def gitlab_url
diff --git a/spec/tasks/gitlab/backup_rake_spec.rb b/spec/tasks/gitlab/backup_rake_spec.rb
index 05fc4c4554f..8aeb013eec6 100644
--- a/spec/tasks/gitlab/backup_rake_spec.rb
+++ b/spec/tasks/gitlab/backup_rake_spec.rb
@@ -21,7 +21,7 @@ describe 'gitlab:app namespace rake task' do
end
def reenable_backup_sub_tasks
- %w{db repo uploads builds artifacts lfs}.each do |subtask|
+ %w{db repo uploads builds artifacts lfs registry}.each do |subtask|
Rake::Task["gitlab:backup:#{subtask}:create"].reenable
end
end
@@ -65,6 +65,7 @@ describe 'gitlab:app namespace rake task' do
expect(Rake::Task['gitlab:backup:uploads:restore']).to receive(:invoke)
expect(Rake::Task['gitlab:backup:artifacts:restore']).to receive(:invoke)
expect(Rake::Task['gitlab:backup:lfs:restore']).to receive(:invoke)
+ expect(Rake::Task['gitlab:backup:registry:restore']).to receive(:invoke)
expect(Rake::Task['gitlab:shell:setup']).to receive(:invoke)
expect { run_rake_task('gitlab:backup:restore') }.not_to raise_error
end
@@ -122,7 +123,7 @@ describe 'gitlab:app namespace rake task' do
it 'should set correct permissions on the tar contents' do
tar_contents, exit_status = Gitlab::Popen.popen(
- %W{tar -tvf #{@backup_tar} db uploads.tar.gz repositories builds.tar.gz artifacts.tar.gz lfs.tar.gz}
+ %W{tar -tvf #{@backup_tar} db uploads.tar.gz repositories builds.tar.gz artifacts.tar.gz lfs.tar.gz registry.tar.gz}
)
expect(exit_status).to eq(0)
expect(tar_contents).to match('db/')
@@ -131,12 +132,13 @@ describe 'gitlab:app namespace rake task' do
expect(tar_contents).to match('builds.tar.gz')
expect(tar_contents).to match('artifacts.tar.gz')
expect(tar_contents).to match('lfs.tar.gz')
- expect(tar_contents).not_to match(/^.{4,9}[rwx].* (database.sql.gz|uploads.tar.gz|repositories|builds.tar.gz|artifacts.tar.gz)\/$/)
+ expect(tar_contents).to match('registry.tar.gz')
+ expect(tar_contents).not_to match(/^.{4,9}[rwx].* (database.sql.gz|uploads.tar.gz|repositories|builds.tar.gz|artifacts.tar.gz|registry.tar.gz)\/$/)
end
it 'should delete temp directories' do
temp_dirs = Dir.glob(
- File.join(Gitlab.config.backup.path, '{db,repositories,uploads,builds,artifacts,lfs}')
+ File.join(Gitlab.config.backup.path, '{db,repositories,uploads,builds,artifacts,lfs,registry}')
)
expect(temp_dirs).to be_empty
@@ -172,7 +174,7 @@ describe 'gitlab:app namespace rake task' do
it "does not contain skipped item" do
tar_contents, _exit_status = Gitlab::Popen.popen(
- %W{tar -tvf #{@backup_tar} db uploads.tar.gz repositories builds.tar.gz artifacts.tar.gz lfs.tar.gz}
+ %W{tar -tvf #{@backup_tar} db uploads.tar.gz repositories builds.tar.gz artifacts.tar.gz lfs.tar.gz registry.tar.gz}
)
expect(tar_contents).to match('db/')
@@ -180,6 +182,7 @@ describe 'gitlab:app namespace rake task' do
expect(tar_contents).to match('builds.tar.gz')
expect(tar_contents).to match('artifacts.tar.gz')
expect(tar_contents).to match('lfs.tar.gz')
+ expect(tar_contents).to match('registry.tar.gz')
expect(tar_contents).not_to match('repositories/')
end
@@ -195,6 +198,7 @@ describe 'gitlab:app namespace rake task' do
expect(Rake::Task['gitlab:backup:builds:restore']).to receive :invoke
expect(Rake::Task['gitlab:backup:artifacts:restore']).to receive :invoke
expect(Rake::Task['gitlab:backup:lfs:restore']).to receive :invoke
+ expect(Rake::Task['gitlab:backup:registry:restore']).to receive :invoke
expect(Rake::Task['gitlab:shell:setup']).to receive :invoke
expect { run_rake_task('gitlab:backup:restore') }.not_to raise_error
end
diff --git a/spec/workers/post_receive_spec.rb b/spec/workers/post_receive_spec.rb
index 94ff3457902..2f465bcf1e3 100644
--- a/spec/workers/post_receive_spec.rb
+++ b/spec/workers/post_receive_spec.rb
@@ -48,6 +48,22 @@ describe PostReceive do
PostReceive.new.perform(pwd(project), key_id, base64_changes)
end
end
+
+ context "gitlab-ci.yml" do
+ subject { PostReceive.new.perform(pwd(project), key_id, base64_changes) }
+
+ context "creates a Ci::Commit for every change" do
+ before { stub_ci_commit_to_return_yaml_file }
+
+ it { expect{ subject }.to change{ Ci::Commit.count }.by(2) }
+ end
+
+ context "does not create a Ci::Commit" do
+ before { stub_ci_commit_yaml_file(nil) }
+
+ it { expect{ subject }.to_not change{ Ci::Commit.count } }
+ end
+ end
end
context "webhook" do
diff --git a/spec/workers/repository_import_worker_spec.rb b/spec/workers/repository_import_worker_spec.rb
index 6739063543b..f1b1574abf4 100644
--- a/spec/workers/repository_import_worker_spec.rb
+++ b/spec/workers/repository_import_worker_spec.rb
@@ -6,14 +6,28 @@ describe RepositoryImportWorker do
subject { described_class.new }
describe '#perform' do
- it 'imports a project' do
- expect_any_instance_of(Projects::ImportService).to receive(:execute).
- and_return({ status: :ok })
+ context 'when the import was successful' do
+ it 'imports a project' do
+ expect_any_instance_of(Projects::ImportService).to receive(:execute).
+ and_return({ status: :ok })
- expect_any_instance_of(Repository).to receive(:expire_emptiness_caches)
- expect_any_instance_of(Project).to receive(:import_finish)
+ expect_any_instance_of(Repository).to receive(:expire_emptiness_caches)
+ expect_any_instance_of(Project).to receive(:import_finish)
- subject.perform(project.id)
+ subject.perform(project.id)
+ end
+ end
+
+ context 'when the import has failed' do
+ it 'hide the credentials that were used in the import URL' do
+ error = %Q{remote: Not Found fatal: repository 'https://user:pass@test.com/root/repoC.git/' not found }
+ expect_any_instance_of(Projects::ImportService).to receive(:execute).
+ and_return({ status: :error, message: error })
+
+ subject.perform(project.id)
+
+ expect(project.reload.import_error).to include("https://*****:*****@test.com/root/repoC.git/")
+ end
end
end
end
diff --git a/vendor/assets/stylesheets/animate.css b/vendor/assets/stylesheets/animate.css
deleted file mode 100644
index b6f61295392..00000000000
--- a/vendor/assets/stylesheets/animate.css
+++ /dev/null
@@ -1,11 +0,0 @@
-@charset "UTF-8";
-
-/*!
- * animate.css -http://daneden.me/animate
- * Version - 3.5.1
- * Licensed under the MIT license - http://opensource.org/licenses/MIT
- *
- * Copyright (c) 2016 Daniel Eden
- */
-
-.animated{-webkit-animation-duration:1s;animation-duration:1s;-webkit-animation-fill-mode:both;animation-fill-mode:both}.animated.infinite{-webkit-animation-iteration-count:infinite;animation-iteration-count:infinite}.animated.hinge{-webkit-animation-duration:2s;animation-duration:2s}.animated.bounceIn,.animated.bounceOut,.animated.flipOutX,.animated.flipOutY{-webkit-animation-duration:.75s;animation-duration:.75s}@-webkit-keyframes bounce{0%,20%,53%,80%,to{-webkit-animation-timing-function:cubic-bezier(.215,.61,.355,1);animation-timing-function:cubic-bezier(.215,.61,.355,1);-webkit-transform:translateZ(0);transform:translateZ(0)}40%,43%{-webkit-transform:translate3d(0,-30px,0);transform:translate3d(0,-30px,0)}40%,43%,70%{-webkit-animation-timing-function:cubic-bezier(.755,.05,.855,.06);animation-timing-function:cubic-bezier(.755,.05,.855,.06)}70%{-webkit-transform:translate3d(0,-15px,0);transform:translate3d(0,-15px,0)}90%{-webkit-transform:translate3d(0,-4px,0);transform:translate3d(0,-4px,0)}}@keyframes bounce{0%,20%,53%,80%,to{-webkit-animation-timing-function:cubic-bezier(.215,.61,.355,1);animation-timing-function:cubic-bezier(.215,.61,.355,1);-webkit-transform:translateZ(0);transform:translateZ(0)}40%,43%{-webkit-transform:translate3d(0,-30px,0);transform:translate3d(0,-30px,0)}40%,43%,70%{-webkit-animation-timing-function:cubic-bezier(.755,.05,.855,.06);animation-timing-function:cubic-bezier(.755,.05,.855,.06)}70%{-webkit-transform:translate3d(0,-15px,0);transform:translate3d(0,-15px,0)}90%{-webkit-transform:translate3d(0,-4px,0);transform:translate3d(0,-4px,0)}}.bounce{-webkit-animation-name:bounce;animation-name:bounce;-webkit-transform-origin:center bottom;transform-origin:center bottom}@-webkit-keyframes flash{0%,50%,to{opacity:1}25%,75%{opacity:0}}@keyframes flash{0%,50%,to{opacity:1}25%,75%{opacity:0}}.flash{-webkit-animation-name:flash;animation-name:flash}@-webkit-keyframes pulse{0%{-webkit-transform:scaleX(1);transform:scaleX(1)}50%{-webkit-transform:scale3d(1.05,1.05,1.05);transform:scale3d(1.05,1.05,1.05)}to{-webkit-transform:scaleX(1);transform:scaleX(1)}}@keyframes pulse{0%{-webkit-transform:scaleX(1);transform:scaleX(1)}50%{-webkit-transform:scale3d(1.05,1.05,1.05);transform:scale3d(1.05,1.05,1.05)}to{-webkit-transform:scaleX(1);transform:scaleX(1)}}.pulse{-webkit-animation-name:pulse;animation-name:pulse}@-webkit-keyframes rubberBand{0%{-webkit-transform:scaleX(1);transform:scaleX(1)}30%{-webkit-transform:scale3d(1.25,.75,1);transform:scale3d(1.25,.75,1)}40%{-webkit-transform:scale3d(.75,1.25,1);transform:scale3d(.75,1.25,1)}50%{-webkit-transform:scale3d(1.15,.85,1);transform:scale3d(1.15,.85,1)}65%{-webkit-transform:scale3d(.95,1.05,1);transform:scale3d(.95,1.05,1)}75%{-webkit-transform:scale3d(1.05,.95,1);transform:scale3d(1.05,.95,1)}to{-webkit-transform:scaleX(1);transform:scaleX(1)}}@keyframes rubberBand{0%{-webkit-transform:scaleX(1);transform:scaleX(1)}30%{-webkit-transform:scale3d(1.25,.75,1);transform:scale3d(1.25,.75,1)}40%{-webkit-transform:scale3d(.75,1.25,1);transform:scale3d(.75,1.25,1)}50%{-webkit-transform:scale3d(1.15,.85,1);transform:scale3d(1.15,.85,1)}65%{-webkit-transform:scale3d(.95,1.05,1);transform:scale3d(.95,1.05,1)}75%{-webkit-transform:scale3d(1.05,.95,1);transform:scale3d(1.05,.95,1)}to{-webkit-transform:scaleX(1);transform:scaleX(1)}}.rubberBand{-webkit-animation-name:rubberBand;animation-name:rubberBand}@-webkit-keyframes shake{0%,to{-webkit-transform:translateZ(0);transform:translateZ(0)}10%,30%,50%,70%,90%{-webkit-transform:translate3d(-10px,0,0);transform:translate3d(-10px,0,0)}20%,40%,60%,80%{-webkit-transform:translate3d(10px,0,0);transform:translate3d(10px,0,0)}}@keyframes shake{0%,to{-webkit-transform:translateZ(0);transform:translateZ(0)}10%,30%,50%,70%,90%{-webkit-transform:translate3d(-10px,0,0);transform:translate3d(-10px,0,0)}20%,40%,60%,80%{-webkit-transform:translate3d(10px,0,0);transform:translate3d(10px,0,0)}}.shake{-webkit-animation-name:shake;animation-name:shake}@-webkit-keyframes headShake{0%{-webkit-transform:translateX(0);transform:translateX(0)}6.5%{-webkit-transform:translateX(-6px) rotateY(-9deg);transform:translateX(-6px) rotateY(-9deg)}18.5%{-webkit-transform:translateX(5px) rotateY(7deg);transform:translateX(5px) rotateY(7deg)}31.5%{-webkit-transform:translateX(-3px) rotateY(-5deg);transform:translateX(-3px) rotateY(-5deg)}43.5%{-webkit-transform:translateX(2px) rotateY(3deg);transform:translateX(2px) rotateY(3deg)}50%{-webkit-transform:translateX(0);transform:translateX(0)}}@keyframes headShake{0%{-webkit-transform:translateX(0);transform:translateX(0)}6.5%{-webkit-transform:translateX(-6px) rotateY(-9deg);transform:translateX(-6px) rotateY(-9deg)}18.5%{-webkit-transform:translateX(5px) rotateY(7deg);transform:translateX(5px) rotateY(7deg)}31.5%{-webkit-transform:translateX(-3px) rotateY(-5deg);transform:translateX(-3px) rotateY(-5deg)}43.5%{-webkit-transform:translateX(2px) rotateY(3deg);transform:translateX(2px) rotateY(3deg)}50%{-webkit-transform:translateX(0);transform:translateX(0)}}.headShake{-webkit-animation-timing-function:ease-in-out;animation-timing-function:ease-in-out;-webkit-animation-name:headShake;animation-name:headShake}@-webkit-keyframes swing{20%{-webkit-transform:rotate(15deg);transform:rotate(15deg)}40%{-webkit-transform:rotate(-10deg);transform:rotate(-10deg)}60%{-webkit-transform:rotate(5deg);transform:rotate(5deg)}80%{-webkit-transform:rotate(-5deg);transform:rotate(-5deg)}to{-webkit-transform:rotate(0deg);transform:rotate(0deg)}}@keyframes swing{20%{-webkit-transform:rotate(15deg);transform:rotate(15deg)}40%{-webkit-transform:rotate(-10deg);transform:rotate(-10deg)}60%{-webkit-transform:rotate(5deg);transform:rotate(5deg)}80%{-webkit-transform:rotate(-5deg);transform:rotate(-5deg)}to{-webkit-transform:rotate(0deg);transform:rotate(0deg)}}.swing{-webkit-transform-origin:top center;transform-origin:top center;-webkit-animation-name:swing;animation-name:swing}@-webkit-keyframes tada{0%{-webkit-transform:scaleX(1);transform:scaleX(1)}10%,20%{-webkit-transform:scale3d(.9,.9,.9) rotate(-3deg);transform:scale3d(.9,.9,.9) rotate(-3deg)}30%,50%,70%,90%{-webkit-transform:scale3d(1.1,1.1,1.1) rotate(3deg);transform:scale3d(1.1,1.1,1.1) rotate(3deg)}40%,60%,80%{-webkit-transform:scale3d(1.1,1.1,1.1) rotate(-3deg);transform:scale3d(1.1,1.1,1.1) rotate(-3deg)}to{-webkit-transform:scaleX(1);transform:scaleX(1)}}@keyframes tada{0%{-webkit-transform:scaleX(1);transform:scaleX(1)}10%,20%{-webkit-transform:scale3d(.9,.9,.9) rotate(-3deg);transform:scale3d(.9,.9,.9) rotate(-3deg)}30%,50%,70%,90%{-webkit-transform:scale3d(1.1,1.1,1.1) rotate(3deg);transform:scale3d(1.1,1.1,1.1) rotate(3deg)}40%,60%,80%{-webkit-transform:scale3d(1.1,1.1,1.1) rotate(-3deg);transform:scale3d(1.1,1.1,1.1) rotate(-3deg)}to{-webkit-transform:scaleX(1);transform:scaleX(1)}}.tada{-webkit-animation-name:tada;animation-name:tada}@-webkit-keyframes wobble{0%{-webkit-transform:none;transform:none}15%{-webkit-transform:translate3d(-25%,0,0) rotate(-5deg);transform:translate3d(-25%,0,0) rotate(-5deg)}30%{-webkit-transform:translate3d(20%,0,0) rotate(3deg);transform:translate3d(20%,0,0) rotate(3deg)}45%{-webkit-transform:translate3d(-15%,0,0) rotate(-3deg);transform:translate3d(-15%,0,0) rotate(-3deg)}60%{-webkit-transform:translate3d(10%,0,0) rotate(2deg);transform:translate3d(10%,0,0) rotate(2deg)}75%{-webkit-transform:translate3d(-5%,0,0) rotate(-1deg);transform:translate3d(-5%,0,0) rotate(-1deg)}to{-webkit-transform:none;transform:none}}@keyframes wobble{0%{-webkit-transform:none;transform:none}15%{-webkit-transform:translate3d(-25%,0,0) rotate(-5deg);transform:translate3d(-25%,0,0) rotate(-5deg)}30%{-webkit-transform:translate3d(20%,0,0) rotate(3deg);transform:translate3d(20%,0,0) rotate(3deg)}45%{-webkit-transform:translate3d(-15%,0,0) rotate(-3deg);transform:translate3d(-15%,0,0) rotate(-3deg)}60%{-webkit-transform:translate3d(10%,0,0) rotate(2deg);transform:translate3d(10%,0,0) rotate(2deg)}75%{-webkit-transform:translate3d(-5%,0,0) rotate(-1deg);transform:translate3d(-5%,0,0) rotate(-1deg)}to{-webkit-transform:none;transform:none}}.wobble{-webkit-animation-name:wobble;animation-name:wobble}@-webkit-keyframes jello{0%,11.1%,to{-webkit-transform:none;transform:none}22.2%{-webkit-transform:skewX(-12.5deg) skewY(-12.5deg);transform:skewX(-12.5deg) skewY(-12.5deg)}33.3%{-webkit-transform:skewX(6.25deg) skewY(6.25deg);transform:skewX(6.25deg) skewY(6.25deg)}44.4%{-webkit-transform:skewX(-3.125deg) skewY(-3.125deg);transform:skewX(-3.125deg) skewY(-3.125deg)}55.5%{-webkit-transform:skewX(1.5625deg) skewY(1.5625deg);transform:skewX(1.5625deg) skewY(1.5625deg)}66.6%{-webkit-transform:skewX(-.78125deg) skewY(-.78125deg);transform:skewX(-.78125deg) skewY(-.78125deg)}77.7%{-webkit-transform:skewX(.390625deg) skewY(.390625deg);transform:skewX(.390625deg) skewY(.390625deg)}88.8%{-webkit-transform:skewX(-.1953125deg) skewY(-.1953125deg);transform:skewX(-.1953125deg) skewY(-.1953125deg)}}@keyframes jello{0%,11.1%,to{-webkit-transform:none;transform:none}22.2%{-webkit-transform:skewX(-12.5deg) skewY(-12.5deg);transform:skewX(-12.5deg) skewY(-12.5deg)}33.3%{-webkit-transform:skewX(6.25deg) skewY(6.25deg);transform:skewX(6.25deg) skewY(6.25deg)}44.4%{-webkit-transform:skewX(-3.125deg) skewY(-3.125deg);transform:skewX(-3.125deg) skewY(-3.125deg)}55.5%{-webkit-transform:skewX(1.5625deg) skewY(1.5625deg);transform:skewX(1.5625deg) skewY(1.5625deg)}66.6%{-webkit-transform:skewX(-.78125deg) skewY(-.78125deg);transform:skewX(-.78125deg) skewY(-.78125deg)}77.7%{-webkit-transform:skewX(.390625deg) skewY(.390625deg);transform:skewX(.390625deg) skewY(.390625deg)}88.8%{-webkit-transform:skewX(-.1953125deg) skewY(-.1953125deg);transform:skewX(-.1953125deg) skewY(-.1953125deg)}}.jello{-webkit-animation-name:jello;animation-name:jello;-webkit-transform-origin:center;transform-origin:center}@-webkit-keyframes bounceIn{0%,20%,40%,60%,80%,to{-webkit-animation-timing-function:cubic-bezier(.215,.61,.355,1);animation-timing-function:cubic-bezier(.215,.61,.355,1)}0%{opacity:0;-webkit-transform:scale3d(.3,.3,.3);transform:scale3d(.3,.3,.3)}20%{-webkit-transform:scale3d(1.1,1.1,1.1);transform:scale3d(1.1,1.1,1.1)}40%{-webkit-transform:scale3d(.9,.9,.9);transform:scale3d(.9,.9,.9)}60%{opacity:1;-webkit-transform:scale3d(1.03,1.03,1.03);transform:scale3d(1.03,1.03,1.03)}80%{-webkit-transform:scale3d(.97,.97,.97);transform:scale3d(.97,.97,.97)}to{opacity:1;-webkit-transform:scaleX(1);transform:scaleX(1)}}@keyframes bounceIn{0%,20%,40%,60%,80%,to{-webkit-animation-timing-function:cubic-bezier(.215,.61,.355,1);animation-timing-function:cubic-bezier(.215,.61,.355,1)}0%{opacity:0;-webkit-transform:scale3d(.3,.3,.3);transform:scale3d(.3,.3,.3)}20%{-webkit-transform:scale3d(1.1,1.1,1.1);transform:scale3d(1.1,1.1,1.1)}40%{-webkit-transform:scale3d(.9,.9,.9);transform:scale3d(.9,.9,.9)}60%{opacity:1;-webkit-transform:scale3d(1.03,1.03,1.03);transform:scale3d(1.03,1.03,1.03)}80%{-webkit-transform:scale3d(.97,.97,.97);transform:scale3d(.97,.97,.97)}to{opacity:1;-webkit-transform:scaleX(1);transform:scaleX(1)}}.bounceIn{-webkit-animation-name:bounceIn;animation-name:bounceIn}@-webkit-keyframes bounceInDown{0%,60%,75%,90%,to{-webkit-animation-timing-function:cubic-bezier(.215,.61,.355,1);animation-timing-function:cubic-bezier(.215,.61,.355,1)}0%{opacity:0;-webkit-transform:translate3d(0,-3000px,0);transform:translate3d(0,-3000px,0)}60%{opacity:1;-webkit-transform:translate3d(0,25px,0);transform:translate3d(0,25px,0)}75%{-webkit-transform:translate3d(0,-10px,0);transform:translate3d(0,-10px,0)}90%{-webkit-transform:translate3d(0,5px,0);transform:translate3d(0,5px,0)}to{-webkit-transform:none;transform:none}}@keyframes bounceInDown{0%,60%,75%,90%,to{-webkit-animation-timing-function:cubic-bezier(.215,.61,.355,1);animation-timing-function:cubic-bezier(.215,.61,.355,1)}0%{opacity:0;-webkit-transform:translate3d(0,-3000px,0);transform:translate3d(0,-3000px,0)}60%{opacity:1;-webkit-transform:translate3d(0,25px,0);transform:translate3d(0,25px,0)}75%{-webkit-transform:translate3d(0,-10px,0);transform:translate3d(0,-10px,0)}90%{-webkit-transform:translate3d(0,5px,0);transform:translate3d(0,5px,0)}to{-webkit-transform:none;transform:none}}.bounceInDown{-webkit-animation-name:bounceInDown;animation-name:bounceInDown}@-webkit-keyframes bounceInLeft{0%,60%,75%,90%,to{-webkit-animation-timing-function:cubic-bezier(.215,.61,.355,1);animation-timing-function:cubic-bezier(.215,.61,.355,1)}0%{opacity:0;-webkit-transform:translate3d(-3000px,0,0);transform:translate3d(-3000px,0,0)}60%{opacity:1;-webkit-transform:translate3d(25px,0,0);transform:translate3d(25px,0,0)}75%{-webkit-transform:translate3d(-10px,0,0);transform:translate3d(-10px,0,0)}90%{-webkit-transform:translate3d(5px,0,0);transform:translate3d(5px,0,0)}to{-webkit-transform:none;transform:none}}@keyframes bounceInLeft{0%,60%,75%,90%,to{-webkit-animation-timing-function:cubic-bezier(.215,.61,.355,1);animation-timing-function:cubic-bezier(.215,.61,.355,1)}0%{opacity:0;-webkit-transform:translate3d(-3000px,0,0);transform:translate3d(-3000px,0,0)}60%{opacity:1;-webkit-transform:translate3d(25px,0,0);transform:translate3d(25px,0,0)}75%{-webkit-transform:translate3d(-10px,0,0);transform:translate3d(-10px,0,0)}90%{-webkit-transform:translate3d(5px,0,0);transform:translate3d(5px,0,0)}to{-webkit-transform:none;transform:none}}.bounceInLeft{-webkit-animation-name:bounceInLeft;animation-name:bounceInLeft}@-webkit-keyframes bounceInRight{0%,60%,75%,90%,to{-webkit-animation-timing-function:cubic-bezier(.215,.61,.355,1);animation-timing-function:cubic-bezier(.215,.61,.355,1)}0%{opacity:0;-webkit-transform:translate3d(3000px,0,0);transform:translate3d(3000px,0,0)}60%{opacity:1;-webkit-transform:translate3d(-25px,0,0);transform:translate3d(-25px,0,0)}75%{-webkit-transform:translate3d(10px,0,0);transform:translate3d(10px,0,0)}90%{-webkit-transform:translate3d(-5px,0,0);transform:translate3d(-5px,0,0)}to{-webkit-transform:none;transform:none}}@keyframes bounceInRight{0%,60%,75%,90%,to{-webkit-animation-timing-function:cubic-bezier(.215,.61,.355,1);animation-timing-function:cubic-bezier(.215,.61,.355,1)}0%{opacity:0;-webkit-transform:translate3d(3000px,0,0);transform:translate3d(3000px,0,0)}60%{opacity:1;-webkit-transform:translate3d(-25px,0,0);transform:translate3d(-25px,0,0)}75%{-webkit-transform:translate3d(10px,0,0);transform:translate3d(10px,0,0)}90%{-webkit-transform:translate3d(-5px,0,0);transform:translate3d(-5px,0,0)}to{-webkit-transform:none;transform:none}}.bounceInRight{-webkit-animation-name:bounceInRight;animation-name:bounceInRight}@-webkit-keyframes bounceInUp{0%,60%,75%,90%,to{-webkit-animation-timing-function:cubic-bezier(.215,.61,.355,1);animation-timing-function:cubic-bezier(.215,.61,.355,1)}0%{opacity:0;-webkit-transform:translate3d(0,3000px,0);transform:translate3d(0,3000px,0)}60%{opacity:1;-webkit-transform:translate3d(0,-20px,0);transform:translate3d(0,-20px,0)}75%{-webkit-transform:translate3d(0,10px,0);transform:translate3d(0,10px,0)}90%{-webkit-transform:translate3d(0,-5px,0);transform:translate3d(0,-5px,0)}to{-webkit-transform:translateZ(0);transform:translateZ(0)}}@keyframes bounceInUp{0%,60%,75%,90%,to{-webkit-animation-timing-function:cubic-bezier(.215,.61,.355,1);animation-timing-function:cubic-bezier(.215,.61,.355,1)}0%{opacity:0;-webkit-transform:translate3d(0,3000px,0);transform:translate3d(0,3000px,0)}60%{opacity:1;-webkit-transform:translate3d(0,-20px,0);transform:translate3d(0,-20px,0)}75%{-webkit-transform:translate3d(0,10px,0);transform:translate3d(0,10px,0)}90%{-webkit-transform:translate3d(0,-5px,0);transform:translate3d(0,-5px,0)}to{-webkit-transform:translateZ(0);transform:translateZ(0)}}.bounceInUp{-webkit-animation-name:bounceInUp;animation-name:bounceInUp}@-webkit-keyframes bounceOut{20%{-webkit-transform:scale3d(.9,.9,.9);transform:scale3d(.9,.9,.9)}50%,55%{opacity:1;-webkit-transform:scale3d(1.1,1.1,1.1);transform:scale3d(1.1,1.1,1.1)}to{opacity:0;-webkit-transform:scale3d(.3,.3,.3);transform:scale3d(.3,.3,.3)}}@keyframes bounceOut{20%{-webkit-transform:scale3d(.9,.9,.9);transform:scale3d(.9,.9,.9)}50%,55%{opacity:1;-webkit-transform:scale3d(1.1,1.1,1.1);transform:scale3d(1.1,1.1,1.1)}to{opacity:0;-webkit-transform:scale3d(.3,.3,.3);transform:scale3d(.3,.3,.3)}}.bounceOut{-webkit-animation-name:bounceOut;animation-name:bounceOut}@-webkit-keyframes bounceOutDown{20%{-webkit-transform:translate3d(0,10px,0);transform:translate3d(0,10px,0)}40%,45%{opacity:1;-webkit-transform:translate3d(0,-20px,0);transform:translate3d(0,-20px,0)}to{opacity:0;-webkit-transform:translate3d(0,2000px,0);transform:translate3d(0,2000px,0)}}@keyframes bounceOutDown{20%{-webkit-transform:translate3d(0,10px,0);transform:translate3d(0,10px,0)}40%,45%{opacity:1;-webkit-transform:translate3d(0,-20px,0);transform:translate3d(0,-20px,0)}to{opacity:0;-webkit-transform:translate3d(0,2000px,0);transform:translate3d(0,2000px,0)}}.bounceOutDown{-webkit-animation-name:bounceOutDown;animation-name:bounceOutDown}@-webkit-keyframes bounceOutLeft{20%{opacity:1;-webkit-transform:translate3d(20px,0,0);transform:translate3d(20px,0,0)}to{opacity:0;-webkit-transform:translate3d(-2000px,0,0);transform:translate3d(-2000px,0,0)}}@keyframes bounceOutLeft{20%{opacity:1;-webkit-transform:translate3d(20px,0,0);transform:translate3d(20px,0,0)}to{opacity:0;-webkit-transform:translate3d(-2000px,0,0);transform:translate3d(-2000px,0,0)}}.bounceOutLeft{-webkit-animation-name:bounceOutLeft;animation-name:bounceOutLeft}@-webkit-keyframes bounceOutRight{20%{opacity:1;-webkit-transform:translate3d(-20px,0,0);transform:translate3d(-20px,0,0)}to{opacity:0;-webkit-transform:translate3d(2000px,0,0);transform:translate3d(2000px,0,0)}}@keyframes bounceOutRight{20%{opacity:1;-webkit-transform:translate3d(-20px,0,0);transform:translate3d(-20px,0,0)}to{opacity:0;-webkit-transform:translate3d(2000px,0,0);transform:translate3d(2000px,0,0)}}.bounceOutRight{-webkit-animation-name:bounceOutRight;animation-name:bounceOutRight}@-webkit-keyframes bounceOutUp{20%{-webkit-transform:translate3d(0,-10px,0);transform:translate3d(0,-10px,0)}40%,45%{opacity:1;-webkit-transform:translate3d(0,20px,0);transform:translate3d(0,20px,0)}to{opacity:0;-webkit-transform:translate3d(0,-2000px,0);transform:translate3d(0,-2000px,0)}}@keyframes bounceOutUp{20%{-webkit-transform:translate3d(0,-10px,0);transform:translate3d(0,-10px,0)}40%,45%{opacity:1;-webkit-transform:translate3d(0,20px,0);transform:translate3d(0,20px,0)}to{opacity:0;-webkit-transform:translate3d(0,-2000px,0);transform:translate3d(0,-2000px,0)}}.bounceOutUp{-webkit-animation-name:bounceOutUp;animation-name:bounceOutUp}@-webkit-keyframes fadeIn{0%{opacity:0}to{opacity:1}}@keyframes fadeIn{0%{opacity:0}to{opacity:1}}.fadeIn{-webkit-animation-name:fadeIn;animation-name:fadeIn}@-webkit-keyframes fadeInDown{0%{opacity:0;-webkit-transform:translate3d(0,-100%,0);transform:translate3d(0,-100%,0)}to{opacity:1;-webkit-transform:none;transform:none}}@keyframes fadeInDown{0%{opacity:0;-webkit-transform:translate3d(0,-100%,0);transform:translate3d(0,-100%,0)}to{opacity:1;-webkit-transform:none;transform:none}}.fadeInDown{-webkit-animation-name:fadeInDown;animation-name:fadeInDown}@-webkit-keyframes fadeInDownBig{0%{opacity:0;-webkit-transform:translate3d(0,-2000px,0);transform:translate3d(0,-2000px,0)}to{opacity:1;-webkit-transform:none;transform:none}}@keyframes fadeInDownBig{0%{opacity:0;-webkit-transform:translate3d(0,-2000px,0);transform:translate3d(0,-2000px,0)}to{opacity:1;-webkit-transform:none;transform:none}}.fadeInDownBig{-webkit-animation-name:fadeInDownBig;animation-name:fadeInDownBig}@-webkit-keyframes fadeInLeft{0%{opacity:0;-webkit-transform:translate3d(-100%,0,0);transform:translate3d(-100%,0,0)}to{opacity:1;-webkit-transform:none;transform:none}}@keyframes fadeInLeft{0%{opacity:0;-webkit-transform:translate3d(-100%,0,0);transform:translate3d(-100%,0,0)}to{opacity:1;-webkit-transform:none;transform:none}}.fadeInLeft{-webkit-animation-name:fadeInLeft;animation-name:fadeInLeft}@-webkit-keyframes fadeInLeftBig{0%{opacity:0;-webkit-transform:translate3d(-2000px,0,0);transform:translate3d(-2000px,0,0)}to{opacity:1;-webkit-transform:none;transform:none}}@keyframes fadeInLeftBig{0%{opacity:0;-webkit-transform:translate3d(-2000px,0,0);transform:translate3d(-2000px,0,0)}to{opacity:1;-webkit-transform:none;transform:none}}.fadeInLeftBig{-webkit-animation-name:fadeInLeftBig;animation-name:fadeInLeftBig}@-webkit-keyframes fadeInRight{0%{opacity:0;-webkit-transform:translate3d(100%,0,0);transform:translate3d(100%,0,0)}to{opacity:1;-webkit-transform:none;transform:none}}@keyframes fadeInRight{0%{opacity:0;-webkit-transform:translate3d(100%,0,0);transform:translate3d(100%,0,0)}to{opacity:1;-webkit-transform:none;transform:none}}.fadeInRight{-webkit-animation-name:fadeInRight;animation-name:fadeInRight}@-webkit-keyframes fadeInRightBig{0%{opacity:0;-webkit-transform:translate3d(2000px,0,0);transform:translate3d(2000px,0,0)}to{opacity:1;-webkit-transform:none;transform:none}}@keyframes fadeInRightBig{0%{opacity:0;-webkit-transform:translate3d(2000px,0,0);transform:translate3d(2000px,0,0)}to{opacity:1;-webkit-transform:none;transform:none}}.fadeInRightBig{-webkit-animation-name:fadeInRightBig;animation-name:fadeInRightBig}@-webkit-keyframes fadeInUp{0%{opacity:0;-webkit-transform:translate3d(0,100%,0);transform:translate3d(0,100%,0)}to{opacity:1;-webkit-transform:none;transform:none}}@keyframes fadeInUp{0%{opacity:0;-webkit-transform:translate3d(0,100%,0);transform:translate3d(0,100%,0)}to{opacity:1;-webkit-transform:none;transform:none}}.fadeInUp{-webkit-animation-name:fadeInUp;animation-name:fadeInUp}@-webkit-keyframes fadeInUpBig{0%{opacity:0;-webkit-transform:translate3d(0,2000px,0);transform:translate3d(0,2000px,0)}to{opacity:1;-webkit-transform:none;transform:none}}@keyframes fadeInUpBig{0%{opacity:0;-webkit-transform:translate3d(0,2000px,0);transform:translate3d(0,2000px,0)}to{opacity:1;-webkit-transform:none;transform:none}}.fadeInUpBig{-webkit-animation-name:fadeInUpBig;animation-name:fadeInUpBig}@-webkit-keyframes fadeOut{0%{opacity:1}to{opacity:0}}@keyframes fadeOut{0%{opacity:1}to{opacity:0}}.fadeOut{-webkit-animation-name:fadeOut;animation-name:fadeOut}@-webkit-keyframes fadeOutDown{0%{opacity:1}to{opacity:0;-webkit-transform:translate3d(0,100%,0);transform:translate3d(0,100%,0)}}@keyframes fadeOutDown{0%{opacity:1}to{opacity:0;-webkit-transform:translate3d(0,100%,0);transform:translate3d(0,100%,0)}}.fadeOutDown{-webkit-animation-name:fadeOutDown;animation-name:fadeOutDown}@-webkit-keyframes fadeOutDownBig{0%{opacity:1}to{opacity:0;-webkit-transform:translate3d(0,2000px,0);transform:translate3d(0,2000px,0)}}@keyframes fadeOutDownBig{0%{opacity:1}to{opacity:0;-webkit-transform:translate3d(0,2000px,0);transform:translate3d(0,2000px,0)}}.fadeOutDownBig{-webkit-animation-name:fadeOutDownBig;animation-name:fadeOutDownBig}@-webkit-keyframes fadeOutLeft{0%{opacity:1}to{opacity:0;-webkit-transform:translate3d(-100%,0,0);transform:translate3d(-100%,0,0)}}@keyframes fadeOutLeft{0%{opacity:1}to{opacity:0;-webkit-transform:translate3d(-100%,0,0);transform:translate3d(-100%,0,0)}}.fadeOutLeft{-webkit-animation-name:fadeOutLeft;animation-name:fadeOutLeft}@-webkit-keyframes fadeOutLeftBig{0%{opacity:1}to{opacity:0;-webkit-transform:translate3d(-2000px,0,0);transform:translate3d(-2000px,0,0)}}@keyframes fadeOutLeftBig{0%{opacity:1}to{opacity:0;-webkit-transform:translate3d(-2000px,0,0);transform:translate3d(-2000px,0,0)}}.fadeOutLeftBig{-webkit-animation-name:fadeOutLeftBig;animation-name:fadeOutLeftBig}@-webkit-keyframes fadeOutRight{0%{opacity:1}to{opacity:0;-webkit-transform:translate3d(100%,0,0);transform:translate3d(100%,0,0)}}@keyframes fadeOutRight{0%{opacity:1}to{opacity:0;-webkit-transform:translate3d(100%,0,0);transform:translate3d(100%,0,0)}}.fadeOutRight{-webkit-animation-name:fadeOutRight;animation-name:fadeOutRight}@-webkit-keyframes fadeOutRightBig{0%{opacity:1}to{opacity:0;-webkit-transform:translate3d(2000px,0,0);transform:translate3d(2000px,0,0)}}@keyframes fadeOutRightBig{0%{opacity:1}to{opacity:0;-webkit-transform:translate3d(2000px,0,0);transform:translate3d(2000px,0,0)}}.fadeOutRightBig{-webkit-animation-name:fadeOutRightBig;animation-name:fadeOutRightBig}@-webkit-keyframes fadeOutUp{0%{opacity:1}to{opacity:0;-webkit-transform:translate3d(0,-100%,0);transform:translate3d(0,-100%,0)}}@keyframes fadeOutUp{0%{opacity:1}to{opacity:0;-webkit-transform:translate3d(0,-100%,0);transform:translate3d(0,-100%,0)}}.fadeOutUp{-webkit-animation-name:fadeOutUp;animation-name:fadeOutUp}@-webkit-keyframes fadeOutUpBig{0%{opacity:1}to{opacity:0;-webkit-transform:translate3d(0,-2000px,0);transform:translate3d(0,-2000px,0)}}@keyframes fadeOutUpBig{0%{opacity:1}to{opacity:0;-webkit-transform:translate3d(0,-2000px,0);transform:translate3d(0,-2000px,0)}}.fadeOutUpBig{-webkit-animation-name:fadeOutUpBig;animation-name:fadeOutUpBig}@-webkit-keyframes flip{0%{-webkit-transform:perspective(400px) rotateY(-1turn);transform:perspective(400px) rotateY(-1turn)}0%,40%{-webkit-animation-timing-function:ease-out;animation-timing-function:ease-out}40%{-webkit-transform:perspective(400px) translateZ(150px) rotateY(-190deg);transform:perspective(400px) translateZ(150px) rotateY(-190deg)}50%{-webkit-transform:perspective(400px) translateZ(150px) rotateY(-170deg);transform:perspective(400px) translateZ(150px) rotateY(-170deg)}50%,80%{-webkit-animation-timing-function:ease-in;animation-timing-function:ease-in}80%{-webkit-transform:perspective(400px) scale3d(.95,.95,.95);transform:perspective(400px) scale3d(.95,.95,.95)}to{-webkit-transform:perspective(400px);transform:perspective(400px);-webkit-animation-timing-function:ease-in;animation-timing-function:ease-in}}@keyframes flip{0%{-webkit-transform:perspective(400px) rotateY(-1turn);transform:perspective(400px) rotateY(-1turn)}0%,40%{-webkit-animation-timing-function:ease-out;animation-timing-function:ease-out}40%{-webkit-transform:perspective(400px) translateZ(150px) rotateY(-190deg);transform:perspective(400px) translateZ(150px) rotateY(-190deg)}50%{-webkit-transform:perspective(400px) translateZ(150px) rotateY(-170deg);transform:perspective(400px) translateZ(150px) rotateY(-170deg)}50%,80%{-webkit-animation-timing-function:ease-in;animation-timing-function:ease-in}80%{-webkit-transform:perspective(400px) scale3d(.95,.95,.95);transform:perspective(400px) scale3d(.95,.95,.95)}to{-webkit-transform:perspective(400px);transform:perspective(400px);-webkit-animation-timing-function:ease-in;animation-timing-function:ease-in}}.animated.flip{-webkit-backface-visibility:visible;backface-visibility:visible;-webkit-animation-name:flip;animation-name:flip}@-webkit-keyframes flipInX{0%{-webkit-transform:perspective(400px) rotateX(90deg);transform:perspective(400px) rotateX(90deg);opacity:0}0%,40%{-webkit-animation-timing-function:ease-in;animation-timing-function:ease-in}40%{-webkit-transform:perspective(400px) rotateX(-20deg);transform:perspective(400px) rotateX(-20deg)}60%{-webkit-transform:perspective(400px) rotateX(10deg);transform:perspective(400px) rotateX(10deg);opacity:1}80%{-webkit-transform:perspective(400px) rotateX(-5deg);transform:perspective(400px) rotateX(-5deg)}to{-webkit-transform:perspective(400px);transform:perspective(400px)}}@keyframes flipInX{0%{-webkit-transform:perspective(400px) rotateX(90deg);transform:perspective(400px) rotateX(90deg);opacity:0}0%,40%{-webkit-animation-timing-function:ease-in;animation-timing-function:ease-in}40%{-webkit-transform:perspective(400px) rotateX(-20deg);transform:perspective(400px) rotateX(-20deg)}60%{-webkit-transform:perspective(400px) rotateX(10deg);transform:perspective(400px) rotateX(10deg);opacity:1}80%{-webkit-transform:perspective(400px) rotateX(-5deg);transform:perspective(400px) rotateX(-5deg)}to{-webkit-transform:perspective(400px);transform:perspective(400px)}}.flipInX{-webkit-backface-visibility:visible!important;backface-visibility:visible!important;-webkit-animation-name:flipInX;animation-name:flipInX}@-webkit-keyframes flipInY{0%{-webkit-transform:perspective(400px) rotateY(90deg);transform:perspective(400px) rotateY(90deg);opacity:0}0%,40%{-webkit-animation-timing-function:ease-in;animation-timing-function:ease-in}40%{-webkit-transform:perspective(400px) rotateY(-20deg);transform:perspective(400px) rotateY(-20deg)}60%{-webkit-transform:perspective(400px) rotateY(10deg);transform:perspective(400px) rotateY(10deg);opacity:1}80%{-webkit-transform:perspective(400px) rotateY(-5deg);transform:perspective(400px) rotateY(-5deg)}to{-webkit-transform:perspective(400px);transform:perspective(400px)}}@keyframes flipInY{0%{-webkit-transform:perspective(400px) rotateY(90deg);transform:perspective(400px) rotateY(90deg);opacity:0}0%,40%{-webkit-animation-timing-function:ease-in;animation-timing-function:ease-in}40%{-webkit-transform:perspective(400px) rotateY(-20deg);transform:perspective(400px) rotateY(-20deg)}60%{-webkit-transform:perspective(400px) rotateY(10deg);transform:perspective(400px) rotateY(10deg);opacity:1}80%{-webkit-transform:perspective(400px) rotateY(-5deg);transform:perspective(400px) rotateY(-5deg)}to{-webkit-transform:perspective(400px);transform:perspective(400px)}}.flipInY{-webkit-backface-visibility:visible!important;backface-visibility:visible!important;-webkit-animation-name:flipInY;animation-name:flipInY}@-webkit-keyframes flipOutX{0%{-webkit-transform:perspective(400px);transform:perspective(400px)}30%{-webkit-transform:perspective(400px) rotateX(-20deg);transform:perspective(400px) rotateX(-20deg);opacity:1}to{-webkit-transform:perspective(400px) rotateX(90deg);transform:perspective(400px) rotateX(90deg);opacity:0}}@keyframes flipOutX{0%{-webkit-transform:perspective(400px);transform:perspective(400px)}30%{-webkit-transform:perspective(400px) rotateX(-20deg);transform:perspective(400px) rotateX(-20deg);opacity:1}to{-webkit-transform:perspective(400px) rotateX(90deg);transform:perspective(400px) rotateX(90deg);opacity:0}}.flipOutX{-webkit-animation-name:flipOutX;animation-name:flipOutX;-webkit-backface-visibility:visible!important;backface-visibility:visible!important}@-webkit-keyframes flipOutY{0%{-webkit-transform:perspective(400px);transform:perspective(400px)}30%{-webkit-transform:perspective(400px) rotateY(-15deg);transform:perspective(400px) rotateY(-15deg);opacity:1}to{-webkit-transform:perspective(400px) rotateY(90deg);transform:perspective(400px) rotateY(90deg);opacity:0}}@keyframes flipOutY{0%{-webkit-transform:perspective(400px);transform:perspective(400px)}30%{-webkit-transform:perspective(400px) rotateY(-15deg);transform:perspective(400px) rotateY(-15deg);opacity:1}to{-webkit-transform:perspective(400px) rotateY(90deg);transform:perspective(400px) rotateY(90deg);opacity:0}}.flipOutY{-webkit-backface-visibility:visible!important;backface-visibility:visible!important;-webkit-animation-name:flipOutY;animation-name:flipOutY}@-webkit-keyframes lightSpeedIn{0%{-webkit-transform:translate3d(100%,0,0) skewX(-30deg);transform:translate3d(100%,0,0) skewX(-30deg);opacity:0}60%{-webkit-transform:skewX(20deg);transform:skewX(20deg)}60%,80%{opacity:1}80%{-webkit-transform:skewX(-5deg);transform:skewX(-5deg)}to{-webkit-transform:none;transform:none;opacity:1}}@keyframes lightSpeedIn{0%{-webkit-transform:translate3d(100%,0,0) skewX(-30deg);transform:translate3d(100%,0,0) skewX(-30deg);opacity:0}60%{-webkit-transform:skewX(20deg);transform:skewX(20deg)}60%,80%{opacity:1}80%{-webkit-transform:skewX(-5deg);transform:skewX(-5deg)}to{-webkit-transform:none;transform:none;opacity:1}}.lightSpeedIn{-webkit-animation-name:lightSpeedIn;animation-name:lightSpeedIn;-webkit-animation-timing-function:ease-out;animation-timing-function:ease-out}@-webkit-keyframes lightSpeedOut{0%{opacity:1}to{-webkit-transform:translate3d(100%,0,0) skewX(30deg);transform:translate3d(100%,0,0) skewX(30deg);opacity:0}}@keyframes lightSpeedOut{0%{opacity:1}to{-webkit-transform:translate3d(100%,0,0) skewX(30deg);transform:translate3d(100%,0,0) skewX(30deg);opacity:0}}.lightSpeedOut{-webkit-animation-name:lightSpeedOut;animation-name:lightSpeedOut;-webkit-animation-timing-function:ease-in;animation-timing-function:ease-in}@-webkit-keyframes rotateIn{0%{transform-origin:center;-webkit-transform:rotate(-200deg);transform:rotate(-200deg);opacity:0}0%,to{-webkit-transform-origin:center}to{transform-origin:center;-webkit-transform:none;transform:none;opacity:1}}@keyframes rotateIn{0%{transform-origin:center;-webkit-transform:rotate(-200deg);transform:rotate(-200deg);opacity:0}0%,to{-webkit-transform-origin:center}to{transform-origin:center;-webkit-transform:none;transform:none;opacity:1}}.rotateIn{-webkit-animation-name:rotateIn;animation-name:rotateIn}@-webkit-keyframes rotateInDownLeft{0%{transform-origin:left bottom;-webkit-transform:rotate(-45deg);transform:rotate(-45deg);opacity:0}0%,to{-webkit-transform-origin:left bottom}to{transform-origin:left bottom;-webkit-transform:none;transform:none;opacity:1}}@keyframes rotateInDownLeft{0%{transform-origin:left bottom;-webkit-transform:rotate(-45deg);transform:rotate(-45deg);opacity:0}0%,to{-webkit-transform-origin:left bottom}to{transform-origin:left bottom;-webkit-transform:none;transform:none;opacity:1}}.rotateInDownLeft{-webkit-animation-name:rotateInDownLeft;animation-name:rotateInDownLeft}@-webkit-keyframes rotateInDownRight{0%{transform-origin:right bottom;-webkit-transform:rotate(45deg);transform:rotate(45deg);opacity:0}0%,to{-webkit-transform-origin:right bottom}to{transform-origin:right bottom;-webkit-transform:none;transform:none;opacity:1}}@keyframes rotateInDownRight{0%{transform-origin:right bottom;-webkit-transform:rotate(45deg);transform:rotate(45deg);opacity:0}0%,to{-webkit-transform-origin:right bottom}to{transform-origin:right bottom;-webkit-transform:none;transform:none;opacity:1}}.rotateInDownRight{-webkit-animation-name:rotateInDownRight;animation-name:rotateInDownRight}@-webkit-keyframes rotateInUpLeft{0%{transform-origin:left bottom;-webkit-transform:rotate(45deg);transform:rotate(45deg);opacity:0}0%,to{-webkit-transform-origin:left bottom}to{transform-origin:left bottom;-webkit-transform:none;transform:none;opacity:1}}@keyframes rotateInUpLeft{0%{transform-origin:left bottom;-webkit-transform:rotate(45deg);transform:rotate(45deg);opacity:0}0%,to{-webkit-transform-origin:left bottom}to{transform-origin:left bottom;-webkit-transform:none;transform:none;opacity:1}}.rotateInUpLeft{-webkit-animation-name:rotateInUpLeft;animation-name:rotateInUpLeft}@-webkit-keyframes rotateInUpRight{0%{transform-origin:right bottom;-webkit-transform:rotate(-90deg);transform:rotate(-90deg);opacity:0}0%,to{-webkit-transform-origin:right bottom}to{transform-origin:right bottom;-webkit-transform:none;transform:none;opacity:1}}@keyframes rotateInUpRight{0%{transform-origin:right bottom;-webkit-transform:rotate(-90deg);transform:rotate(-90deg);opacity:0}0%,to{-webkit-transform-origin:right bottom}to{transform-origin:right bottom;-webkit-transform:none;transform:none;opacity:1}}.rotateInUpRight{-webkit-animation-name:rotateInUpRight;animation-name:rotateInUpRight}@-webkit-keyframes rotateOut{0%{transform-origin:center;opacity:1}0%,to{-webkit-transform-origin:center}to{transform-origin:center;-webkit-transform:rotate(200deg);transform:rotate(200deg);opacity:0}}@keyframes rotateOut{0%{transform-origin:center;opacity:1}0%,to{-webkit-transform-origin:center}to{transform-origin:center;-webkit-transform:rotate(200deg);transform:rotate(200deg);opacity:0}}.rotateOut{-webkit-animation-name:rotateOut;animation-name:rotateOut}@-webkit-keyframes rotateOutDownLeft{0%{transform-origin:left bottom;opacity:1}0%,to{-webkit-transform-origin:left bottom}to{transform-origin:left bottom;-webkit-transform:rotate(45deg);transform:rotate(45deg);opacity:0}}@keyframes rotateOutDownLeft{0%{transform-origin:left bottom;opacity:1}0%,to{-webkit-transform-origin:left bottom}to{transform-origin:left bottom;-webkit-transform:rotate(45deg);transform:rotate(45deg);opacity:0}}.rotateOutDownLeft{-webkit-animation-name:rotateOutDownLeft;animation-name:rotateOutDownLeft}@-webkit-keyframes rotateOutDownRight{0%{transform-origin:right bottom;opacity:1}0%,to{-webkit-transform-origin:right bottom}to{transform-origin:right bottom;-webkit-transform:rotate(-45deg);transform:rotate(-45deg);opacity:0}}@keyframes rotateOutDownRight{0%{transform-origin:right bottom;opacity:1}0%,to{-webkit-transform-origin:right bottom}to{transform-origin:right bottom;-webkit-transform:rotate(-45deg);transform:rotate(-45deg);opacity:0}}.rotateOutDownRight{-webkit-animation-name:rotateOutDownRight;animation-name:rotateOutDownRight}@-webkit-keyframes rotateOutUpLeft{0%{transform-origin:left bottom;opacity:1}0%,to{-webkit-transform-origin:left bottom}to{transform-origin:left bottom;-webkit-transform:rotate(-45deg);transform:rotate(-45deg);opacity:0}}@keyframes rotateOutUpLeft{0%{transform-origin:left bottom;opacity:1}0%,to{-webkit-transform-origin:left bottom}to{transform-origin:left bottom;-webkit-transform:rotate(-45deg);transform:rotate(-45deg);opacity:0}}.rotateOutUpLeft{-webkit-animation-name:rotateOutUpLeft;animation-name:rotateOutUpLeft}@-webkit-keyframes rotateOutUpRight{0%{transform-origin:right bottom;opacity:1}0%,to{-webkit-transform-origin:right bottom}to{transform-origin:right bottom;-webkit-transform:rotate(90deg);transform:rotate(90deg);opacity:0}}@keyframes rotateOutUpRight{0%{transform-origin:right bottom;opacity:1}0%,to{-webkit-transform-origin:right bottom}to{transform-origin:right bottom;-webkit-transform:rotate(90deg);transform:rotate(90deg);opacity:0}}.rotateOutUpRight{-webkit-animation-name:rotateOutUpRight;animation-name:rotateOutUpRight}@-webkit-keyframes hinge{0%{transform-origin:top left}0%,20%,60%{-webkit-transform-origin:top left;-webkit-animation-timing-function:ease-in-out;animation-timing-function:ease-in-out}20%,60%{-webkit-transform:rotate(80deg);transform:rotate(80deg);transform-origin:top left}40%,80%{-webkit-transform:rotate(60deg);transform:rotate(60deg);-webkit-transform-origin:top left;transform-origin:top left;-webkit-animation-timing-function:ease-in-out;animation-timing-function:ease-in-out;opacity:1}to{-webkit-transform:translate3d(0,700px,0);transform:translate3d(0,700px,0);opacity:0}}@keyframes hinge{0%{transform-origin:top left}0%,20%,60%{-webkit-transform-origin:top left;-webkit-animation-timing-function:ease-in-out;animation-timing-function:ease-in-out}20%,60%{-webkit-transform:rotate(80deg);transform:rotate(80deg);transform-origin:top left}40%,80%{-webkit-transform:rotate(60deg);transform:rotate(60deg);-webkit-transform-origin:top left;transform-origin:top left;-webkit-animation-timing-function:ease-in-out;animation-timing-function:ease-in-out;opacity:1}to{-webkit-transform:translate3d(0,700px,0);transform:translate3d(0,700px,0);opacity:0}}.hinge{-webkit-animation-name:hinge;animation-name:hinge}@-webkit-keyframes rollIn{0%{opacity:0;-webkit-transform:translate3d(-100%,0,0) rotate(-120deg);transform:translate3d(-100%,0,0) rotate(-120deg)}to{opacity:1;-webkit-transform:none;transform:none}}@keyframes rollIn{0%{opacity:0;-webkit-transform:translate3d(-100%,0,0) rotate(-120deg);transform:translate3d(-100%,0,0) rotate(-120deg)}to{opacity:1;-webkit-transform:none;transform:none}}.rollIn{-webkit-animation-name:rollIn;animation-name:rollIn}@-webkit-keyframes rollOut{0%{opacity:1}to{opacity:0;-webkit-transform:translate3d(100%,0,0) rotate(120deg);transform:translate3d(100%,0,0) rotate(120deg)}}@keyframes rollOut{0%{opacity:1}to{opacity:0;-webkit-transform:translate3d(100%,0,0) rotate(120deg);transform:translate3d(100%,0,0) rotate(120deg)}}.rollOut{-webkit-animation-name:rollOut;animation-name:rollOut}@-webkit-keyframes zoomIn{0%{opacity:0;-webkit-transform:scale3d(.3,.3,.3);transform:scale3d(.3,.3,.3)}50%{opacity:1}}@keyframes zoomIn{0%{opacity:0;-webkit-transform:scale3d(.3,.3,.3);transform:scale3d(.3,.3,.3)}50%{opacity:1}}.zoomIn{-webkit-animation-name:zoomIn;animation-name:zoomIn}@-webkit-keyframes zoomInDown{0%{opacity:0;-webkit-transform:scale3d(.1,.1,.1) translate3d(0,-1000px,0);transform:scale3d(.1,.1,.1) translate3d(0,-1000px,0);-webkit-animation-timing-function:cubic-bezier(.55,.055,.675,.19);animation-timing-function:cubic-bezier(.55,.055,.675,.19)}60%{opacity:1;-webkit-transform:scale3d(.475,.475,.475) translate3d(0,60px,0);transform:scale3d(.475,.475,.475) translate3d(0,60px,0);-webkit-animation-timing-function:cubic-bezier(.175,.885,.32,1);animation-timing-function:cubic-bezier(.175,.885,.32,1)}}@keyframes zoomInDown{0%{opacity:0;-webkit-transform:scale3d(.1,.1,.1) translate3d(0,-1000px,0);transform:scale3d(.1,.1,.1) translate3d(0,-1000px,0);-webkit-animation-timing-function:cubic-bezier(.55,.055,.675,.19);animation-timing-function:cubic-bezier(.55,.055,.675,.19)}60%{opacity:1;-webkit-transform:scale3d(.475,.475,.475) translate3d(0,60px,0);transform:scale3d(.475,.475,.475) translate3d(0,60px,0);-webkit-animation-timing-function:cubic-bezier(.175,.885,.32,1);animation-timing-function:cubic-bezier(.175,.885,.32,1)}}.zoomInDown{-webkit-animation-name:zoomInDown;animation-name:zoomInDown}@-webkit-keyframes zoomInLeft{0%{opacity:0;-webkit-transform:scale3d(.1,.1,.1) translate3d(-1000px,0,0);transform:scale3d(.1,.1,.1) translate3d(-1000px,0,0);-webkit-animation-timing-function:cubic-bezier(.55,.055,.675,.19);animation-timing-function:cubic-bezier(.55,.055,.675,.19)}60%{opacity:1;-webkit-transform:scale3d(.475,.475,.475) translate3d(10px,0,0);transform:scale3d(.475,.475,.475) translate3d(10px,0,0);-webkit-animation-timing-function:cubic-bezier(.175,.885,.32,1);animation-timing-function:cubic-bezier(.175,.885,.32,1)}}@keyframes zoomInLeft{0%{opacity:0;-webkit-transform:scale3d(.1,.1,.1) translate3d(-1000px,0,0);transform:scale3d(.1,.1,.1) translate3d(-1000px,0,0);-webkit-animation-timing-function:cubic-bezier(.55,.055,.675,.19);animation-timing-function:cubic-bezier(.55,.055,.675,.19)}60%{opacity:1;-webkit-transform:scale3d(.475,.475,.475) translate3d(10px,0,0);transform:scale3d(.475,.475,.475) translate3d(10px,0,0);-webkit-animation-timing-function:cubic-bezier(.175,.885,.32,1);animation-timing-function:cubic-bezier(.175,.885,.32,1)}}.zoomInLeft{-webkit-animation-name:zoomInLeft;animation-name:zoomInLeft}@-webkit-keyframes zoomInRight{0%{opacity:0;-webkit-transform:scale3d(.1,.1,.1) translate3d(1000px,0,0);transform:scale3d(.1,.1,.1) translate3d(1000px,0,0);-webkit-animation-timing-function:cubic-bezier(.55,.055,.675,.19);animation-timing-function:cubic-bezier(.55,.055,.675,.19)}60%{opacity:1;-webkit-transform:scale3d(.475,.475,.475) translate3d(-10px,0,0);transform:scale3d(.475,.475,.475) translate3d(-10px,0,0);-webkit-animation-timing-function:cubic-bezier(.175,.885,.32,1);animation-timing-function:cubic-bezier(.175,.885,.32,1)}}@keyframes zoomInRight{0%{opacity:0;-webkit-transform:scale3d(.1,.1,.1) translate3d(1000px,0,0);transform:scale3d(.1,.1,.1) translate3d(1000px,0,0);-webkit-animation-timing-function:cubic-bezier(.55,.055,.675,.19);animation-timing-function:cubic-bezier(.55,.055,.675,.19)}60%{opacity:1;-webkit-transform:scale3d(.475,.475,.475) translate3d(-10px,0,0);transform:scale3d(.475,.475,.475) translate3d(-10px,0,0);-webkit-animation-timing-function:cubic-bezier(.175,.885,.32,1);animation-timing-function:cubic-bezier(.175,.885,.32,1)}}.zoomInRight{-webkit-animation-name:zoomInRight;animation-name:zoomInRight}@-webkit-keyframes zoomInUp{0%{opacity:0;-webkit-transform:scale3d(.1,.1,.1) translate3d(0,1000px,0);transform:scale3d(.1,.1,.1) translate3d(0,1000px,0);-webkit-animation-timing-function:cubic-bezier(.55,.055,.675,.19);animation-timing-function:cubic-bezier(.55,.055,.675,.19)}60%{opacity:1;-webkit-transform:scale3d(.475,.475,.475) translate3d(0,-60px,0);transform:scale3d(.475,.475,.475) translate3d(0,-60px,0);-webkit-animation-timing-function:cubic-bezier(.175,.885,.32,1);animation-timing-function:cubic-bezier(.175,.885,.32,1)}}@keyframes zoomInUp{0%{opacity:0;-webkit-transform:scale3d(.1,.1,.1) translate3d(0,1000px,0);transform:scale3d(.1,.1,.1) translate3d(0,1000px,0);-webkit-animation-timing-function:cubic-bezier(.55,.055,.675,.19);animation-timing-function:cubic-bezier(.55,.055,.675,.19)}60%{opacity:1;-webkit-transform:scale3d(.475,.475,.475) translate3d(0,-60px,0);transform:scale3d(.475,.475,.475) translate3d(0,-60px,0);-webkit-animation-timing-function:cubic-bezier(.175,.885,.32,1);animation-timing-function:cubic-bezier(.175,.885,.32,1)}}.zoomInUp{-webkit-animation-name:zoomInUp;animation-name:zoomInUp}@-webkit-keyframes zoomOut{0%{opacity:1}50%{-webkit-transform:scale3d(.3,.3,.3);transform:scale3d(.3,.3,.3)}50%,to{opacity:0}}@keyframes zoomOut{0%{opacity:1}50%{-webkit-transform:scale3d(.3,.3,.3);transform:scale3d(.3,.3,.3)}50%,to{opacity:0}}.zoomOut{-webkit-animation-name:zoomOut;animation-name:zoomOut}@-webkit-keyframes zoomOutDown{40%{opacity:1;-webkit-transform:scale3d(.475,.475,.475) translate3d(0,-60px,0);transform:scale3d(.475,.475,.475) translate3d(0,-60px,0);-webkit-animation-timing-function:cubic-bezier(.55,.055,.675,.19);animation-timing-function:cubic-bezier(.55,.055,.675,.19)}to{opacity:0;-webkit-transform:scale3d(.1,.1,.1) translate3d(0,2000px,0);transform:scale3d(.1,.1,.1) translate3d(0,2000px,0);-webkit-transform-origin:center bottom;transform-origin:center bottom;-webkit-animation-timing-function:cubic-bezier(.175,.885,.32,1);animation-timing-function:cubic-bezier(.175,.885,.32,1)}}@keyframes zoomOutDown{40%{opacity:1;-webkit-transform:scale3d(.475,.475,.475) translate3d(0,-60px,0);transform:scale3d(.475,.475,.475) translate3d(0,-60px,0);-webkit-animation-timing-function:cubic-bezier(.55,.055,.675,.19);animation-timing-function:cubic-bezier(.55,.055,.675,.19)}to{opacity:0;-webkit-transform:scale3d(.1,.1,.1) translate3d(0,2000px,0);transform:scale3d(.1,.1,.1) translate3d(0,2000px,0);-webkit-transform-origin:center bottom;transform-origin:center bottom;-webkit-animation-timing-function:cubic-bezier(.175,.885,.32,1);animation-timing-function:cubic-bezier(.175,.885,.32,1)}}.zoomOutDown{-webkit-animation-name:zoomOutDown;animation-name:zoomOutDown}@-webkit-keyframes zoomOutLeft{40%{opacity:1;-webkit-transform:scale3d(.475,.475,.475) translate3d(42px,0,0);transform:scale3d(.475,.475,.475) translate3d(42px,0,0)}to{opacity:0;-webkit-transform:scale(.1) translate3d(-2000px,0,0);transform:scale(.1) translate3d(-2000px,0,0);-webkit-transform-origin:left center;transform-origin:left center}}@keyframes zoomOutLeft{40%{opacity:1;-webkit-transform:scale3d(.475,.475,.475) translate3d(42px,0,0);transform:scale3d(.475,.475,.475) translate3d(42px,0,0)}to{opacity:0;-webkit-transform:scale(.1) translate3d(-2000px,0,0);transform:scale(.1) translate3d(-2000px,0,0);-webkit-transform-origin:left center;transform-origin:left center}}.zoomOutLeft{-webkit-animation-name:zoomOutLeft;animation-name:zoomOutLeft}@-webkit-keyframes zoomOutRight{40%{opacity:1;-webkit-transform:scale3d(.475,.475,.475) translate3d(-42px,0,0);transform:scale3d(.475,.475,.475) translate3d(-42px,0,0)}to{opacity:0;-webkit-transform:scale(.1) translate3d(2000px,0,0);transform:scale(.1) translate3d(2000px,0,0);-webkit-transform-origin:right center;transform-origin:right center}}@keyframes zoomOutRight{40%{opacity:1;-webkit-transform:scale3d(.475,.475,.475) translate3d(-42px,0,0);transform:scale3d(.475,.475,.475) translate3d(-42px,0,0)}to{opacity:0;-webkit-transform:scale(.1) translate3d(2000px,0,0);transform:scale(.1) translate3d(2000px,0,0);-webkit-transform-origin:right center;transform-origin:right center}}.zoomOutRight{-webkit-animation-name:zoomOutRight;animation-name:zoomOutRight}@-webkit-keyframes zoomOutUp{40%{opacity:1;-webkit-transform:scale3d(.475,.475,.475) translate3d(0,60px,0);transform:scale3d(.475,.475,.475) translate3d(0,60px,0);-webkit-animation-timing-function:cubic-bezier(.55,.055,.675,.19);animation-timing-function:cubic-bezier(.55,.055,.675,.19)}to{opacity:0;-webkit-transform:scale3d(.1,.1,.1) translate3d(0,-2000px,0);transform:scale3d(.1,.1,.1) translate3d(0,-2000px,0);-webkit-transform-origin:center bottom;transform-origin:center bottom;-webkit-animation-timing-function:cubic-bezier(.175,.885,.32,1);animation-timing-function:cubic-bezier(.175,.885,.32,1)}}@keyframes zoomOutUp{40%{opacity:1;-webkit-transform:scale3d(.475,.475,.475) translate3d(0,60px,0);transform:scale3d(.475,.475,.475) translate3d(0,60px,0);-webkit-animation-timing-function:cubic-bezier(.55,.055,.675,.19);animation-timing-function:cubic-bezier(.55,.055,.675,.19)}to{opacity:0;-webkit-transform:scale3d(.1,.1,.1) translate3d(0,-2000px,0);transform:scale3d(.1,.1,.1) translate3d(0,-2000px,0);-webkit-transform-origin:center bottom;transform-origin:center bottom;-webkit-animation-timing-function:cubic-bezier(.175,.885,.32,1);animation-timing-function:cubic-bezier(.175,.885,.32,1)}}.zoomOutUp{-webkit-animation-name:zoomOutUp;animation-name:zoomOutUp}@-webkit-keyframes slideInDown{0%{-webkit-transform:translate3d(0,-100%,0);transform:translate3d(0,-100%,0);visibility:visible}to{-webkit-transform:translateZ(0);transform:translateZ(0)}}@keyframes slideInDown{0%{-webkit-transform:translate3d(0,-100%,0);transform:translate3d(0,-100%,0);visibility:visible}to{-webkit-transform:translateZ(0);transform:translateZ(0)}}.slideInDown{-webkit-animation-name:slideInDown;animation-name:slideInDown}@-webkit-keyframes slideInLeft{0%{-webkit-transform:translate3d(-100%,0,0);transform:translate3d(-100%,0,0);visibility:visible}to{-webkit-transform:translateZ(0);transform:translateZ(0)}}@keyframes slideInLeft{0%{-webkit-transform:translate3d(-100%,0,0);transform:translate3d(-100%,0,0);visibility:visible}to{-webkit-transform:translateZ(0);transform:translateZ(0)}}.slideInLeft{-webkit-animation-name:slideInLeft;animation-name:slideInLeft}@-webkit-keyframes slideInRight{0%{-webkit-transform:translate3d(100%,0,0);transform:translate3d(100%,0,0);visibility:visible}to{-webkit-transform:translateZ(0);transform:translateZ(0)}}@keyframes slideInRight{0%{-webkit-transform:translate3d(100%,0,0);transform:translate3d(100%,0,0);visibility:visible}to{-webkit-transform:translateZ(0);transform:translateZ(0)}}.slideInRight{-webkit-animation-name:slideInRight;animation-name:slideInRight}@-webkit-keyframes slideInUp{0%{-webkit-transform:translate3d(0,100%,0);transform:translate3d(0,100%,0);visibility:visible}to{-webkit-transform:translateZ(0);transform:translateZ(0)}}@keyframes slideInUp{0%{-webkit-transform:translate3d(0,100%,0);transform:translate3d(0,100%,0);visibility:visible}to{-webkit-transform:translateZ(0);transform:translateZ(0)}}.slideInUp{-webkit-animation-name:slideInUp;animation-name:slideInUp}@-webkit-keyframes slideOutDown{0%{-webkit-transform:translateZ(0);transform:translateZ(0)}to{visibility:hidden;-webkit-transform:translate3d(0,100%,0);transform:translate3d(0,100%,0)}}@keyframes slideOutDown{0%{-webkit-transform:translateZ(0);transform:translateZ(0)}to{visibility:hidden;-webkit-transform:translate3d(0,100%,0);transform:translate3d(0,100%,0)}}.slideOutDown{-webkit-animation-name:slideOutDown;animation-name:slideOutDown}@-webkit-keyframes slideOutLeft{0%{-webkit-transform:translateZ(0);transform:translateZ(0)}to{visibility:hidden;-webkit-transform:translate3d(-100%,0,0);transform:translate3d(-100%,0,0)}}@keyframes slideOutLeft{0%{-webkit-transform:translateZ(0);transform:translateZ(0)}to{visibility:hidden;-webkit-transform:translate3d(-100%,0,0);transform:translate3d(-100%,0,0)}}.slideOutLeft{-webkit-animation-name:slideOutLeft;animation-name:slideOutLeft}@-webkit-keyframes slideOutRight{0%{-webkit-transform:translateZ(0);transform:translateZ(0)}to{visibility:hidden;-webkit-transform:translate3d(100%,0,0);transform:translate3d(100%,0,0)}}@keyframes slideOutRight{0%{-webkit-transform:translateZ(0);transform:translateZ(0)}to{visibility:hidden;-webkit-transform:translate3d(100%,0,0);transform:translate3d(100%,0,0)}}.slideOutRight{-webkit-animation-name:slideOutRight;animation-name:slideOutRight}@-webkit-keyframes slideOutUp{0%{-webkit-transform:translateZ(0);transform:translateZ(0)}to{visibility:hidden;-webkit-transform:translate3d(0,-100%,0);transform:translate3d(0,-100%,0)}}@keyframes slideOutUp{0%{-webkit-transform:translateZ(0);transform:translateZ(0)}to{visibility:hidden;-webkit-transform:translate3d(0,-100%,0);transform:translate3d(0,-100%,0)}}.slideOutUp{-webkit-animation-name:slideOutUp;animation-name:slideOutUp} \ No newline at end of file
diff --git a/vendor/gitignore/Actionscript.gitignore b/vendor/gitignore/Actionscript.gitignore
new file mode 100644
index 00000000000..11e612e9853
--- /dev/null
+++ b/vendor/gitignore/Actionscript.gitignore
@@ -0,0 +1,19 @@
+# Build and Release Folders
+bin/
+bin-debug/
+bin-release/
+[Oo]bj/ # FlashDevelop obj
+[Bb]in/ # FlashDevelop bin
+
+# Other files and folders
+.settings/
+
+# Executables
+*.swf
+*.air
+*.ipa
+*.apk
+
+# Project files, i.e. `.project`, `.actionScriptProperties` and `.flexProperties`
+# should NOT be excluded as they contain compiler settings and other important
+# information for Eclipse / Flash Builder.
diff --git a/vendor/gitignore/Ada.gitignore b/vendor/gitignore/Ada.gitignore
new file mode 100644
index 00000000000..b4d703968a4
--- /dev/null
+++ b/vendor/gitignore/Ada.gitignore
@@ -0,0 +1,5 @@
+# Object file
+*.o
+
+# Ada Library Information
+*.ali
diff --git a/vendor/gitignore/Agda.gitignore b/vendor/gitignore/Agda.gitignore
new file mode 100644
index 00000000000..171a38976c1
--- /dev/null
+++ b/vendor/gitignore/Agda.gitignore
@@ -0,0 +1 @@
+*.agdai
diff --git a/vendor/gitignore/Android.gitignore b/vendor/gitignore/Android.gitignore
new file mode 100644
index 00000000000..a8368751267
--- /dev/null
+++ b/vendor/gitignore/Android.gitignore
@@ -0,0 +1,39 @@
+# Built application files
+*.apk
+*.ap_
+
+# Files for the Dalvik VM
+*.dex
+
+# Java class files
+*.class
+
+# Generated files
+bin/
+gen/
+out/
+
+# Gradle files
+.gradle/
+build/
+
+# Local configuration file (sdk path, etc)
+local.properties
+
+# Proguard folder generated by Eclipse
+proguard/
+
+# Log Files
+*.log
+
+# Android Studio Navigation editor temp files
+.navigation/
+
+# Android Studio captures folder
+captures/
+
+# Intellij
+*.iml
+
+# Keystore files
+*.jks
diff --git a/vendor/gitignore/AppEngine.gitignore b/vendor/gitignore/AppEngine.gitignore
new file mode 100644
index 00000000000..62273454531
--- /dev/null
+++ b/vendor/gitignore/AppEngine.gitignore
@@ -0,0 +1,2 @@
+# Google App Engine generated folder
+appengine-generated/
diff --git a/vendor/gitignore/AppceleratorTitanium.gitignore b/vendor/gitignore/AppceleratorTitanium.gitignore
new file mode 100644
index 00000000000..3abea559761
--- /dev/null
+++ b/vendor/gitignore/AppceleratorTitanium.gitignore
@@ -0,0 +1,3 @@
+# Build folder and log file
+build/
+build.log
diff --git a/vendor/gitignore/ArchLinuxPackages.gitignore b/vendor/gitignore/ArchLinuxPackages.gitignore
new file mode 100644
index 00000000000..b73905529f2
--- /dev/null
+++ b/vendor/gitignore/ArchLinuxPackages.gitignore
@@ -0,0 +1,13 @@
+*.tar
+*.tar.*
+*.jar
+*.exe
+*.msi
+*.zip
+*.tgz
+*.log
+*.log.*
+*.sig
+
+pkg/
+src/
diff --git a/vendor/gitignore/Autotools.gitignore b/vendor/gitignore/Autotools.gitignore
new file mode 100644
index 00000000000..1e9158e2a85
--- /dev/null
+++ b/vendor/gitignore/Autotools.gitignore
@@ -0,0 +1,18 @@
+# http://www.gnu.org/software/automake
+
+Makefile.in
+
+# http://www.gnu.org/software/autoconf
+
+/autom4te.cache
+/autoscan.log
+/autoscan-*.log
+/aclocal.m4
+/compile
+/config.h.in
+/configure
+/configure.scan
+/depcomp
+/install-sh
+/missing
+/stamp-h1
diff --git a/vendor/gitignore/C++.gitignore b/vendor/gitignore/C++.gitignore
new file mode 100644
index 00000000000..b8bd0267bdf
--- /dev/null
+++ b/vendor/gitignore/C++.gitignore
@@ -0,0 +1,28 @@
+# Compiled Object files
+*.slo
+*.lo
+*.o
+*.obj
+
+# Precompiled Headers
+*.gch
+*.pch
+
+# Compiled Dynamic libraries
+*.so
+*.dylib
+*.dll
+
+# Fortran module files
+*.mod
+
+# Compiled Static libraries
+*.lai
+*.la
+*.a
+*.lib
+
+# Executables
+*.exe
+*.out
+*.app
diff --git a/vendor/gitignore/C.gitignore b/vendor/gitignore/C.gitignore
new file mode 100644
index 00000000000..f805e810e5c
--- /dev/null
+++ b/vendor/gitignore/C.gitignore
@@ -0,0 +1,33 @@
+# Object files
+*.o
+*.ko
+*.obj
+*.elf
+
+# Precompiled Headers
+*.gch
+*.pch
+
+# Libraries
+*.lib
+*.a
+*.la
+*.lo
+
+# Shared objects (inc. Windows DLLs)
+*.dll
+*.so
+*.so.*
+*.dylib
+
+# Executables
+*.exe
+*.out
+*.app
+*.i*86
+*.x86_64
+*.hex
+
+# Debug files
+*.dSYM/
+*.su
diff --git a/vendor/gitignore/CFWheels.gitignore b/vendor/gitignore/CFWheels.gitignore
new file mode 100644
index 00000000000..f2fec34ff89
--- /dev/null
+++ b/vendor/gitignore/CFWheels.gitignore
@@ -0,0 +1,12 @@
+# unpacked plugin folders
+plugins/**/*
+
+# files directory where uploads go
+files
+
+# DBMigrate plugin: generated SQL
+db/sql
+
+# AssetBundler plugin: generated bundles
+javascripts/bundles
+stylesheets/bundles
diff --git a/vendor/gitignore/CMake.gitignore b/vendor/gitignore/CMake.gitignore
new file mode 100644
index 00000000000..b558e9afa6d
--- /dev/null
+++ b/vendor/gitignore/CMake.gitignore
@@ -0,0 +1,6 @@
+CMakeCache.txt
+CMakeFiles
+CMakeScripts
+Makefile
+cmake_install.cmake
+install_manifest.txt
diff --git a/vendor/gitignore/CUDA.gitignore b/vendor/gitignore/CUDA.gitignore
new file mode 100644
index 00000000000..cb385db83fe
--- /dev/null
+++ b/vendor/gitignore/CUDA.gitignore
@@ -0,0 +1,6 @@
+*.i
+*.ii
+*.gpu
+*.ptx
+*.cubin
+*.fatbin
diff --git a/vendor/gitignore/CakePHP.gitignore b/vendor/gitignore/CakePHP.gitignore
new file mode 100644
index 00000000000..c6597e4eabf
--- /dev/null
+++ b/vendor/gitignore/CakePHP.gitignore
@@ -0,0 +1,25 @@
+# CakePHP 3
+
+/vendor/*
+/config/app.php
+
+/tmp/cache/models/*
+!/tmp/cache/models/empty
+/tmp/cache/persistent/*
+!/tmp/cache/persistent/empty
+/tmp/cache/views/*
+!/tmp/cache/views/empty
+/tmp/sessions/*
+!/tmp/sessions/empty
+/tmp/tests/*
+!/tmp/tests/empty
+
+/logs/*
+!/logs/empty
+
+# CakePHP 2
+
+/app/tmp/*
+/app/Config/core.php
+/app/Config/database.php
+/vendors/*
diff --git a/vendor/gitignore/ChefCookbook.gitignore b/vendor/gitignore/ChefCookbook.gitignore
new file mode 100644
index 00000000000..5ee7b7a9a18
--- /dev/null
+++ b/vendor/gitignore/ChefCookbook.gitignore
@@ -0,0 +1,9 @@
+.vagrant
+/cookbooks
+
+# Bundler
+bin/*
+.bundle/*
+
+.kitchen/
+.kitchen.local.yml
diff --git a/vendor/gitignore/Clojure.gitignore b/vendor/gitignore/Clojure.gitignore
new file mode 120000
index 00000000000..7657a270c45
--- /dev/null
+++ b/vendor/gitignore/Clojure.gitignore
@@ -0,0 +1 @@
+Leiningen.gitignore \ No newline at end of file
diff --git a/vendor/gitignore/CodeIgniter.gitignore b/vendor/gitignore/CodeIgniter.gitignore
new file mode 100644
index 00000000000..0f77d9e1d17
--- /dev/null
+++ b/vendor/gitignore/CodeIgniter.gitignore
@@ -0,0 +1,6 @@
+*/config/development
+*/logs/log-*.php
+!*/logs/index.html
+*/cache/*
+!*/cache/index.html
+!*/cache/.htaccess
diff --git a/vendor/gitignore/CommonLisp.gitignore b/vendor/gitignore/CommonLisp.gitignore
new file mode 100644
index 00000000000..4806e580b60
--- /dev/null
+++ b/vendor/gitignore/CommonLisp.gitignore
@@ -0,0 +1,3 @@
+*.FASL
+*.fasl
+*.lisp-temp
diff --git a/vendor/gitignore/Composer.gitignore b/vendor/gitignore/Composer.gitignore
new file mode 100644
index 00000000000..c4222678424
--- /dev/null
+++ b/vendor/gitignore/Composer.gitignore
@@ -0,0 +1,6 @@
+composer.phar
+/vendor/
+
+# Commit your application's lock file http://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file
+# You may choose to ignore a library lock file http://getcomposer.org/doc/02-libraries.md#lock-file
+# composer.lock
diff --git a/vendor/gitignore/Concrete5.gitignore b/vendor/gitignore/Concrete5.gitignore
new file mode 100644
index 00000000000..1fe53611e5d
--- /dev/null
+++ b/vendor/gitignore/Concrete5.gitignore
@@ -0,0 +1,4 @@
+config/site.php
+files/cache/*
+files/tmp/*
+.htaccess
diff --git a/vendor/gitignore/Coq.gitignore b/vendor/gitignore/Coq.gitignore
new file mode 100644
index 00000000000..d3083b3a605
--- /dev/null
+++ b/vendor/gitignore/Coq.gitignore
@@ -0,0 +1,3 @@
+*.vo
+*.glob
+*.v.d
diff --git a/vendor/gitignore/CraftCMS.gitignore b/vendor/gitignore/CraftCMS.gitignore
new file mode 100644
index 00000000000..a70d4772c46
--- /dev/null
+++ b/vendor/gitignore/CraftCMS.gitignore
@@ -0,0 +1,3 @@
+# Craft Storage (cache) [http://buildwithcraft.com/help/craft-storage-gitignore]
+/craft/storage/*
+!/craft/storage/logo/* \ No newline at end of file
diff --git a/vendor/gitignore/D.gitignore b/vendor/gitignore/D.gitignore
new file mode 100644
index 00000000000..b4433f8a512
--- /dev/null
+++ b/vendor/gitignore/D.gitignore
@@ -0,0 +1,20 @@
+# Compiled Object files
+*.o
+*.obj
+
+# Compiled Dynamic libraries
+*.so
+*.dylib
+*.dll
+
+# Compiled Static libraries
+*.a
+*.lib
+
+# Executables
+*.exe
+
+# DUB
+.dub
+docs.json
+__dummy.html
diff --git a/vendor/gitignore/DM.gitignore b/vendor/gitignore/DM.gitignore
new file mode 100644
index 00000000000..ba5abdab836
--- /dev/null
+++ b/vendor/gitignore/DM.gitignore
@@ -0,0 +1,5 @@
+*.dmb
+*.rsc
+*.int
+*.lk
+*.zip
diff --git a/vendor/gitignore/Dart.gitignore b/vendor/gitignore/Dart.gitignore
new file mode 100644
index 00000000000..7c280441649
--- /dev/null
+++ b/vendor/gitignore/Dart.gitignore
@@ -0,0 +1,27 @@
+# See https://www.dartlang.org/tools/private-files.html
+
+# Files and directories created by pub
+.buildlog
+.packages
+.project
+.pub/
+build/
+**/packages/
+
+# Files created by dart2js
+# (Most Dart developers will use pub build to compile Dart, use/modify these
+# rules if you intend to use dart2js directly
+# Convention is to use extension '.dart.js' for Dart compiled to Javascript to
+# differentiate from explicit Javascript files)
+*.dart.js
+*.part.js
+*.js.deps
+*.js.map
+*.info.json
+
+# Directory created by dartdoc
+doc/api/
+
+# Don't commit pubspec lock file
+# (Library packages only! Remove pattern if developing an application package)
+pubspec.lock
diff --git a/vendor/gitignore/Delphi.gitignore b/vendor/gitignore/Delphi.gitignore
new file mode 100644
index 00000000000..19864c6bbef
--- /dev/null
+++ b/vendor/gitignore/Delphi.gitignore
@@ -0,0 +1,66 @@
+# Uncomment these types if you want even more clean repository. But be careful.
+# It can make harm to an existing project source. Read explanations below.
+#
+# Resource files are binaries containing manifest, project icon and version info.
+# They can not be viewed as text or compared by diff-tools. Consider replacing them with .rc files.
+#*.res
+#
+# Type library file (binary). In old Delphi versions it should be stored.
+# Since Delphi 2009 it is produced from .ridl file and can safely be ignored.
+#*.tlb
+#
+# Diagram Portfolio file. Used by the diagram editor up to Delphi 7.
+# Uncomment this if you are not using diagrams or use newer Delphi version.
+#*.ddp
+#
+# Visual LiveBindings file. Added in Delphi XE2.
+# Uncomment this if you are not using LiveBindings Designer.
+#*.vlb
+#
+# Deployment Manager configuration file for your project. Added in Delphi XE2.
+# Uncomment this if it is not mobile development and you do not use remote debug feature.
+#*.deployproj
+#
+# C++ object files produced when C/C++ Output file generation is configured.
+# Uncomment this if you are not using external objects (zlib library for example).
+#*.obj
+#
+
+# Delphi compiler-generated binaries (safe to delete)
+*.exe
+*.dll
+*.bpl
+*.bpi
+*.dcp
+*.so
+*.apk
+*.drc
+*.map
+*.dres
+*.rsm
+*.tds
+*.dcu
+*.lib
+*.a
+*.o
+*.ocx
+
+# Delphi autogenerated files (duplicated info)
+*.cfg
+*.hpp
+*Resource.rc
+
+# Delphi local files (user-specific info)
+*.local
+*.identcache
+*.projdata
+*.tvsconfig
+*.dsk
+
+# Delphi history and backups
+__history/
+__recovery/
+*.~*
+
+# Castalia statistics file (since XE7 Castalia is distributed with Delphi)
+*.stat
diff --git a/vendor/gitignore/Drupal.gitignore b/vendor/gitignore/Drupal.gitignore
new file mode 100644
index 00000000000..0d2fe537f46
--- /dev/null
+++ b/vendor/gitignore/Drupal.gitignore
@@ -0,0 +1,36 @@
+# Ignore configuration files that may contain sensitive information.
+sites/*/*settings*.php
+
+# Ignore paths that contain generated content.
+files/
+sites/*/files
+sites/*/private
+
+# Ignore default text files
+robots.txt
+/CHANGELOG.txt
+/COPYRIGHT.txt
+/INSTALL*.txt
+/LICENSE.txt
+/MAINTAINERS.txt
+/UPGRADE.txt
+/README.txt
+sites/README.txt
+sites/all/modules/README.txt
+sites/all/themes/README.txt
+
+# Ignore everything but the "sites" folder ( for non core developer )
+.htaccess
+web.config
+authorize.php
+cron.php
+index.php
+install.php
+update.php
+xmlrpc.php
+/includes
+/misc
+/modules
+/profiles
+/scripts
+/themes
diff --git a/vendor/gitignore/EPiServer.gitignore b/vendor/gitignore/EPiServer.gitignore
new file mode 100644
index 00000000000..97037de743e
--- /dev/null
+++ b/vendor/gitignore/EPiServer.gitignore
@@ -0,0 +1,4 @@
+######################
+## EPiServer Files
+######################
+*License.config
diff --git a/vendor/gitignore/Eagle.gitignore b/vendor/gitignore/Eagle.gitignore
new file mode 100644
index 00000000000..9ced1260266
--- /dev/null
+++ b/vendor/gitignore/Eagle.gitignore
@@ -0,0 +1,44 @@
+# Ignore list for Eagle, a PCB layout tool
+
+# Backup files
+*.s#?
+*.b#?
+*.l#?
+
+# Eagle project file
+# It contains a serial number and references to the file structure
+# on your computer.
+# comment the following line if you want to have your project file included.
+eagle.epf
+
+# Autorouter files
+*.pro
+*.job
+
+# CAM files
+*.$$$
+*.cmp
+*.ly2
+*.l15
+*.sol
+*.plc
+*.stc
+*.sts
+*.crc
+*.crs
+
+*.dri
+*.drl
+*.gpi
+*.pls
+
+*.drd
+*.drd.*
+
+*.info
+
+*.eps
+
+# file locks introduced since 7.x
+*.lck
+
diff --git a/vendor/gitignore/Elisp.gitignore b/vendor/gitignore/Elisp.gitignore
new file mode 100644
index 00000000000..9b4291b7fe8
--- /dev/null
+++ b/vendor/gitignore/Elisp.gitignore
@@ -0,0 +1,5 @@
+# Compiled
+*.elc
+
+# Packaging
+.cask
diff --git a/vendor/gitignore/Elixir.gitignore b/vendor/gitignore/Elixir.gitignore
new file mode 100644
index 00000000000..755b605549d
--- /dev/null
+++ b/vendor/gitignore/Elixir.gitignore
@@ -0,0 +1,5 @@
+/_build
+/cover
+/deps
+erl_crash.dump
+*.ez
diff --git a/vendor/gitignore/Elm.gitignore b/vendor/gitignore/Elm.gitignore
new file mode 100644
index 00000000000..a594364e2c0
--- /dev/null
+++ b/vendor/gitignore/Elm.gitignore
@@ -0,0 +1,4 @@
+# elm-package generated files
+elm-stuff/
+# elm-repl generated files
+repl-temp-*
diff --git a/vendor/gitignore/Erlang.gitignore b/vendor/gitignore/Erlang.gitignore
new file mode 100644
index 00000000000..8e46d5a07f8
--- /dev/null
+++ b/vendor/gitignore/Erlang.gitignore
@@ -0,0 +1,10 @@
+.eunit
+deps
+*.o
+*.beam
+*.plt
+erl_crash.dump
+ebin
+rel/example_project
+.concrete/DEV_MODE
+.rebar
diff --git a/vendor/gitignore/ExpressionEngine.gitignore b/vendor/gitignore/ExpressionEngine.gitignore
new file mode 100644
index 00000000000..314e4df123a
--- /dev/null
+++ b/vendor/gitignore/ExpressionEngine.gitignore
@@ -0,0 +1,19 @@
+.DS_Store
+
+# Images
+images/avatars/
+images/captchas/
+images/smileys/
+images/member_photos/
+images/signature_attachments/
+images/pm_attachments/
+
+# For security do not publish the following files
+system/expressionengine/config/database.php
+system/expressionengine/config/config.php
+
+# Caches
+sized/
+thumbs/
+_thumbs/
+*/expressionengine/cache/*
diff --git a/vendor/gitignore/ExtJs.gitignore b/vendor/gitignore/ExtJs.gitignore
new file mode 100644
index 00000000000..5ffc21546ec
--- /dev/null
+++ b/vendor/gitignore/ExtJs.gitignore
@@ -0,0 +1,4 @@
+.architect
+bootstrap.json
+build/
+ext/
diff --git a/vendor/gitignore/Fancy.gitignore b/vendor/gitignore/Fancy.gitignore
new file mode 100644
index 00000000000..70d6e631e55
--- /dev/null
+++ b/vendor/gitignore/Fancy.gitignore
@@ -0,0 +1,2 @@
+*.rbc
+*.fyc
diff --git a/vendor/gitignore/Finale.gitignore b/vendor/gitignore/Finale.gitignore
new file mode 100644
index 00000000000..7ef08e0c343
--- /dev/null
+++ b/vendor/gitignore/Finale.gitignore
@@ -0,0 +1,13 @@
+*.bak
+*.db
+*.avi
+*.pdf
+*.ps
+*.mid
+*.midi
+*.mp3
+*.aif
+*.wav
+# Some versions of Finale have a bug and randomly save extra copies of
+# the music source as "<Filename> copy.mus"
+*copy.mus
diff --git a/vendor/gitignore/ForceDotCom.gitignore b/vendor/gitignore/ForceDotCom.gitignore
new file mode 100644
index 00000000000..3933cd4dd50
--- /dev/null
+++ b/vendor/gitignore/ForceDotCom.gitignore
@@ -0,0 +1,4 @@
+.project
+.settings
+salesforce.schema
+Referenced Packages
diff --git a/vendor/gitignore/Fortran.gitignore b/vendor/gitignore/Fortran.gitignore
new file mode 120000
index 00000000000..5daba98a3e6
--- /dev/null
+++ b/vendor/gitignore/Fortran.gitignore
@@ -0,0 +1 @@
+C++.gitignore \ No newline at end of file
diff --git a/vendor/gitignore/FuelPHP.gitignore b/vendor/gitignore/FuelPHP.gitignore
new file mode 100644
index 00000000000..d69f71f4338
--- /dev/null
+++ b/vendor/gitignore/FuelPHP.gitignore
@@ -0,0 +1,21 @@
+# the composer package lock file and install directory
+# Commit your application's lock file http://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file
+# You may choose to ignore a library lock file http://getcomposer.org/doc/02-libraries.md#lock-file
+# /composer.lock
+/fuel/vendor
+
+# the fuelphp document
+/docs/
+
+# you may install these packages with `oil package`.
+# http://fuelphp.com/docs/packages/oil/package.html
+# /fuel/packages/auth/
+# /fuel/packages/email/
+# /fuel/packages/oil/
+# /fuel/packages/orm/
+# /fuel/packages/parser/
+
+# dynamically generated files
+/fuel/app/logs/*/*/*
+/fuel/app/cache/*/*
+/fuel/app/config/crypt.php
diff --git a/vendor/gitignore/GWT.gitignore b/vendor/gitignore/GWT.gitignore
new file mode 100644
index 00000000000..07704e54bbc
--- /dev/null
+++ b/vendor/gitignore/GWT.gitignore
@@ -0,0 +1,28 @@
+*.class
+
+# Package Files #
+*.jar
+*.war
+
+# gwt caches and compiled units #
+war/gwt_bree/
+gwt-unitCache/
+
+# boilerplate generated classes #
+.apt_generated/
+
+# more caches and things from deploy #
+war/WEB-INF/deploy/
+war/WEB-INF/classes/
+
+#compilation logs
+.gwt/
+
+#caching for already compiled files
+gwt-unitCache/
+
+#gwt junit compilation files
+www-test/
+
+#old GWT (1.5) created this dir
+.gwt-tmp/
diff --git a/vendor/gitignore/Gcov.gitignore b/vendor/gitignore/Gcov.gitignore
new file mode 100644
index 00000000000..a6451430e17
--- /dev/null
+++ b/vendor/gitignore/Gcov.gitignore
@@ -0,0 +1,5 @@
+# gcc coverage testing tool files
+
+*.gcno
+*.gcda
+*.gcov
diff --git a/vendor/gitignore/GitBook.gitignore b/vendor/gitignore/GitBook.gitignore
new file mode 100644
index 00000000000..4cb12d8db77
--- /dev/null
+++ b/vendor/gitignore/GitBook.gitignore
@@ -0,0 +1,16 @@
+# Node rules:
+## Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
+.grunt
+
+## Dependency directory
+## Commenting this out is preferred by some people, see
+## https://docs.npmjs.com/misc/faq#should-i-check-my-node_modules-folder-into-git
+node_modules
+
+# Book build output
+_book
+
+# eBook build output
+*.epub
+*.mobi
+*.pdf
diff --git a/vendor/gitignore/Global/Anjuta.gitignore b/vendor/gitignore/Global/Anjuta.gitignore
new file mode 100644
index 00000000000..20dd42c53e6
--- /dev/null
+++ b/vendor/gitignore/Global/Anjuta.gitignore
@@ -0,0 +1,3 @@
+# Local configuration folder and symbol database
+/.anjuta/
+/.anjuta_sym_db.db
diff --git a/vendor/gitignore/Global/Archives.gitignore b/vendor/gitignore/Global/Archives.gitignore
new file mode 100644
index 00000000000..e9eda68baf2
--- /dev/null
+++ b/vendor/gitignore/Global/Archives.gitignore
@@ -0,0 +1,27 @@
+# It's better to unpack these files and commit the raw source because
+# git has its own built in compression methods.
+*.7z
+*.jar
+*.rar
+*.zip
+*.gz
+*.bzip
+*.bz2
+*.xz
+*.lzma
+*.cab
+
+#packing-only formats
+*.iso
+*.tar
+
+#package management formats
+*.dmg
+*.xpi
+*.gem
+*.egg
+*.deb
+*.rpm
+*.msi
+*.msm
+*.msp
diff --git a/vendor/gitignore/Global/BricxCC.gitignore b/vendor/gitignore/Global/BricxCC.gitignore
new file mode 100644
index 00000000000..c1d16a46c98
--- /dev/null
+++ b/vendor/gitignore/Global/BricxCC.gitignore
@@ -0,0 +1,4 @@
+# Bricx Command Center IDE
+# http://bricxcc.sourceforge.net
+*.bak
+*.sym
diff --git a/vendor/gitignore/Global/CVS.gitignore b/vendor/gitignore/Global/CVS.gitignore
new file mode 100644
index 00000000000..1695352e146
--- /dev/null
+++ b/vendor/gitignore/Global/CVS.gitignore
@@ -0,0 +1,4 @@
+/CVS/*
+**/CVS/*
+.cvsignore
+*/.cvsignore
diff --git a/vendor/gitignore/Global/Calabash.gitignore b/vendor/gitignore/Global/Calabash.gitignore
new file mode 100644
index 00000000000..8a75b329dcd
--- /dev/null
+++ b/vendor/gitignore/Global/Calabash.gitignore
@@ -0,0 +1,10 @@
+# Calabash / Cucumber
+rerun/
+reports/
+screenshots/
+screenshot*.png
+test-servers/
+
+# bundler
+.bundle
+vendor
diff --git a/vendor/gitignore/Global/Cloud9.gitignore b/vendor/gitignore/Global/Cloud9.gitignore
new file mode 100644
index 00000000000..3f4384df508
--- /dev/null
+++ b/vendor/gitignore/Global/Cloud9.gitignore
@@ -0,0 +1,3 @@
+# Cloud9 IDE - http://c9.io
+.c9revisions
+.c9
diff --git a/vendor/gitignore/Global/CodeKit.gitignore b/vendor/gitignore/Global/CodeKit.gitignore
new file mode 100644
index 00000000000..bd9e67fcca2
--- /dev/null
+++ b/vendor/gitignore/Global/CodeKit.gitignore
@@ -0,0 +1,3 @@
+# General CodeKit files to ignore
+config.codekit
+/min
diff --git a/vendor/gitignore/Global/DartEditor.gitignore b/vendor/gitignore/Global/DartEditor.gitignore
new file mode 100644
index 00000000000..948920b420e
--- /dev/null
+++ b/vendor/gitignore/Global/DartEditor.gitignore
@@ -0,0 +1,2 @@
+.project
+.buildlog
diff --git a/vendor/gitignore/Global/Dreamweaver.gitignore b/vendor/gitignore/Global/Dreamweaver.gitignore
new file mode 100644
index 00000000000..0621a3d53b5
--- /dev/null
+++ b/vendor/gitignore/Global/Dreamweaver.gitignore
@@ -0,0 +1,7 @@
+# DW Dreamweaver added files
+_notes
+_compareTemp
+configs/
+dwsync.xml
+dw_php_codehinting.config
+*.mno
diff --git a/vendor/gitignore/Global/Dropbox.gitignore b/vendor/gitignore/Global/Dropbox.gitignore
new file mode 100644
index 00000000000..40f4a469d25
--- /dev/null
+++ b/vendor/gitignore/Global/Dropbox.gitignore
@@ -0,0 +1,4 @@
+# Dropbox settings and caches
+.dropbox
+.dropbox.attr
+.dropbox.cache
diff --git a/vendor/gitignore/Global/Eclipse.gitignore b/vendor/gitignore/Global/Eclipse.gitignore
new file mode 100644
index 00000000000..31c9fb31167
--- /dev/null
+++ b/vendor/gitignore/Global/Eclipse.gitignore
@@ -0,0 +1,51 @@
+
+.metadata
+bin/
+tmp/
+*.tmp
+*.bak
+*.swp
+*~.nib
+local.properties
+.settings/
+.loadpath
+.recommenders
+
+# Eclipse Core
+.project
+
+# External tool builders
+.externalToolBuilders/
+
+# Locally stored "Eclipse launch configurations"
+*.launch
+
+# PyDev specific (Python IDE for Eclipse)
+*.pydevproject
+
+# CDT-specific (C/C++ Development Tooling)
+.cproject
+
+# JDT-specific (Eclipse Java Development Tools)
+.classpath
+
+# Java annotation processor (APT)
+.factorypath
+
+# PDT-specific (PHP Development Tools)
+.buildpath
+
+# sbteclipse plugin
+.target
+
+# Tern plugin
+.tern-project
+
+# TeXlipse plugin
+.texlipse
+
+# STS (Spring Tool Suite)
+.springBeans
+
+# Code Recommenders
+.recommenders/
diff --git a/vendor/gitignore/Global/EiffelStudio.gitignore b/vendor/gitignore/Global/EiffelStudio.gitignore
new file mode 100644
index 00000000000..f41b4f70216
--- /dev/null
+++ b/vendor/gitignore/Global/EiffelStudio.gitignore
@@ -0,0 +1,2 @@
+# The compilation directory
+EIFGENs
diff --git a/vendor/gitignore/Global/Emacs.gitignore b/vendor/gitignore/Global/Emacs.gitignore
new file mode 100644
index 00000000000..0c96c9ad060
--- /dev/null
+++ b/vendor/gitignore/Global/Emacs.gitignore
@@ -0,0 +1,42 @@
+# -*- mode: gitignore; -*-
+*~
+\#*\#
+/.emacs.desktop
+/.emacs.desktop.lock
+*.elc
+auto-save-list
+tramp
+.\#*
+
+# Org-mode
+.org-id-locations
+*_archive
+
+# flymake-mode
+*_flymake.*
+
+# eshell files
+/eshell/history
+/eshell/lastdir
+
+# elpa packages
+/elpa/
+
+# reftex files
+*.rel
+
+# AUCTeX auto folder
+/auto/
+
+# cask packages
+.cask/
+dist/
+
+# Flycheck
+flycheck_*.el
+
+# server auth directory
+/server/
+
+# projectiles files
+.projectile \ No newline at end of file
diff --git a/vendor/gitignore/Global/Ensime.gitignore b/vendor/gitignore/Global/Ensime.gitignore
new file mode 100644
index 00000000000..f2daebb9f4b
--- /dev/null
+++ b/vendor/gitignore/Global/Ensime.gitignore
@@ -0,0 +1,4 @@
+# Ensime specific
+.ensime
+.ensime_cache/
+.ensime_lucene/
diff --git a/vendor/gitignore/Global/Espresso.gitignore b/vendor/gitignore/Global/Espresso.gitignore
new file mode 100644
index 00000000000..1234530b5b3
--- /dev/null
+++ b/vendor/gitignore/Global/Espresso.gitignore
@@ -0,0 +1 @@
+*.esproj
diff --git a/vendor/gitignore/Global/FlexBuilder.gitignore b/vendor/gitignore/Global/FlexBuilder.gitignore
new file mode 100644
index 00000000000..bbbfb91d9eb
--- /dev/null
+++ b/vendor/gitignore/Global/FlexBuilder.gitignore
@@ -0,0 +1,3 @@
+bin/
+bin-debug/
+bin-release/
diff --git a/vendor/gitignore/Global/GPG.gitignore b/vendor/gitignore/Global/GPG.gitignore
new file mode 100644
index 00000000000..7740a01538c
--- /dev/null
+++ b/vendor/gitignore/Global/GPG.gitignore
@@ -0,0 +1,2 @@
+secring.*
+
diff --git a/vendor/gitignore/Global/IPythonNotebook.gitignore b/vendor/gitignore/Global/IPythonNotebook.gitignore
new file mode 100644
index 00000000000..27c13510bf5
--- /dev/null
+++ b/vendor/gitignore/Global/IPythonNotebook.gitignore
@@ -0,0 +1,2 @@
+# Temporary data
+.ipynb_checkpoints/
diff --git a/vendor/gitignore/Global/JDeveloper.gitignore b/vendor/gitignore/Global/JDeveloper.gitignore
new file mode 100644
index 00000000000..5bba6f37733
--- /dev/null
+++ b/vendor/gitignore/Global/JDeveloper.gitignore
@@ -0,0 +1,13 @@
+# default application storage directory used by the IDE Performance Cache feature
+.data/
+
+# used for ADF styles caching
+temp/
+
+# default output directories
+classes/
+deploy/
+javadoc/
+
+# lock file, a part of Oracle Credential Store Framework
+cwallet.sso.lck \ No newline at end of file
diff --git a/vendor/gitignore/Global/JetBrains.gitignore b/vendor/gitignore/Global/JetBrains.gitignore
new file mode 100644
index 00000000000..ea83a5eb620
--- /dev/null
+++ b/vendor/gitignore/Global/JetBrains.gitignore
@@ -0,0 +1,44 @@
+# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm
+# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
+
+# User-specific stuff:
+.idea/workspace.xml
+.idea/tasks.xml
+.idea/dictionaries
+.idea/vcs.xml
+.idea/jsLibraryMappings.xml
+
+# Sensitive or high-churn files:
+.idea/dataSources.ids
+.idea/dataSources.xml
+.idea/dataSources.local.xml
+.idea/sqlDataSources.xml
+.idea/dynamic.xml
+.idea/uiDesigner.xml
+
+# Gradle:
+.idea/gradle.xml
+.idea/libraries
+
+# Mongo Explorer plugin:
+.idea/mongoSettings.xml
+
+## File-based project format:
+*.iws
+
+## Plugin-specific files:
+
+# IntelliJ
+/out/
+
+# mpeltonen/sbt-idea plugin
+.idea_modules/
+
+# JIRA plugin
+atlassian-ide-plugin.xml
+
+# Crashlytics plugin (for Android Studio and IntelliJ)
+com_crashlytics_export_strings.xml
+crashlytics.properties
+crashlytics-build.properties
+fabric.properties
diff --git a/vendor/gitignore/Global/KDevelop4.gitignore b/vendor/gitignore/Global/KDevelop4.gitignore
new file mode 100644
index 00000000000..7ac57b1add4
--- /dev/null
+++ b/vendor/gitignore/Global/KDevelop4.gitignore
@@ -0,0 +1,2 @@
+*.kdev4
+.kdev4/
diff --git a/vendor/gitignore/Global/Kate.gitignore b/vendor/gitignore/Global/Kate.gitignore
new file mode 100644
index 00000000000..7ff06ce5390
--- /dev/null
+++ b/vendor/gitignore/Global/Kate.gitignore
@@ -0,0 +1,3 @@
+# Swap Files #
+.*.kate-swp
+.swp.*
diff --git a/vendor/gitignore/Global/Lazarus.gitignore b/vendor/gitignore/Global/Lazarus.gitignore
new file mode 100644
index 00000000000..b32943f1c6e
--- /dev/null
+++ b/vendor/gitignore/Global/Lazarus.gitignore
@@ -0,0 +1,30 @@
+# Lazarus compiler-generated binaries (safe to delete)
+*.exe
+*.dll
+*.so
+*.dylib
+*.lrs
+*.res
+*.compiled
+*.dbg
+*.ppu
+*.o
+*.or
+*.a
+
+# Lazarus autogenerated files (duplicated info)
+*.rst
+*.rsj
+*.lrt
+
+# Lazarus local files (user-specific info)
+*.lps
+
+# Lazarus backups and unit output folders.
+# These can be changed by user in Lazarus/project options.
+backup/
+*.bak
+lib/
+
+# Application bundle for Mac OS
+*.app/
diff --git a/vendor/gitignore/Global/LibreOffice.gitignore b/vendor/gitignore/Global/LibreOffice.gitignore
new file mode 100644
index 00000000000..586beac91d3
--- /dev/null
+++ b/vendor/gitignore/Global/LibreOffice.gitignore
@@ -0,0 +1,2 @@
+# LibreOffice locks
+.~lock.*#
diff --git a/vendor/gitignore/Global/Linux.gitignore b/vendor/gitignore/Global/Linux.gitignore
new file mode 100644
index 00000000000..cc9586893b6
--- /dev/null
+++ b/vendor/gitignore/Global/Linux.gitignore
@@ -0,0 +1,10 @@
+*~
+
+# temporary files which can be created if a process still has a handle open of a deleted file
+.fuse_hidden*
+
+# KDE directory preferences
+.directory
+
+# Linux trash folder which might appear on any partition or disk
+.Trash-*
diff --git a/vendor/gitignore/Global/LyX.gitignore b/vendor/gitignore/Global/LyX.gitignore
new file mode 100644
index 00000000000..8efe0195cf3
--- /dev/null
+++ b/vendor/gitignore/Global/LyX.gitignore
@@ -0,0 +1,4 @@
+# Ignore LyX backup and autosave files
+# http://www.lyx.org/
+*.lyx~
+*.lyx#
diff --git a/vendor/gitignore/Global/Matlab.gitignore b/vendor/gitignore/Global/Matlab.gitignore
new file mode 100644
index 00000000000..32a5ad4c777
--- /dev/null
+++ b/vendor/gitignore/Global/Matlab.gitignore
@@ -0,0 +1,19 @@
+##---------------------------------------------------
+## Remove autosaves generated by the Matlab editor
+## We have git for backups!
+##---------------------------------------------------
+
+# Windows default autosave extension
+*.asv
+
+# OSX / *nix default autosave extension
+*.m~
+
+# Compiled MEX binaries (all platforms)
+*.mex*
+
+# Simulink Code Generation
+slprj/
+
+# Session info
+octave-workspace
diff --git a/vendor/gitignore/Global/Mercurial.gitignore b/vendor/gitignore/Global/Mercurial.gitignore
new file mode 100644
index 00000000000..e65d1137988
--- /dev/null
+++ b/vendor/gitignore/Global/Mercurial.gitignore
@@ -0,0 +1,6 @@
+.hg/
+.hgignore
+.hgsigs
+.hgsub
+.hgsubstate
+.hgtags
diff --git a/vendor/gitignore/Global/MicrosoftOffice.gitignore b/vendor/gitignore/Global/MicrosoftOffice.gitignore
new file mode 100644
index 00000000000..cb891745660
--- /dev/null
+++ b/vendor/gitignore/Global/MicrosoftOffice.gitignore
@@ -0,0 +1,16 @@
+*.tmp
+
+# Word temporary
+~$*.doc*
+
+# Excel temporary
+~$*.xls*
+
+# Excel Backup File
+*.xlk
+
+# PowerPoint temporary
+~$*.ppt*
+
+# Visio autosave temporary files
+*.~vsdx
diff --git a/vendor/gitignore/Global/ModelSim.gitignore b/vendor/gitignore/Global/ModelSim.gitignore
new file mode 100644
index 00000000000..46592b86430
--- /dev/null
+++ b/vendor/gitignore/Global/ModelSim.gitignore
@@ -0,0 +1,23 @@
+# ignore ModelSim generated files and directories (temp files and so on)
+[_@]*
+
+# ignore compilation output of ModelSim
+*.mti
+*.dat
+*.dbs
+*.psm
+*.bak
+*.cmp
+*.jpg
+*.html
+*.bsf
+
+# ignore simulation output of ModelSim
+wlf*
+*.wlf
+*.vstf
+*.ucdb
+cov*/
+transcript*
+sc_dpiheader.h
+vsim.dbg
diff --git a/vendor/gitignore/Global/Momentics.gitignore b/vendor/gitignore/Global/Momentics.gitignore
new file mode 100644
index 00000000000..b14db2d8645
--- /dev/null
+++ b/vendor/gitignore/Global/Momentics.gitignore
@@ -0,0 +1,8 @@
+# Built files
+x86/
+arm/
+arm-p/
+translations/*.qm
+
+# IDE settings
+.settings/
diff --git a/vendor/gitignore/Global/MonoDevelop.gitignore b/vendor/gitignore/Global/MonoDevelop.gitignore
new file mode 100644
index 00000000000..ef38d06b08f
--- /dev/null
+++ b/vendor/gitignore/Global/MonoDevelop.gitignore
@@ -0,0 +1,8 @@
+#User Specific
+*.userprefs
+*.usertasks
+
+#Mono Project Files
+*.pidb
+*.resources
+test-results/
diff --git a/vendor/gitignore/Global/NetBeans.gitignore b/vendor/gitignore/Global/NetBeans.gitignore
new file mode 100644
index 00000000000..520d91ff584
--- /dev/null
+++ b/vendor/gitignore/Global/NetBeans.gitignore
@@ -0,0 +1,7 @@
+nbproject/private/
+build/
+nbbuild/
+dist/
+nbdist/
+nbactions.xml
+.nb-gradle/
diff --git a/vendor/gitignore/Global/Ninja.gitignore b/vendor/gitignore/Global/Ninja.gitignore
new file mode 100644
index 00000000000..50e58f24cc9
--- /dev/null
+++ b/vendor/gitignore/Global/Ninja.gitignore
@@ -0,0 +1,2 @@
+.ninja_deps
+.ninja_log
diff --git a/vendor/gitignore/Global/NotepadPP.gitignore b/vendor/gitignore/Global/NotepadPP.gitignore
new file mode 100644
index 00000000000..8fbda83a2c9
--- /dev/null
+++ b/vendor/gitignore/Global/NotepadPP.gitignore
@@ -0,0 +1,2 @@
+# Notepad++ backups #
+*.bak
diff --git a/vendor/gitignore/Global/OSX.gitignore b/vendor/gitignore/Global/OSX.gitignore
new file mode 100644
index 00000000000..660b31353e8
--- /dev/null
+++ b/vendor/gitignore/Global/OSX.gitignore
@@ -0,0 +1,24 @@
+.DS_Store
+.AppleDouble
+.LSOverride
+
+# Icon must end with two \r
+Icon
+
+# Thumbnails
+._*
+
+# Files that might appear in the root of a volume
+.DocumentRevisions-V100
+.fseventsd
+.Spotlight-V100
+.TemporaryItems
+.Trashes
+.VolumeIcon.icns
+
+# Directories potentially created on remote AFP share
+.AppleDB
+.AppleDesktop
+Network Trash Folder
+Temporary Items
+.apdisk
diff --git a/vendor/gitignore/Global/Otto.gitignore b/vendor/gitignore/Global/Otto.gitignore
new file mode 100644
index 00000000000..5aa263f9db0
--- /dev/null
+++ b/vendor/gitignore/Global/Otto.gitignore
@@ -0,0 +1 @@
+.otto/
diff --git a/vendor/gitignore/Global/Redcar.gitignore b/vendor/gitignore/Global/Redcar.gitignore
new file mode 100644
index 00000000000..b4a9d1d68e3
--- /dev/null
+++ b/vendor/gitignore/Global/Redcar.gitignore
@@ -0,0 +1 @@
+.redcar
diff --git a/vendor/gitignore/Global/Redis.gitignore b/vendor/gitignore/Global/Redis.gitignore
new file mode 100644
index 00000000000..57c1c230f92
--- /dev/null
+++ b/vendor/gitignore/Global/Redis.gitignore
@@ -0,0 +1,3 @@
+# Ignore redis binary dump (dump.rdb) files
+
+*.rdb
diff --git a/vendor/gitignore/Global/SBT.gitignore b/vendor/gitignore/Global/SBT.gitignore
new file mode 100644
index 00000000000..970d897c75c
--- /dev/null
+++ b/vendor/gitignore/Global/SBT.gitignore
@@ -0,0 +1,9 @@
+# Simple Build Tool
+# http://www.scala-sbt.org/release/docs/Getting-Started/Directories.html#configuring-version-control
+
+target/
+lib_managed/
+src_managed/
+project/boot/
+.history
+.cache
diff --git a/vendor/gitignore/Global/SVN.gitignore b/vendor/gitignore/Global/SVN.gitignore
new file mode 100644
index 00000000000..1b53ace613f
--- /dev/null
+++ b/vendor/gitignore/Global/SVN.gitignore
@@ -0,0 +1 @@
+.svn/
diff --git a/vendor/gitignore/Global/SlickEdit.gitignore b/vendor/gitignore/Global/SlickEdit.gitignore
new file mode 100644
index 00000000000..f30b8da457c
--- /dev/null
+++ b/vendor/gitignore/Global/SlickEdit.gitignore
@@ -0,0 +1,11 @@
+# SlickEdit workspace and project files are ignored by default because
+# typically they are considered to be developer-specific and not part of a
+# project.
+*.vpw
+*.vpj
+
+# SlickEdit workspace history and tag files always contain user-specific
+# data so they should not be stored in a repository.
+*.vpwhistu
+*.vpwhist
+*.vtg
diff --git a/vendor/gitignore/Global/SublimeText.gitignore b/vendor/gitignore/Global/SublimeText.gitignore
new file mode 100644
index 00000000000..1d4e6137591
--- /dev/null
+++ b/vendor/gitignore/Global/SublimeText.gitignore
@@ -0,0 +1,14 @@
+# cache files for sublime text
+*.tmlanguage.cache
+*.tmPreferences.cache
+*.stTheme.cache
+
+# workspace files are user-specific
+*.sublime-workspace
+
+# project files should be checked into the repository, unless a significant
+# proportion of contributors will probably not be using SublimeText
+# *.sublime-project
+
+# sftp configuration file
+sftp-config.json
diff --git a/vendor/gitignore/Global/SynopsysVCS.gitignore b/vendor/gitignore/Global/SynopsysVCS.gitignore
new file mode 100644
index 00000000000..eed2432fb78
--- /dev/null
+++ b/vendor/gitignore/Global/SynopsysVCS.gitignore
@@ -0,0 +1,36 @@
+# Waveform formats
+*.vcd
+*.vpd
+*.evcd
+*.fsdb
+
+# Default name of the simulation executable. A different name can be
+# specified with this switch (the associated daidir database name is
+# also taken from here): -o <path>/<filename>
+simv
+
+# Generated for Verilog and VHDL top configs
+simv.daidir/
+simv.db.dir/
+
+# Infrastructure necessary to co-simulate SystemC models with
+# Verilog/VHDL models. An alternate directory may be specified with this
+# switch: -Mdir=<directory_path>
+csrc/
+
+# Log file - the following switch allows to specify the file that will be
+# used to write all messages from simulation: -l <filename>
+*.log
+
+# Coverage results (generated with urg) and database location. The
+# following switch can also be used: urg -dir <coverage_directory>.vdb
+simv.vdb/
+urgReport/
+
+# DVE and UCLI related files.
+DVEfiles/
+ucli.key
+
+# When the design is elaborated for DirectC, the following file is created
+# with declarations for C/C++ functions.
+vc_hdrs.h
diff --git a/vendor/gitignore/Global/Tags.gitignore b/vendor/gitignore/Global/Tags.gitignore
new file mode 100644
index 00000000000..c0318165a27
--- /dev/null
+++ b/vendor/gitignore/Global/Tags.gitignore
@@ -0,0 +1,16 @@
+# Ignore tags created by etags, ctags, gtags (GNU global) and cscope
+TAGS
+.TAGS
+!TAGS/
+tags
+.tags
+!tags/
+gtags.files
+GTAGS
+GRTAGS
+GPATH
+cscope.files
+cscope.out
+cscope.in.out
+cscope.po.out
+
diff --git a/vendor/gitignore/Global/TextMate.gitignore b/vendor/gitignore/Global/TextMate.gitignore
new file mode 100644
index 00000000000..41e8d07a940
--- /dev/null
+++ b/vendor/gitignore/Global/TextMate.gitignore
@@ -0,0 +1,3 @@
+*.tmproj
+*.tmproject
+tmtags
diff --git a/vendor/gitignore/Global/TortoiseGit.gitignore b/vendor/gitignore/Global/TortoiseGit.gitignore
new file mode 100644
index 00000000000..db89590a629
--- /dev/null
+++ b/vendor/gitignore/Global/TortoiseGit.gitignore
@@ -0,0 +1,2 @@
+# Project-level settings
+/.tgitconfig
diff --git a/vendor/gitignore/Global/Vagrant.gitignore b/vendor/gitignore/Global/Vagrant.gitignore
new file mode 100644
index 00000000000..a977916f658
--- /dev/null
+++ b/vendor/gitignore/Global/Vagrant.gitignore
@@ -0,0 +1 @@
+.vagrant/
diff --git a/vendor/gitignore/Global/Vim.gitignore b/vendor/gitignore/Global/Vim.gitignore
new file mode 100644
index 00000000000..bdc04a0b529
--- /dev/null
+++ b/vendor/gitignore/Global/Vim.gitignore
@@ -0,0 +1,10 @@
+# swap
+[._]*.s[a-w][a-z]
+[._]s[a-w][a-z]
+# session
+Session.vim
+# temporary
+.netrwhist
+*~
+# auto-generated tag files
+tags
diff --git a/vendor/gitignore/Global/VirtualEnv.gitignore b/vendor/gitignore/Global/VirtualEnv.gitignore
new file mode 100644
index 00000000000..b2c22f2af7f
--- /dev/null
+++ b/vendor/gitignore/Global/VirtualEnv.gitignore
@@ -0,0 +1,12 @@
+# Virtualenv
+# http://iamzed.com/2009/05/07/a-primer-on-virtualenv/
+.Python
+[Bb]in
+[Ii]nclude
+[Ll]ib
+[Ll]ib64
+[Ll]ocal
+[Ss]cripts
+pyvenv.cfg
+.venv
+pip-selfcheck.json
diff --git a/vendor/gitignore/Global/VisualStudioCode.gitignore b/vendor/gitignore/Global/VisualStudioCode.gitignore
new file mode 100644
index 00000000000..faa18382a3c
--- /dev/null
+++ b/vendor/gitignore/Global/VisualStudioCode.gitignore
@@ -0,0 +1,2 @@
+.vscode
+
diff --git a/vendor/gitignore/Global/WebMethods.gitignore b/vendor/gitignore/Global/WebMethods.gitignore
new file mode 100644
index 00000000000..b383c25ca3c
--- /dev/null
+++ b/vendor/gitignore/Global/WebMethods.gitignore
@@ -0,0 +1,14 @@
+**/IntegrationServer/datastore/
+**/IntegrationServer/db/
+**/IntegrationServer/DocumentStore/
+**/IntegrationServer/lib/
+**/IntegrationServer/logs/
+**/IntegrationServer/replicate/
+**/IntegrationServer/sdk/
+**/IntegrationServer/support/
+**/IntegrationServer/update/
+**/IntegrationServer/userFtpRoot/
+**/IntegrationServer/web/
+**/IntegrationServer/WmRepository4/
+**/IntegrationServer/XAStore/
+**/IntegrationServer/packages/Wm*/
diff --git a/vendor/gitignore/Global/Windows.gitignore b/vendor/gitignore/Global/Windows.gitignore
new file mode 100644
index 00000000000..a0d31452b0e
--- /dev/null
+++ b/vendor/gitignore/Global/Windows.gitignore
@@ -0,0 +1,18 @@
+# Windows image file caches
+Thumbs.db
+ehthumbs.db
+
+# Folder config file
+Desktop.ini
+
+# Recycle Bin used on file shares
+$RECYCLE.BIN/
+
+# Windows Installer files
+*.cab
+*.msi
+*.msm
+*.msp
+
+# Windows shortcuts
+*.lnk
diff --git a/vendor/gitignore/Global/Xcode.gitignore b/vendor/gitignore/Global/Xcode.gitignore
new file mode 100644
index 00000000000..37de8bb4793
--- /dev/null
+++ b/vendor/gitignore/Global/Xcode.gitignore
@@ -0,0 +1,23 @@
+# Xcode
+#
+# gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore
+
+## Build generated
+build/
+DerivedData/
+
+## Various settings
+*.pbxuser
+!default.pbxuser
+*.mode1v3
+!default.mode1v3
+*.mode2v3
+!default.mode2v3
+*.perspectivev3
+!default.perspectivev3
+xcuserdata/
+
+## Other
+*.moved-aside
+*.xccheckout
+*.xcscmblueprint
diff --git a/vendor/gitignore/Global/XilinxISE.gitignore b/vendor/gitignore/Global/XilinxISE.gitignore
new file mode 100644
index 00000000000..4475f843da9
--- /dev/null
+++ b/vendor/gitignore/Global/XilinxISE.gitignore
@@ -0,0 +1,67 @@
+# intermediate build files
+*.bgn
+*.bit
+*.bld
+*.cmd_log
+*.drc
+*.ll
+*.lso
+*.msd
+*.msk
+*.ncd
+*.ngc
+*.ngd
+*.ngr
+*.pad
+*.par
+*.pcf
+*.prj
+*.ptwx
+*.rbb
+*.rbd
+*.stx
+*.syr
+*.twr
+*.twx
+*.unroutes
+*.ut
+*.xpi
+*.xst
+*_bitgen.xwbt
+*_envsettings.html
+*_map.map
+*_map.mrp
+*_map.ngm
+*_map.xrpt
+*_ngdbuild.xrpt
+*_pad.csv
+*_pad.txt
+*_par.xrpt
+*_summary.html
+*_summary.xml
+*_usage.xml
+*_xst.xrpt
+
+# iMPACT generated files
+_impactbatch.log
+impact.xsl
+impact_impact.xwbt
+ise_impact.cmd
+webtalk_impact.xml
+
+# Core Generator generated files
+xaw2verilog.log
+
+# project-wide generated files
+*.gise
+par_usage_statistics.html
+usage_statistics_webtalk.html
+webtalk.log
+webtalk_pn.xml
+
+# generated folders
+iseconfig/
+xlnx_auto_0_xdb/
+xst/
+_ngo/
+_xmsgs/
diff --git a/vendor/gitignore/Go.gitignore b/vendor/gitignore/Go.gitignore
new file mode 100644
index 00000000000..daf913b1b34
--- /dev/null
+++ b/vendor/gitignore/Go.gitignore
@@ -0,0 +1,24 @@
+# Compiled Object files, Static and Dynamic libs (Shared Objects)
+*.o
+*.a
+*.so
+
+# Folders
+_obj
+_test
+
+# Architecture specific extensions/prefixes
+*.[568vq]
+[568vq].out
+
+*.cgo1.go
+*.cgo2.c
+_cgo_defun.c
+_cgo_gotypes.go
+_cgo_export.*
+
+_testmain.go
+
+*.exe
+*.test
+*.prof
diff --git a/vendor/gitignore/Gradle.gitignore b/vendor/gitignore/Gradle.gitignore
new file mode 100644
index 00000000000..77617a15c38
--- /dev/null
+++ b/vendor/gitignore/Gradle.gitignore
@@ -0,0 +1,14 @@
+.gradle
+build/
+
+# Ignore Gradle GUI config
+gradle-app.setting
+
+# Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored)
+!gradle-wrapper.jar
+
+# Cache of project
+.gradletasknamecache
+
+# # Work around https://youtrack.jetbrains.com/issue/IDEA-116898
+# gradle/wrapper/gradle-wrapper.properties
diff --git a/vendor/gitignore/Grails.gitignore b/vendor/gitignore/Grails.gitignore
new file mode 100644
index 00000000000..9185f14c37c
--- /dev/null
+++ b/vendor/gitignore/Grails.gitignore
@@ -0,0 +1,33 @@
+# .gitignore for Grails 1.2 and 1.3
+# Although this should work for most versions of grails, it is
+# suggested that you use the "grails integrate-with --git" command
+# to generate your .gitignore file.
+
+# web application files
+/web-app/WEB-INF/classes
+
+# default HSQL database files for production mode
+/prodDb.*
+
+# general HSQL database files
+*Db.properties
+*Db.script
+
+# logs
+/stacktrace.log
+/test/reports
+/logs
+
+# project release file
+/*.war
+
+# plugin release files
+/*.zip
+/plugin.xml
+
+# older plugin install locations
+/plugins
+/web-app/plugins
+
+# "temporary" build files
+/target
diff --git a/vendor/gitignore/Haskell.gitignore b/vendor/gitignore/Haskell.gitignore
new file mode 100644
index 00000000000..096abdd90b3
--- /dev/null
+++ b/vendor/gitignore/Haskell.gitignore
@@ -0,0 +1,18 @@
+dist
+dist-*
+cabal-dev
+*.o
+*.hi
+*.chi
+*.chs.h
+*.dyn_o
+*.dyn_hi
+.hpc
+.hsenv
+.cabal-sandbox/
+cabal.sandbox.config
+*.prof
+*.aux
+*.hp
+*.eventlog
+.stack-work/
diff --git a/vendor/gitignore/IGORPro.gitignore b/vendor/gitignore/IGORPro.gitignore
new file mode 100644
index 00000000000..c62be650036
--- /dev/null
+++ b/vendor/gitignore/IGORPro.gitignore
@@ -0,0 +1,5 @@
+# Avoid including Experiment files: they can be created and edited locally to test the ipf files
+*.pxp
+*.pxt
+*.uxp
+*.uxt
diff --git a/vendor/gitignore/Idris.gitignore b/vendor/gitignore/Idris.gitignore
new file mode 100644
index 00000000000..c28bc7cc675
--- /dev/null
+++ b/vendor/gitignore/Idris.gitignore
@@ -0,0 +1,2 @@
+*.ibc
+*.o
diff --git a/vendor/gitignore/Java.gitignore b/vendor/gitignore/Java.gitignore
new file mode 100644
index 00000000000..32858aad3c3
--- /dev/null
+++ b/vendor/gitignore/Java.gitignore
@@ -0,0 +1,12 @@
+*.class
+
+# Mobile Tools for Java (J2ME)
+.mtj.tmp/
+
+# Package Files #
+*.jar
+*.war
+*.ear
+
+# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
+hs_err_pid*
diff --git a/vendor/gitignore/Jboss.gitignore b/vendor/gitignore/Jboss.gitignore
new file mode 100644
index 00000000000..75d1731ed97
--- /dev/null
+++ b/vendor/gitignore/Jboss.gitignore
@@ -0,0 +1,19 @@
+jboss/server/all/deploy/project.ext
+jboss/server/default/deploy/project.ext
+jboss/server/minimal/deploy/project.ext
+jboss/server/all/log/*.log
+jboss/server/all/tmp/**/*
+jboss/server/all/data/**/*
+jboss/server/all/work/**/*
+jboss/server/default/log/*.log
+jboss/server/default/tmp/**/*
+jboss/server/default/data/**/*
+jboss/server/default/work/**/*
+jboss/server/minimal/log/*.log
+jboss/server/minimal/tmp/**/*
+jboss/server/minimal/data/**/*
+jboss/server/minimal/work/**/*
+
+# deployed package files #
+
+*.DEPLOYED
diff --git a/vendor/gitignore/Jekyll.gitignore b/vendor/gitignore/Jekyll.gitignore
new file mode 100644
index 00000000000..5c91b60c063
--- /dev/null
+++ b/vendor/gitignore/Jekyll.gitignore
@@ -0,0 +1,3 @@
+_site/
+.sass-cache/
+.jekyll-metadata
diff --git a/vendor/gitignore/Joomla.gitignore b/vendor/gitignore/Joomla.gitignore
new file mode 100644
index 00000000000..0d7a0de298f
--- /dev/null
+++ b/vendor/gitignore/Joomla.gitignore
@@ -0,0 +1,546 @@
+/.gitignore
+/.htaccess
+/administrator/cache/*
+/administrator/components/com_admin/*
+/administrator/components/com_ajax/*
+/administrator/components/com_tags/*
+/administrator/components/com_banners/*
+/administrator/components/com_cache/*
+/administrator/components/com_postinstall/*
+/administrator/components/com_joomlaupdate/*
+/administrator/components/com_contenthistory/*
+/administrator/components/com_categories/*
+/administrator/components/com_checkin/*
+/administrator/components/com_config/*
+/administrator/components/com_contact/*
+/administrator/components/com_content/*
+/administrator/components/com_cpanel/*
+/administrator/components/com_finder/*
+/administrator/components/com_installer/*
+/administrator/components/com_languages/*
+/administrator/components/com_login/*
+/administrator/components/com_media/*
+/administrator/components/com_menus/*
+/administrator/components/com_messages/*
+/administrator/components/com_modules/*
+/administrator/components/com_newsfeeds/*
+/administrator/components/com_plugins/*
+/administrator/components/com_redirect/*
+/administrator/components/com_search/*
+/administrator/components/com_templates/*
+/administrator/components/com_users/*
+/administrator/components/com_weblinks/*
+/administrator/components/index.html
+/administrator/help/*
+/administrator/includes/*
+/administrator/language/en-GB/en-GB.com_ajax.ini
+/administrator/language/en-GB/en-GB.com_ajax.sys.ini
+/administrator/language/en-GB/en-GB.com_contenthistory.ini
+/administrator/language/en-GB/en-GB.com_contenthistory.sys.ini
+/administrator/language/en-GB/en-GB.com_joomlaupdate.ini
+/administrator/language/en-GB/en-GB.com_joomlaupdate.sys.ini
+/administrator/language/en-GB/en-GB.com_postinstall.ini
+/administrator/language/en-GB/en-GB.com_postinstall.sys.ini
+/administrator/language/en-GB/en-GB.com_sitemapjen.sys.ini
+/administrator/language/en-GB/en-GB.com_tags.ini
+/administrator/language/en-GB/en-GB.com_tags.sys.ini
+/administrator/language/en-GB/en-GB.mod_stats_admin.ini
+/administrator/language/en-GB/en-GB.mod_stats_admin.sys.ini
+/administrator/language/en-GB/en-GB.plg_authentication_cookie.ini
+/administrator/language/en-GB/en-GB.plg_authentication_cookie.sys.ini
+/administrator/language/en-GB/en-GB.plg_content_contact.ini
+/administrator/language/en-GB/en-GB.plg_content_contact.sys.ini
+/administrator/language/en-GB/en-GB.plg_content_finder.ini
+/administrator/language/en-GB/en-GB.plg_content_finder.sys.ini
+/administrator/language/en-GB/en-GB.plg_finder_categories.ini
+/administrator/language/en-GB/en-GB.plg_finder_categories.sys.ini
+/administrator/language/en-GB/en-GB.plg_finder_contacts.ini
+/administrator/language/en-GB/en-GB.plg_finder_contacts.sys.ini
+/administrator/language/en-GB/en-GB.plg_finder_content.ini
+/administrator/language/en-GB/en-GB.plg_finder_content.sys.ini
+/administrator/language/en-GB/en-GB.plg_finder_newsfeeds.sys.ini
+/administrator/language/en-GB/en-GB.plg_finder_newsfeeds.ini
+/administrator/language/en-GB/en-GB.plg_finder_tags.ini
+/administrator/language/en-GB/en-GB.plg_finder_tags.sys.ini
+/administrator/language/en-GB/en-GB.plg_finder_weblinks.ini
+/administrator/language/en-GB/en-GB.plg_finder_weblinks.sys.ini
+/administrator/language/en-GB/en-GB.plg_installer_webinstaller.ini
+/administrator/language/en-GB/en-GB.plg_installer_webinstaller.sys.ini
+/administrator/language/en-GB/en-GB.plg_quickicon_joomlaupdate.ini
+/administrator/language/en-GB/en-GB.plg_quickicon_joomlaupdate.sys.ini
+/administrator/language/en-GB/en-GB.plg_search_tags.ini
+/administrator/language/en-GB/en-GB.plg_search_tags.sys.ini
+/administrator/language/en-GB/en-GB.plg_system_languagecode.ini
+/administrator/language/en-GB/en-GB.plg_system_languagecode.sys.ini
+/administrator/language/en-GB/en-GB.plg_twofactorauth_totp.ini
+/administrator/language/en-GB/en-GB.plg_twofactorauth_totp.sys.ini
+/administrator/language/en-GB/en-GB.plg_twofactorauth_yubikey.ini
+/administrator/language/en-GB/en-GB.plg_twofactorauth_yubikey.sys.ini
+/administrator/language/en-GB/en-GB.tpl_isis.ini
+/administrator/language/en-GB/en-GB.tpl_isis.sys.ini
+/administrator/language/en-GB/install.xml
+/administrator/language/en-GB/en-GB.com_admin.ini
+/administrator/language/en-GB/en-GB.com_admin.sys.ini
+/administrator/language/en-GB/en-GB.com_banners.ini
+/administrator/language/en-GB/en-GB.com_banners.sys.ini
+/administrator/language/en-GB/en-GB.com_cache.ini
+/administrator/language/en-GB/en-GB.com_cache.sys.ini
+/administrator/language/en-GB/en-GB.com_categories.ini
+/administrator/language/en-GB/en-GB.com_categories.sys.ini
+/administrator/language/en-GB/en-GB.com_checkin.ini
+/administrator/language/en-GB/en-GB.com_checkin.sys.ini
+/administrator/language/en-GB/en-GB.com_config.ini
+/administrator/language/en-GB/en-GB.com_config.sys.ini
+/administrator/language/en-GB/en-GB.com_contact.ini
+/administrator/language/en-GB/en-GB.com_contact.sys.ini
+/administrator/language/en-GB/en-GB.com_content.ini
+/administrator/language/en-GB/en-GB.com_content.sys.ini
+/administrator/language/en-GB/en-GB.com_cpanel.ini
+/administrator/language/en-GB/en-GB.com_cpanel.sys.ini
+/administrator/language/en-GB/en-GB.com_finder.ini
+/administrator/language/en-GB/en-GB.com_finder.sys.ini
+/administrator/language/en-GB/en-GB.com_installer.ini
+/administrator/language/en-GB/en-GB.com_installer.sys.ini
+/administrator/language/en-GB/en-GB.com_languages.ini
+/administrator/language/en-GB/en-GB.com_languages.sys.ini
+/administrator/language/en-GB/en-GB.com_login.ini
+/administrator/language/en-GB/en-GB.com_login.sys.ini
+/administrator/language/en-GB/en-GB.com_mailto.sys.ini
+/administrator/language/en-GB/en-GB.com_media.ini
+/administrator/language/en-GB/en-GB.com_media.sys.ini
+/administrator/language/en-GB/en-GB.com_menus.ini
+/administrator/language/en-GB/en-GB.com_menus.sys.ini
+/administrator/language/en-GB/en-GB.com_messages.ini
+/administrator/language/en-GB/en-GB.com_messages.sys.ini
+/administrator/language/en-GB/en-GB.com_modules.ini
+/administrator/language/en-GB/en-GB.com_modules.sys.ini
+/administrator/language/en-GB/en-GB.com_newsfeeds.ini
+/administrator/language/en-GB/en-GB.com_newsfeeds.sys.ini
+/administrator/language/en-GB/en-GB.com_plugins.ini
+/administrator/language/en-GB/en-GB.com_plugins.sys.ini
+/administrator/language/en-GB/en-GB.com_redirect.ini
+/administrator/language/en-GB/en-GB.com_redirect.sys.ini
+/administrator/language/en-GB/en-GB.com_search.ini
+/administrator/language/en-GB/en-GB.com_search.sys.ini
+/administrator/language/en-GB/en-GB.com_templates.ini
+/administrator/language/en-GB/en-GB.com_templates.sys.ini
+/administrator/language/en-GB/en-GB.com_users.ini
+/administrator/language/en-GB/en-GB.com_users.sys.ini
+/administrator/language/en-GB/en-GB.com_weblinks.ini
+/administrator/language/en-GB/en-GB.com_weblinks.sys.ini
+/administrator/language/en-GB/en-GB.com_wrapper.ini
+/administrator/language/en-GB/en-GB.com_wrapper.sys.ini
+/administrator/language/en-GB/en-GB.ini
+/administrator/language/en-GB/en-GB.lib_joomla.ini
+/administrator/language/en-GB/en-GB.localise.php
+/administrator/language/en-GB/en-GB.mod_custom.ini
+/administrator/language/en-GB/en-GB.mod_custom.sys.ini
+/administrator/language/en-GB/en-GB.mod_feed.ini
+/administrator/language/en-GB/en-GB.mod_feed.sys.ini
+/administrator/language/en-GB/en-GB.mod_latest.ini
+/administrator/language/en-GB/en-GB.mod_latest.sys.ini
+/administrator/language/en-GB/en-GB.mod_logged.ini
+/administrator/language/en-GB/en-GB.mod_logged.sys.ini
+/administrator/language/en-GB/en-GB.mod_login.ini
+/administrator/language/en-GB/en-GB.mod_login.sys.ini
+/administrator/language/en-GB/en-GB.mod_menu.ini
+/administrator/language/en-GB/en-GB.mod_menu.sys.ini
+/administrator/language/en-GB/en-GB.mod_multilangstatus.ini
+/administrator/language/en-GB/en-GB.mod_multilangstatus.sys.ini
+/administrator/language/en-GB/en-GB.mod_online.ini
+/administrator/language/en-GB/en-GB.mod_online.sys.ini
+/administrator/language/en-GB/en-GB.mod_popular.ini
+/administrator/language/en-GB/en-GB.mod_popular.sys.ini
+/administrator/language/en-GB/en-GB.mod_quickicon.ini
+/administrator/language/en-GB/en-GB.mod_quickicon.sys.ini
+/administrator/language/en-GB/en-GB.mod_status.ini
+/administrator/language/en-GB/en-GB.mod_status.sys.ini
+/administrator/language/en-GB/en-GB.mod_submenu.ini
+/administrator/language/en-GB/en-GB.mod_submenu.sys.ini
+/administrator/language/en-GB/en-GB.mod_title.ini
+/administrator/language/en-GB/en-GB.mod_title.sys.ini
+/administrator/language/en-GB/en-GB.mod_toolbar.ini
+/administrator/language/en-GB/en-GB.mod_toolbar.sys.ini
+/administrator/language/en-GB/en-GB.mod_unread.ini
+/administrator/language/en-GB/en-GB.mod_unread.sys.ini
+/administrator/language/en-GB/en-GB.mod_version.ini
+/administrator/language/en-GB/en-GB.mod_version.sys.ini
+/administrator/language/en-GB/en-GB.plg_authentication_example.ini
+/administrator/language/en-GB/en-GB.plg_authentication_example.sys.ini
+/administrator/language/en-GB/en-GB.plg_authentication_gmail.ini
+/administrator/language/en-GB/en-GB.plg_authentication_gmail.sys.ini
+/administrator/language/en-GB/en-GB.plg_authentication_joomla.ini
+/administrator/language/en-GB/en-GB.plg_authentication_joomla.sys.ini
+/administrator/language/en-GB/en-GB.plg_authentication_ldap.ini
+/administrator/language/en-GB/en-GB.plg_authentication_ldap.sys.ini
+/administrator/language/en-GB/en-GB.plg_captcha_recaptcha.ini
+/administrator/language/en-GB/en-GB.plg_captcha_recaptcha.sys.ini
+/administrator/language/en-GB/en-GB.plg_content_emailcloak.ini
+/administrator/language/en-GB/en-GB.plg_content_emailcloak.sys.ini
+/administrator/language/en-GB/en-GB.plg_content_geshi.ini
+/administrator/language/en-GB/en-GB.plg_content_geshi.sys.ini
+/administrator/language/en-GB/en-GB.plg_content_joomla.ini
+/administrator/language/en-GB/en-GB.plg_content_joomla.sys.ini
+/administrator/language/en-GB/en-GB.plg_content_loadmodule.ini
+/administrator/language/en-GB/en-GB.plg_content_loadmodule.sys.ini
+/administrator/language/en-GB/en-GB.plg_content_pagebreak.ini
+/administrator/language/en-GB/en-GB.plg_content_pagebreak.sys.ini
+/administrator/language/en-GB/en-GB.plg_content_pagenavigation.ini
+/administrator/language/en-GB/en-GB.plg_content_pagenavigation.sys.ini
+/administrator/language/en-GB/en-GB.plg_content_vote.ini
+/administrator/language/en-GB/en-GB.plg_content_vote.sys.ini
+/administrator/language/en-GB/en-GB.plg_editors_codemirror.ini
+/administrator/language/en-GB/en-GB.plg_editors_codemirror.sys.ini
+/administrator/language/en-GB/en-GB.plg_editors_none.ini
+/administrator/language/en-GB/en-GB.plg_editors_none.sys.ini
+/administrator/language/en-GB/en-GB.plg_editors_tinymce.ini
+/administrator/language/en-GB/en-GB.plg_editors_tinymce.sys.ini
+/administrator/language/en-GB/en-GB.plg_editors-xtd_article.ini
+/administrator/language/en-GB/en-GB.plg_editors-xtd_article.sys.ini
+/administrator/language/en-GB/en-GB.plg_editors-xtd_image.ini
+/administrator/language/en-GB/en-GB.plg_editors-xtd_image.sys.ini
+/administrator/language/en-GB/en-GB.plg_editors-xtd_pagebreak.ini
+/administrator/language/en-GB/en-GB.plg_editors-xtd_pagebreak.sys.ini
+/administrator/language/en-GB/en-GB.plg_editors-xtd_readmore.ini
+/administrator/language/en-GB/en-GB.plg_editors-xtd_readmore.sys.ini
+/administrator/language/en-GB/en-GB.plg_extension_joomla.ini
+/administrator/language/en-GB/en-GB.plg_extension_joomla.sys.ini
+/administrator/language/en-GB/en-GB.plg_quickicon_extensionupdate.ini
+/administrator/language/en-GB/en-GB.plg_quickicon_extensionupdate.sys.ini
+/administrator/language/en-GB/en-GB.plg_search_categories.ini
+/administrator/language/en-GB/en-GB.plg_search_categories.sys.ini
+/administrator/language/en-GB/en-GB.plg_search_contacts.ini
+/administrator/language/en-GB/en-GB.plg_search_contacts.sys.ini
+/administrator/language/en-GB/en-GB.plg_search_content.ini
+/administrator/language/en-GB/en-GB.plg_search_content.sys.ini
+/administrator/language/en-GB/en-GB.plg_search_newsfeeds.ini
+/administrator/language/en-GB/en-GB.plg_search_newsfeeds.sys.ini
+/administrator/language/en-GB/en-GB.plg_search_weblinks.ini
+/administrator/language/en-GB/en-GB.plg_search_weblinks.sys.ini
+/administrator/language/en-GB/en-GB.plg_system_cache.ini
+/administrator/language/en-GB/en-GB.plg_system_cache.sys.ini
+/administrator/language/en-GB/en-GB.plg_system_debug.ini
+/administrator/language/en-GB/en-GB.plg_system_debug.sys.ini
+/administrator/language/en-GB/en-GB.plg_system_highlight.ini
+/administrator/language/en-GB/en-GB.plg_system_highlight.sys.ini
+/administrator/language/en-GB/en-GB.plg_system_languagefilter.ini
+/administrator/language/en-GB/en-GB.plg_system_languagefilter.sys.ini
+/administrator/language/en-GB/en-GB.plg_system_log.ini
+/administrator/language/en-GB/en-GB.plg_system_logout.ini
+/administrator/language/en-GB/en-GB.plg_system_logout.sys.ini
+/administrator/language/en-GB/en-GB.plg_system_log.sys.ini
+/administrator/language/en-GB/en-GB.plg_system_p3p.ini
+/administrator/language/en-GB/en-GB.plg_system_p3p.sys.ini
+/administrator/language/en-GB/en-GB.plg_system_redirect.ini
+/administrator/language/en-GB/en-GB.plg_system_redirect.sys.ini
+/administrator/language/en-GB/en-GB.plg_system_remember.ini
+/administrator/language/en-GB/en-GB.plg_system_remember.sys.ini
+/administrator/language/en-GB/en-GB.plg_system_sef.ini
+/administrator/language/en-GB/en-GB.plg_system_sef.sys.ini
+/administrator/language/en-GB/en-GB.plg_user_contactcreator.ini
+/administrator/language/en-GB/en-GB.plg_user_contactcreator.sys.ini
+/administrator/language/en-GB/en-GB.plg_user_joomla.ini
+/administrator/language/en-GB/en-GB.plg_user_joomla.sys.ini
+/administrator/language/en-GB/en-GB.plg_user_profile.ini
+/administrator/language/en-GB/en-GB.plg_user_profile.sys.ini
+/administrator/language/en-GB/en-GB.tpl_bluestork.ini
+/administrator/language/en-GB/en-GB.tpl_bluestork.sys.ini
+/administrator/language/en-GB/en-GB.tpl_hathor.ini
+/administrator/language/en-GB/en-GB.tpl_hathor.sys.ini
+/administrator/language/en-GB/en-GB.xml
+/administrator/language/en-GB/index.html
+/administrator/language/overrides/*
+/administrator/language/index.html
+/administrator/manifests/*
+/administrator/modules/mod_custom/*
+/administrator/modules/mod_feed/*
+/administrator/modules/mod_latest/*
+/administrator/modules/mod_logged/*
+/administrator/modules/mod_login/*
+/administrator/modules/mod_menu/*
+/administrator/modules/mod_multilangstatus/*
+/administrator/modules/mod_online/*
+/administrator/modules/mod_popular/*
+/administrator/modules/mod_quickicon/*
+/administrator/modules/mod_status/*
+/administrator/modules/mod_submenu/*
+/administrator/modules/mod_title/*
+/administrator/modules/mod_toolbar/*
+/administrator/modules/mod_unread/*
+/administrator/modules/mod_version/*
+/administrator/modules/mod_stats_admin/*
+/administrator/modules/index.html
+/administrator/templates/bluestork/*
+/administrator/templates/isis/*
+/administrator/templates/hathor/*
+/administrator/templates/system/*
+/administrator/templates/index.html
+/administrator/index.php
+/cache/*
+/bin/*
+/cli/*
+/components/com_banners/*
+/components/com_ajax/*
+/components/com_config/*
+/components/com_contenthistory/*
+/components/com_tags/*
+/components/com_contact/*
+/components/com_content/*
+/components/com_finder/*
+/components/com_mailto/*
+/components/com_media/*
+/components/com_newsfeeds/*
+/components/com_search/*
+/components/com_users/*
+/components/com_weblinks/*
+/components/com_wrapper/*
+/components/index.html
+/images/banners/*
+/images/headers/*
+/images/sampledata/*
+/images/joomla*
+/images/index.html
+/images/powered_by.png
+/includes/*
+/installation/*
+/language/en-GB/en-GB.com_ajax.ini
+/language/en-GB/en-GB.com_config.ini
+/language/en-GB/en-GB.com_contact.ini
+/language/en-GB/en-GB.com_finder.ini
+/language/en-GB/en-GB.com_tags.ini
+/language/en-GB/en-GB.finder_cli.ini
+/language/en-GB/en-GB.lib_fof.sys.ini
+/language/en-GB/en-GB.lib_fof.ini
+/language/en-GB/en-GB.com_content.ini
+/language/en-GB/en-GB.lib_idna_convert.sys.ini
+/language/en-GB/en-GB.com_mailto.ini
+/language/en-GB/en-GB.lib_joomla.sys.ini
+/language/en-GB/en-GB.lib_phpass.sys.ini
+/language/en-GB/en-GB.lib_phpmailer.sys.ini
+/language/en-GB/en-GB.lib_phputf8.sys.ini
+/language/en-GB/en-GB.lib_simplepie.sys.ini
+/language/en-GB/en-GB.com_media.ini
+/language/en-GB/en-GB.mod_finder.ini
+/language/en-GB/en-GB.com_messages.ini
+/language/en-GB/en-GB.mod_tags_popular.ini
+/language/en-GB/en-GB.mod_tags_popular.sys.ini
+/language/en-GB/en-GB.mod_tags_similar.ini
+/language/en-GB/en-GB.mod_tags_similar.sys.ini
+/language/en-GB/en-GB.mod_finder.sys.ini
+/language/en-GB/en-GB.tpl_beez3.ini
+/language/en-GB/en-GB.tpl_beez3.sys.ini
+/language/en-GB/en-GB.com_newsfeeds.ini
+/language/en-GB/en-GB.tpl_protostar.ini
+/language/en-GB/en-GB.tpl_protostar.sys.ini
+/language/en-GB/en-GB.com_search.ini
+/language/en-GB/en-GB.com_users.ini
+/language/en-GB/en-GB.com_weblinks.ini
+/language/en-GB/en-GB.com_wrapper.ini
+/language/en-GB/en-GB.files_joomla.sys.ini
+/language/en-GB/en-GB.ini
+/language/en-GB/en-GB.lib_joomla.ini
+/language/en-GB/en-GB.localise.php
+/language/en-GB/en-GB.mod_articles_archive.ini
+/language/en-GB/en-GB.mod_articles_archive.sys.ini
+/language/en-GB/en-GB.mod_articles_categories.ini
+/language/en-GB/en-GB.mod_articles_categories.sys.ini
+/language/en-GB/en-GB.mod_articles_category.ini
+/language/en-GB/en-GB.mod_articles_category.sys.ini
+/language/en-GB/en-GB.mod_articles_latest.ini
+/language/en-GB/en-GB.mod_articles_latest.sys.ini
+/language/en-GB/en-GB.mod_articles_news.ini
+/language/en-GB/en-GB.mod_articles_news.sys.ini
+/language/en-GB/en-GB.mod_articles_popular.ini
+/language/en-GB/en-GB.mod_articles_popular.sys.ini
+/language/en-GB/en-GB.mod_banners.ini
+/language/en-GB/en-GB.mod_banners.sys.ini
+/language/en-GB/en-GB.mod_breadcrumbs.ini
+/language/en-GB/en-GB.mod_breadcrumbs.sys.ini
+/language/en-GB/en-GB.mod_custom.ini
+/language/en-GB/en-GB.mod_custom.sys.ini
+/language/en-GB/en-GB.mod_feed.ini
+/language/en-GB/en-GB.mod_feed.sys.ini
+/language/en-GB/en-GB.mod_footer.ini
+/language/en-GB/en-GB.mod_footer.sys.ini
+/language/en-GB/en-GB.mod_languages.ini
+/language/en-GB/en-GB.mod_languages.sys.ini
+/language/en-GB/en-GB.mod_login.ini
+/language/en-GB/en-GB.mod_login.sys.ini
+/language/en-GB/en-GB.mod_menu.ini
+/language/en-GB/en-GB.mod_menu.sys.ini
+/language/en-GB/en-GB.mod_random_image.ini
+/language/en-GB/en-GB.mod_random_image.sys.ini
+/language/en-GB/en-GB.mod_related_items.ini
+/language/en-GB/en-GB.mod_related_items.sys.ini
+/language/en-GB/en-GB.mod_search.ini
+/language/en-GB/en-GB.mod_search.sys.ini
+/language/en-GB/en-GB.mod_stats.ini
+/language/en-GB/en-GB.mod_stats.sys.ini
+/language/en-GB/en-GB.mod_syndicate.ini
+/language/en-GB/en-GB.mod_syndicate.sys.ini
+/language/en-GB/en-GB.mod_users_latest.ini
+/language/en-GB/en-GB.mod_users_latest.sys.ini
+/language/en-GB/en-GB.mod_weblinks.ini
+/language/en-GB/en-GB.mod_weblinks.sys.ini
+/language/en-GB/en-GB.mod_whosonline.ini
+/language/en-GB/en-GB.mod_whosonline.sys.ini
+/language/en-GB/en-GB.mod_wrapper.ini
+/language/en-GB/en-GB.mod_wrapper.sys.ini
+/language/en-GB/en-GB.tpl_atomic.ini
+/language/en-GB/en-GB.tpl_atomic.sys.ini
+/language/en-GB/en-GB.tpl_beez_20.ini
+/language/en-GB/en-GB.tpl_beez_20.sys.ini
+/language/en-GB/en-GB.tpl_beez5.ini
+/language/en-GB/en-GB.tpl_beez5.sys.ini
+/language/en-GB/en-GB.xml
+/language/en-GB/index.html
+/language/en-GB/install.xml
+/language/overrides/*
+/language/index.html
+/layouts/joomla/*
+/layouts/libraries/*
+/layouts/plugins/*
+/layouts/index.html
+/libraries/cms.php
+/libraries/cms/*
+/libraries/fof/*
+/libraries/idna_convert/*
+/libraries/joomla/*
+/libraries/legacy/*
+/libraries/phpass/*
+/libraries/phpmailer/*
+/libraries/phputf8/*
+/libraries/simplepie/*
+/libraries/vendor/*
+/libraries/classmap.php
+/libraries/import.legacy.php
+/libraries/index.html
+/libraries/import.php
+/libraries/loader.php
+/libraries/platform.php
+/logs/*
+/media/cms/*
+/media/com_contenthistory/*
+/media/com_finder/*
+/media/com_joomlaupdate/*
+/media/com_wrapper/*
+/media/contacts/*
+/media/editors/*
+/media/jui/*
+/media/mailto/*
+/media/media/*
+/media/mod_languages/*
+/media/overrider/*
+/media/plg_quickicon_extensionupdate/*
+/media/plg_quickicon_joomlaupdate/*
+/media/plg_system_highlight/*
+/media/system/*
+/media/index.html
+/modules/mod_articles_archive/*
+/modules/mod_articles_categories/*
+/modules/mod_articles_category/*
+/modules/mod_articles_latest/*
+/modules/mod_articles_news/*
+/modules/mod_articles_popular/*
+/modules/mod_banners/*
+/modules/mod_breadcrumbs/*
+/modules/mod_custom/*
+/modules/mod_feed/*
+/modules/mod_finder/*
+/modules/mod_footer/*
+/modules/mod_languages/*
+/modules/mod_login/*
+/modules/mod_menu/*
+/modules/mod_random_image/*
+/modules/mod_related_items/*
+/modules/mod_search/*
+/modules/mod_stats/*
+/modules/mod_syndicate/*
+/modules/mod_tags_popular/*
+/modules/mod_tags_similar/*
+/modules/mod_users_latest/*
+/modules/mod_weblinks/*
+/modules/mod_whosonline/*
+/modules/mod_wrapper/*
+/modules/index.html
+/plugins/authentication/example/*
+/plugins/authentication/gmail/*
+/plugins/authentication/joomla/*
+/plugins/authentication/ldap/*
+/plugins/authentication/cookie/*
+/plugins/authentication/index.html
+/plugins/captcha/recaptcha/*
+/plugins/captcha/index.html
+/plugins/content/emailcloak/*
+/plugins/content/example/*
+/plugins/content/finder/*
+/plugins/content/geshi/*
+/plugins/content/joomla/*
+/plugins/content/loadmodule/*
+/plugins/content/pagebreak/*
+/plugins/content/pagenavigation/*
+/plugins/content/vote/*
+/plugins/content/contact/*
+/plugins/content/index.html
+/plugins/editors/codemirror/*
+/plugins/editors/none/*
+/plugins/editors/tinymce/*
+/plugins/editors/index.html
+/plugins/editors-xtd/article/*
+/plugins/editors-xtd/image/*
+/plugins/editors-xtd/pagebreak/*
+/plugins/editors-xtd/readmore/*
+/plugins/editors-xtd/index.html
+/plugins/extension/example/*
+/plugins/extension/joomla/*
+/plugins/extension/index.html
+/plugins/finder/index.html
+/plugins/finder/categories/*
+/plugins/finder/contacts/*
+/plugins/finder/content/*
+/plugins/finder/newsfeeds/*
+/plugins/finder/tags/*
+/plugins/finder/weblinks/*
+/plugins/installer/*
+/plugins/quickicon/extensionupdate/*
+/plugins/quickicon/joomlaupdate/*
+/plugins/quickicon/index.html
+/plugins/search/categories/*
+/plugins/search/contacts/*
+/plugins/search/content/*
+/plugins/search/newsfeeds/*
+/plugins/search/weblinks/*
+/plugins/search/tags/*
+/plugins/search/index.html
+/plugins/system/cache/*
+/plugins/system/debug/*
+/plugins/system/highlight/*
+/plugins/system/languagecode/*
+/plugins/system/languagefilter/*
+/plugins/system/log/*
+/plugins/system/logout/*
+/plugins/system/p3p/*
+/plugins/system/redirect/*
+/plugins/system/remember/*
+/plugins/system/sef/*
+/plugins/system/index.html
+/plugins/twofactorauth/*
+/plugins/user/contactcreator/*
+/plugins/user/example/*
+/plugins/user/joomla/*
+/plugins/user/profile/*
+/plugins/user/index.html
+/plugins/index.html
+/templates/atomic/*
+/templates/beez3/*
+/templates/beez_20/*
+/templates/beez5/*
+/templates/protostar/*
+/templates/system/*
+/templates/index.html
+/tmp/*
+/configuration.php
+/index.php
+/joomla.xml
+/*.txt
+/robots.txt.dist
diff --git a/vendor/gitignore/KiCad.gitignore b/vendor/gitignore/KiCad.gitignore
new file mode 100644
index 00000000000..606ed1c7b4d
--- /dev/null
+++ b/vendor/gitignore/KiCad.gitignore
@@ -0,0 +1,20 @@
+# For PCBs designed using KiCad: http://www.kicad-pcb.org/
+
+# Temporary files
+*.000
+*.bak
+*.bck
+*.kicad_pcb-bak
+*~
+_autosave-*
+*.tmp
+
+# Netlist files (exported from Eeschema)
+*.net
+
+# Autorouter files (exported from Pcbnew)
+.dsn
+
+# Exported BOM files
+*.xml
+*.csv
diff --git a/vendor/gitignore/Kohana.gitignore b/vendor/gitignore/Kohana.gitignore
new file mode 100644
index 00000000000..8b2ab01a800
--- /dev/null
+++ b/vendor/gitignore/Kohana.gitignore
@@ -0,0 +1,2 @@
+application/cache/*
+application/logs/*
diff --git a/vendor/gitignore/LabVIEW.gitignore b/vendor/gitignore/LabVIEW.gitignore
new file mode 100644
index 00000000000..122450865cf
--- /dev/null
+++ b/vendor/gitignore/LabVIEW.gitignore
@@ -0,0 +1,16 @@
+# Libraries
+*.lvlibp
+*.llb
+
+# Shared objects (inc. Windows DLLs)
+*.dll
+*.so
+*.so.*
+*.dylib
+
+# Executables
+*.exe
+
+# Metadata
+*.aliases
+*.lvlps
diff --git a/vendor/gitignore/Laravel.gitignore b/vendor/gitignore/Laravel.gitignore
new file mode 100644
index 00000000000..c491fa2bc6f
--- /dev/null
+++ b/vendor/gitignore/Laravel.gitignore
@@ -0,0 +1,16 @@
+vendor/
+node_modules/
+
+# Laravel 4 specific
+bootstrap/compiled.php
+app/storage/
+
+# Laravel 5 & Lumen specific
+bootstrap/cache/
+storage/
+.env.*.php
+.env.php
+.env
+
+# Rocketeer PHP task runner and deployment package. https://github.com/rocketeers/rocketeer
+.rocketeer/
diff --git a/vendor/gitignore/Leiningen.gitignore b/vendor/gitignore/Leiningen.gitignore
new file mode 100644
index 00000000000..47fed6c20d9
--- /dev/null
+++ b/vendor/gitignore/Leiningen.gitignore
@@ -0,0 +1,12 @@
+pom.xml
+pom.xml.asc
+*jar
+/lib/
+/classes/
+/target/
+/checkouts/
+.lein-deps-sum
+.lein-repl-history
+.lein-plugins/
+.lein-failures
+.nrepl-port
diff --git a/vendor/gitignore/LemonStand.gitignore b/vendor/gitignore/LemonStand.gitignore
new file mode 100644
index 00000000000..c7d94ad34b0
--- /dev/null
+++ b/vendor/gitignore/LemonStand.gitignore
@@ -0,0 +1,21 @@
+boot.php
+index.php
+install.php
+/config/*
+!/config/config.php
+/controllers/*
+/init/*
+/logs/*
+/phproad/*
+/temp/*
+/uploaded/*
+/installer_files/*
+/modules/backend/*
+/modules/blog/*
+/modules/cms/*
+/modules/core/*
+/modules/session/*
+/modules/shop/*
+/modules/system/*
+/modules/users/*
+# add content_*.php if you don't want erase client changes to content
diff --git a/vendor/gitignore/Lilypond.gitignore b/vendor/gitignore/Lilypond.gitignore
new file mode 100644
index 00000000000..513e6edd9c4
--- /dev/null
+++ b/vendor/gitignore/Lilypond.gitignore
@@ -0,0 +1,6 @@
+*.pdf
+*.ps
+*.midi
+*.mid
+*.log
+*~
diff --git a/vendor/gitignore/Lithium.gitignore b/vendor/gitignore/Lithium.gitignore
new file mode 100644
index 00000000000..7b22568ea89
--- /dev/null
+++ b/vendor/gitignore/Lithium.gitignore
@@ -0,0 +1,2 @@
+libraries/*
+resources/tmp/*
diff --git a/vendor/gitignore/Lua.gitignore b/vendor/gitignore/Lua.gitignore
new file mode 100644
index 00000000000..6fd0a376dec
--- /dev/null
+++ b/vendor/gitignore/Lua.gitignore
@@ -0,0 +1,41 @@
+# Compiled Lua sources
+luac.out
+
+# luarocks build files
+*.src.rock
+*.zip
+*.tar.gz
+
+# Object files
+*.o
+*.os
+*.ko
+*.obj
+*.elf
+
+# Precompiled Headers
+*.gch
+*.pch
+
+# Libraries
+*.lib
+*.a
+*.la
+*.lo
+*.def
+*.exp
+
+# Shared objects (inc. Windows DLLs)
+*.dll
+*.so
+*.so.*
+*.dylib
+
+# Executables
+*.exe
+*.out
+*.app
+*.i*86
+*.x86_64
+*.hex
+
diff --git a/vendor/gitignore/Magento.gitignore b/vendor/gitignore/Magento.gitignore
new file mode 100644
index 00000000000..195c9b7a029
--- /dev/null
+++ b/vendor/gitignore/Magento.gitignore
@@ -0,0 +1,104 @@
+.htaccess.sample
+.modgit/
+.modman/
+app/code/community/Phoenix/Moneybookers/
+app/code/community/Cm/RedisSession/
+app/code/core/
+app/design/adminhtml/default/default/
+app/design/frontend/base/
+app/design/frontend/rwd/
+app/design/frontend/default/blank/
+app/design/frontend/default/default/
+app/design/frontend/default/iphone/
+app/design/frontend/default/modern/
+app/design/frontend/enterprise/default
+app/design/install/
+app/etc/modules/Enterprise_*
+app/etc/modules/Mage_*.xml
+app/etc/modules/Phoenix_Moneybookers.xml
+app/etc/modules/Cm_RedisSession.xml
+app/etc/applied.patches.list
+app/etc/config.xml
+app/etc/enterprise.xml
+app/etc/local.xml.additional
+app/etc/local.xml.template
+app/etc/local.xml
+app/.htaccess
+app/bootstrap.php
+app/locale/en_US/
+app/Mage.php
+/cron.php
+cron.sh
+dev/.htaccess
+dev/tests/functional/
+downloader/
+errors/
+favicon.ico
+/get.php
+includes/
+/index.php
+index.php.sample
+/install.php
+js/blank.html
+js/calendar/
+js/enterprise/
+js/extjs/
+js/firebug/
+js/flash/
+js/index.php
+js/jscolor/
+js/lib/
+js/mage/
+js/prototype/
+js/scriptaculous/
+js/spacer.gif
+js/tiny_mce/
+js/varien/
+lib/3Dsecure/
+lib/Apache/
+lib/flex/
+lib/googlecheckout/
+lib/.htaccess
+lib/LinLibertineFont/
+lib/Mage/
+lib/PEAR/
+lib/Pelago/
+lib/phpseclib/
+lib/Varien/
+lib/Zend/
+lib/Cm/
+lib/Credis/
+lib/Magento/
+LICENSE_AFL.txt
+LICENSE.html
+LICENSE.txt
+LICENSE_EE*
+/mage
+media/
+/api.php
+nbproject/
+pear
+pear/
+php.ini.sample
+pkginfo/
+RELEASE_NOTES.txt
+shell/.htaccess
+shell/abstract.php
+shell/compiler.php
+shell/indexer.php
+shell/log.php
+sitemap.xml
+skin/adminhtml/default/default/
+skin/adminhtml/default/enterprise
+skin/frontend/base/
+skin/frontend/rwd/
+skin/frontend/default/blank/
+skin/frontend/default/blue/
+skin/frontend/default/default/
+skin/frontend/default/french/
+skin/frontend/default/german/
+skin/frontend/default/iphone/
+skin/frontend/default/modern/
+skin/frontend/enterprise
+skin/install/
+var/
diff --git a/vendor/gitignore/Maven.gitignore b/vendor/gitignore/Maven.gitignore
new file mode 100644
index 00000000000..1cdc9f7fd45
--- /dev/null
+++ b/vendor/gitignore/Maven.gitignore
@@ -0,0 +1,9 @@
+target/
+pom.xml.tag
+pom.xml.releaseBackup
+pom.xml.versionsBackup
+pom.xml.next
+release.properties
+dependency-reduced-pom.xml
+buildNumber.properties
+.mvn/timing.properties
diff --git a/vendor/gitignore/Mercury.gitignore b/vendor/gitignore/Mercury.gitignore
new file mode 100644
index 00000000000..70ec8693971
--- /dev/null
+++ b/vendor/gitignore/Mercury.gitignore
@@ -0,0 +1,13 @@
+Mercury/
+Mercury.modules
+*.mh
+*.err
+*.init
+*.dll
+*.exe
+*.a
+*.so
+*.dylib
+*.beams
+*.d
+*.c_date
diff --git a/vendor/gitignore/MetaProgrammingSystem.gitignore b/vendor/gitignore/MetaProgrammingSystem.gitignore
new file mode 100644
index 00000000000..3e75841041c
--- /dev/null
+++ b/vendor/gitignore/MetaProgrammingSystem.gitignore
@@ -0,0 +1,16 @@
+workspace.xml
+junitvmwatcher*.properties
+build.properties
+
+# generated java classes and java source files
+# manually add any custom artifacts that can't be generated from the models
+# http://confluence.jetbrains.com/display/MPSD25/HowTo+--+MPS+and+Git
+classes_gen
+source_gen
+source_gen.caches
+
+# generated test code and test results
+test_gen
+test_gen.caches
+TEST-*.xml
+junit*.properties
diff --git a/vendor/gitignore/Nanoc.gitignore b/vendor/gitignore/Nanoc.gitignore
new file mode 100644
index 00000000000..abc21828a3e
--- /dev/null
+++ b/vendor/gitignore/Nanoc.gitignore
@@ -0,0 +1,10 @@
+# For projects using nanoc (http://nanoc.ws/)
+
+# Default location for output, needs to match output_dir's value found in config.yaml
+output/
+
+# Temporary file directory
+tmp/
+
+# Crash Log
+crash.log
diff --git a/vendor/gitignore/Nim.gitignore b/vendor/gitignore/Nim.gitignore
new file mode 100644
index 00000000000..67d9b34c6ce
--- /dev/null
+++ b/vendor/gitignore/Nim.gitignore
@@ -0,0 +1 @@
+nimcache/
diff --git a/vendor/gitignore/Node.gitignore b/vendor/gitignore/Node.gitignore
new file mode 100644
index 00000000000..5148e527a7e
--- /dev/null
+++ b/vendor/gitignore/Node.gitignore
@@ -0,0 +1,37 @@
+# Logs
+logs
+*.log
+npm-debug.log*
+
+# Runtime data
+pids
+*.pid
+*.seed
+
+# Directory for instrumented libs generated by jscoverage/JSCover
+lib-cov
+
+# Coverage directory used by tools like istanbul
+coverage
+
+# nyc test coverage
+.nyc_output
+
+# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
+.grunt
+
+# node-waf configuration
+.lock-wscript
+
+# Compiled binary addons (http://nodejs.org/api/addons.html)
+build/Release
+
+# Dependency directories
+node_modules
+jspm_packages
+
+# Optional npm cache directory
+.npm
+
+# Optional REPL history
+.node_repl_history
diff --git a/vendor/gitignore/OCaml.gitignore b/vendor/gitignore/OCaml.gitignore
new file mode 100644
index 00000000000..f7817ae5c36
--- /dev/null
+++ b/vendor/gitignore/OCaml.gitignore
@@ -0,0 +1,20 @@
+*.annot
+*.cmo
+*.cma
+*.cmi
+*.a
+*.o
+*.cmx
+*.cmxs
+*.cmxa
+
+# ocamlbuild working directory
+_build/
+
+# ocamlbuild targets
+*.byte
+*.native
+
+# oasis generated files
+setup.data
+setup.log
diff --git a/vendor/gitignore/Objective-C.gitignore b/vendor/gitignore/Objective-C.gitignore
new file mode 100644
index 00000000000..3020bc327a7
--- /dev/null
+++ b/vendor/gitignore/Objective-C.gitignore
@@ -0,0 +1,51 @@
+# Xcode
+#
+# gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore
+
+## Build generated
+build/
+DerivedData/
+
+## Various settings
+*.pbxuser
+!default.pbxuser
+*.mode1v3
+!default.mode1v3
+*.mode2v3
+!default.mode2v3
+*.perspectivev3
+!default.perspectivev3
+xcuserdata/
+
+## Other
+*.moved-aside
+*.xcuserstate
+
+## Obj-C/Swift specific
+*.hmap
+*.ipa
+
+# CocoaPods
+#
+# We recommend against adding the Pods directory to your .gitignore. However
+# you should judge for yourself, the pros and cons are mentioned at:
+# https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
+#
+# Pods/
+
+# Carthage
+#
+# Add this line if you want to avoid checking in source code from Carthage dependencies.
+# Carthage/Checkouts
+
+Carthage/Build
+
+# fastlane
+#
+# It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the
+# screenshots whenever they are needed.
+# For more information about the recommended setup visit:
+# https://github.com/fastlane/fastlane/blob/master/fastlane/docs/Gitignore.md
+
+fastlane/report.xml
+fastlane/screenshots
diff --git a/vendor/gitignore/Opa.gitignore b/vendor/gitignore/Opa.gitignore
new file mode 100644
index 00000000000..74c6219ceda
--- /dev/null
+++ b/vendor/gitignore/Opa.gitignore
@@ -0,0 +1,13 @@
+_build
+_tracks
+
+opa-debug-js
+
+*.opp
+*.opx
+*.opx.broken
+*.dump
+*.api
+*.api-txt
+*.exe
+*.log
diff --git a/vendor/gitignore/OpenCart.gitignore b/vendor/gitignore/OpenCart.gitignore
new file mode 100644
index 00000000000..28e45aa6aac
--- /dev/null
+++ b/vendor/gitignore/OpenCart.gitignore
@@ -0,0 +1,13 @@
+.htaccess
+/config.php
+admin/config.php
+
+!index.html
+
+download/
+image/data/
+image/cache/
+system/cache/
+system/logs/
+
+system/storage/
diff --git a/vendor/gitignore/OracleForms.gitignore b/vendor/gitignore/OracleForms.gitignore
new file mode 100644
index 00000000000..699a4940118
--- /dev/null
+++ b/vendor/gitignore/OracleForms.gitignore
@@ -0,0 +1,8 @@
+# Compiled Form Modules
+*.fmx
+
+# Compiled Menu Modules
+*.mmx
+
+# Compiled Pre-Linked Libraries
+*.plx
diff --git a/vendor/gitignore/Packer.gitignore b/vendor/gitignore/Packer.gitignore
new file mode 100644
index 00000000000..1b7a03efdd7
--- /dev/null
+++ b/vendor/gitignore/Packer.gitignore
@@ -0,0 +1,5 @@
+# Cache objects
+packer_cache/
+
+# For built boxes
+*.box
diff --git a/vendor/gitignore/Perl.gitignore b/vendor/gitignore/Perl.gitignore
new file mode 100644
index 00000000000..ae2ad536abb
--- /dev/null
+++ b/vendor/gitignore/Perl.gitignore
@@ -0,0 +1,20 @@
+/blib/
+/.build/
+_build/
+cover_db/
+inc/
+Build
+!Build/
+Build.bat
+.last_cover_stats
+/Makefile
+/Makefile.old
+/MANIFEST.bak
+/META.yml
+/META.json
+/MYMETA.*
+nytprof.out
+/pm_to_blib
+*.o
+*.bs
+/_eumm/
diff --git a/vendor/gitignore/Phalcon.gitignore b/vendor/gitignore/Phalcon.gitignore
new file mode 100644
index 00000000000..6ffe3aa220a
--- /dev/null
+++ b/vendor/gitignore/Phalcon.gitignore
@@ -0,0 +1,2 @@
+/cache/
+/config/development/
diff --git a/vendor/gitignore/PlayFramework.gitignore b/vendor/gitignore/PlayFramework.gitignore
new file mode 100644
index 00000000000..6d67f119175
--- /dev/null
+++ b/vendor/gitignore/PlayFramework.gitignore
@@ -0,0 +1,15 @@
+# Ignore Play! working directory #
+bin/
+/db
+.eclipse
+/lib/
+/logs/
+/modules
+/project/target
+/target
+tmp/
+test-result
+server.pid
+*.eml
+/dist/
+.cache
diff --git a/vendor/gitignore/Plone.gitignore b/vendor/gitignore/Plone.gitignore
new file mode 100644
index 00000000000..770a8681ac3
--- /dev/null
+++ b/vendor/gitignore/Plone.gitignore
@@ -0,0 +1,18 @@
+*.pyc
+*.pyo
+*.tmp*
+*.mo
+*.egg
+*.EGG
+*.egg-info
+*.EGG-INFO
+.*.cfg
+bin/
+build/
+develop-eggs/
+downloads/
+eggs/
+fake-eggs/
+parts/
+dist/
+var/
diff --git a/vendor/gitignore/Prestashop.gitignore b/vendor/gitignore/Prestashop.gitignore
new file mode 100644
index 00000000000..7c6ae1e31cc
--- /dev/null
+++ b/vendor/gitignore/Prestashop.gitignore
@@ -0,0 +1,32 @@
+# Private files
+# The following files contain your database credentials and other personal data.
+
+config/settings.*.php
+
+# Cache, temp and generated files
+# The following files are generated by PrestaShop.
+
+admin-dev/autoupgrade/
+/cache/
+!/cache/index.php
+!/cache/cachefs/index.php
+!/cache/purifier/index.php
+!/cache/push/index.php
+!/cache/sandbox/index.php
+!/cache/smarty/index.php
+!/cache/tcpdf/index.php
+config/xml/*.xml
+/log/*
+*sitemap.xml
+themes/*/cache/
+modules/*/config*.xml
+
+# Site content
+# The following folders contain product images, virtual products, CSV's, etc.
+
+admin-dev/backups/
+admin-dev/export/
+admin-dev/import/
+download/
+/img/*
+upload/
diff --git a/vendor/gitignore/Processing.gitignore b/vendor/gitignore/Processing.gitignore
new file mode 100644
index 00000000000..85f269a89f6
--- /dev/null
+++ b/vendor/gitignore/Processing.gitignore
@@ -0,0 +1,7 @@
+.DS_Store
+applet
+application.linux32
+application.linux64
+application.windows32
+application.windows64
+application.macosx
diff --git a/vendor/gitignore/Python.gitignore b/vendor/gitignore/Python.gitignore
new file mode 100644
index 00000000000..72364f99fe4
--- /dev/null
+++ b/vendor/gitignore/Python.gitignore
@@ -0,0 +1,89 @@
+# Byte-compiled / optimized / DLL files
+__pycache__/
+*.py[cod]
+*$py.class
+
+# C extensions
+*.so
+
+# Distribution / packaging
+.Python
+env/
+build/
+develop-eggs/
+dist/
+downloads/
+eggs/
+.eggs/
+lib/
+lib64/
+parts/
+sdist/
+var/
+*.egg-info/
+.installed.cfg
+*.egg
+
+# PyInstaller
+# Usually these files are written by a python script from a template
+# before PyInstaller builds the exe, so as to inject date/other infos into it.
+*.manifest
+*.spec
+
+# Installer logs
+pip-log.txt
+pip-delete-this-directory.txt
+
+# Unit test / coverage reports
+htmlcov/
+.tox/
+.coverage
+.coverage.*
+.cache
+nosetests.xml
+coverage.xml
+*,cover
+.hypothesis/
+
+# Translations
+*.mo
+*.pot
+
+# Django stuff:
+*.log
+local_settings.py
+
+# Flask stuff:
+instance/
+.webassets-cache
+
+# Scrapy stuff:
+.scrapy
+
+# Sphinx documentation
+docs/_build/
+
+# PyBuilder
+target/
+
+# IPython Notebook
+.ipynb_checkpoints
+
+# pyenv
+.python-version
+
+# celery beat schedule file
+celerybeat-schedule
+
+# dotenv
+.env
+
+# virtualenv
+venv/
+ENV/
+
+# Spyder project settings
+.spyderproject
+
+# Rope project settings
+.ropeproject
diff --git a/vendor/gitignore/Qooxdoo.gitignore b/vendor/gitignore/Qooxdoo.gitignore
new file mode 100644
index 00000000000..d0c64102d85
--- /dev/null
+++ b/vendor/gitignore/Qooxdoo.gitignore
@@ -0,0 +1,5 @@
+cache
+cache-downloads
+inspector
+api
+source/inspector.html
diff --git a/vendor/gitignore/Qt.gitignore b/vendor/gitignore/Qt.gitignore
new file mode 100644
index 00000000000..fa24b2efee8
--- /dev/null
+++ b/vendor/gitignore/Qt.gitignore
@@ -0,0 +1,38 @@
+# C++ objects and libs
+
+*.slo
+*.lo
+*.o
+*.a
+*.la
+*.lai
+*.so
+*.dll
+*.dylib
+
+# Qt-es
+
+/.qmake.cache
+/.qmake.stash
+*.pro.user
+*.pro.user.*
+*.qbs.user
+*.qbs.user.*
+*.moc
+moc_*.cpp
+qrc_*.cpp
+ui_*.h
+Makefile*
+*build-*
+
+# QtCreator
+
+*.autosave
+
+# QtCtreator Qml
+*.qmlproject.user
+*.qmlproject.user.*
+
+# QtCtreator CMake
+CMakeLists.txt.user
+
diff --git a/vendor/gitignore/R.gitignore b/vendor/gitignore/R.gitignore
new file mode 100644
index 00000000000..fcff087aebb
--- /dev/null
+++ b/vendor/gitignore/R.gitignore
@@ -0,0 +1,33 @@
+# History files
+.Rhistory
+.Rapp.history
+
+# Session Data files
+.RData
+
+# Example code in package build process
+*-Ex.R
+
+# Output files from R CMD build
+/*.tar.gz
+
+# Output files from R CMD check
+/*.Rcheck/
+
+# RStudio files
+.Rproj.user/
+
+# produced vignettes
+vignettes/*.html
+vignettes/*.pdf
+
+# OAuth2 token, see https://github.com/hadley/httr/releases/tag/v0.3
+.httr-oauth
+
+# knitr and R markdown default cache directories
+/*_cache/
+/cache/
+
+# Temporary files created by R markdown
+*.utf8.md
+*.knit.md
diff --git a/vendor/gitignore/README.md b/vendor/gitignore/README.md
new file mode 100644
index 00000000000..43131e815cc
--- /dev/null
+++ b/vendor/gitignore/README.md
@@ -0,0 +1,14 @@
+# .gitignore templates
+
+This directory contains language-specific .gitignore templates that are used by GitLab.
+
+These files were automatically pulled from [this repository](https://github.com/github/gitignore).
+Please submit pull requests to that repository. There is no need to edit the files in this directory.
+
+## Bulk Update
+
+To update this directory with the latest changes in the repository, run:
+
+```sh
+bundle exec rake gitlab:update_gitignore
+```
diff --git a/vendor/gitignore/ROS.gitignore b/vendor/gitignore/ROS.gitignore
new file mode 100644
index 00000000000..f8bcd117371
--- /dev/null
+++ b/vendor/gitignore/ROS.gitignore
@@ -0,0 +1,47 @@
+build/
+bin/
+lib/
+msg_gen/
+srv_gen/
+msg/*Action.msg
+msg/*ActionFeedback.msg
+msg/*ActionGoal.msg
+msg/*ActionResult.msg
+msg/*Feedback.msg
+msg/*Goal.msg
+msg/*Result.msg
+msg/_*.py
+
+# Generated by dynamic reconfigure
+*.cfgc
+/cfg/cpp/
+/cfg/*.py
+
+# Ignore generated docs
+*.dox
+*.wikidoc
+
+# eclipse stuff
+.project
+.cproject
+
+# qcreator stuff
+CMakeLists.txt.user
+
+srv/_*.py
+*.pcd
+*.pyc
+qtcreator-*
+*.user
+
+/planning/cfg
+/planning/docs
+/planning/src
+
+*~
+
+# Emacs
+.#*
+
+# Catkin custom files
+CATKIN_IGNORE
diff --git a/vendor/gitignore/Rails.gitignore b/vendor/gitignore/Rails.gitignore
new file mode 100644
index 00000000000..2121e0a8038
--- /dev/null
+++ b/vendor/gitignore/Rails.gitignore
@@ -0,0 +1,38 @@
+*.rbc
+capybara-*.html
+.rspec
+/log
+/tmp
+/db/*.sqlite3
+/db/*.sqlite3-journal
+/public/system
+/coverage/
+/spec/tmp
+**.orig
+rerun.txt
+pickle-email-*.html
+
+# TODO Comment out these rules if you are OK with secrets being uploaded to the repo
+config/initializers/secret_token.rb
+config/secrets.yml
+
+## Environment normalization:
+/.bundle
+/vendor/bundle
+
+# these should all be checked in to normalize the environment:
+# Gemfile.lock, .ruby-version, .ruby-gemset
+
+# unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
+.rvmrc
+
+# if using bower-rails ignore default bower_components path bower.json files
+/vendor/assets/bower_components
+*.bowerrc
+bower.json
+
+# Ignore pow environment settings
+.powenv
+
+# Ignore Byebug command history file.
+.byebug_history
diff --git a/vendor/gitignore/RhodesRhomobile.gitignore b/vendor/gitignore/RhodesRhomobile.gitignore
new file mode 100644
index 00000000000..a211dcc3b0f
--- /dev/null
+++ b/vendor/gitignore/RhodesRhomobile.gitignore
@@ -0,0 +1,9 @@
+rholog-*
+sim-*
+bin/libs
+bin/RhoBundle
+bin/tmp
+bin/target
+bin/*.ap_
+*.o
+*.jar
diff --git a/vendor/gitignore/Ruby.gitignore b/vendor/gitignore/Ruby.gitignore
new file mode 100644
index 00000000000..5e1422c9c3f
--- /dev/null
+++ b/vendor/gitignore/Ruby.gitignore
@@ -0,0 +1,50 @@
+*.gem
+*.rbc
+/.config
+/coverage/
+/InstalledFiles
+/pkg/
+/spec/reports/
+/spec/examples.txt
+/test/tmp/
+/test/version_tmp/
+/tmp/
+
+# Used by dotenv library to load environment variables.
+# .env
+
+## Specific to RubyMotion:
+.dat*
+.repl_history
+build/
+*.bridgesupport
+build-iPhoneOS/
+build-iPhoneSimulator/
+
+## Specific to RubyMotion (use of CocoaPods):
+#
+# We recommend against adding the Pods directory to your .gitignore. However
+# you should judge for yourself, the pros and cons are mentioned at:
+# https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
+#
+# vendor/Pods/
+
+## Documentation cache and generated files:
+/.yardoc/
+/_yardoc/
+/doc/
+/rdoc/
+
+## Environment normalization:
+/.bundle/
+/vendor/bundle
+/lib/bundler/man/
+
+# for a library or gem, you might want to ignore these files since the code is
+# intended to run in multiple environments; otherwise, check them in:
+# Gemfile.lock
+# .ruby-version
+# .ruby-gemset
+
+# unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
+.rvmrc
diff --git a/vendor/gitignore/Rust.gitignore b/vendor/gitignore/Rust.gitignore
new file mode 100644
index 00000000000..cb14a420640
--- /dev/null
+++ b/vendor/gitignore/Rust.gitignore
@@ -0,0 +1,7 @@
+# Generated by Cargo
+# will have compiled files and executables
+/target/
+
+# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries
+# More information here http://doc.crates.io/guide.html#cargotoml-vs-cargolock
+Cargo.lock
diff --git a/vendor/gitignore/SCons.gitignore b/vendor/gitignore/SCons.gitignore
new file mode 100644
index 00000000000..39d9743a082
--- /dev/null
+++ b/vendor/gitignore/SCons.gitignore
@@ -0,0 +1,2 @@
+# for projects that use SCons for building: http://http://www.scons.org/
+.sconsign.dblite
diff --git a/vendor/gitignore/Sass.gitignore b/vendor/gitignore/Sass.gitignore
new file mode 100644
index 00000000000..486b32ce90c
--- /dev/null
+++ b/vendor/gitignore/Sass.gitignore
@@ -0,0 +1,2 @@
+.sass-cache/
+*.css.map
diff --git a/vendor/gitignore/Scala.gitignore b/vendor/gitignore/Scala.gitignore
new file mode 100644
index 00000000000..c58d83b3189
--- /dev/null
+++ b/vendor/gitignore/Scala.gitignore
@@ -0,0 +1,17 @@
+*.class
+*.log
+
+# sbt specific
+.cache
+.history
+.lib/
+dist/*
+target/
+lib_managed/
+src_managed/
+project/boot/
+project/plugins/project/
+
+# Scala-IDE specific
+.scala_dependencies
+.worksheet
diff --git a/vendor/gitignore/Scheme.gitignore b/vendor/gitignore/Scheme.gitignore
new file mode 100644
index 00000000000..cbb89d78da5
--- /dev/null
+++ b/vendor/gitignore/Scheme.gitignore
@@ -0,0 +1,7 @@
+*.ss~
+*.ss#*
+.#*.ss
+
+*.scm~
+*.scm#*
+.#*.scm
diff --git a/vendor/gitignore/Scrivener.gitignore b/vendor/gitignore/Scrivener.gitignore
new file mode 100644
index 00000000000..3b39c66ba12
--- /dev/null
+++ b/vendor/gitignore/Scrivener.gitignore
@@ -0,0 +1,7 @@
+/Files/binder.autosave
+/Files/binder.backup
+/Files/search.indexes
+/Files/user.lock
+/Files/Docs/docs.checksum
+/QuickLook/
+/Settings/ui.plist
diff --git a/vendor/gitignore/Sdcc.gitignore b/vendor/gitignore/Sdcc.gitignore
new file mode 100644
index 00000000000..07ee7d59aba
--- /dev/null
+++ b/vendor/gitignore/Sdcc.gitignore
@@ -0,0 +1,8 @@
+# SDCC stuff
+*.lnk
+*.lst
+*.map
+*.mem
+*.rel
+*.rst
+*.sym
diff --git a/vendor/gitignore/SeamGen.gitignore b/vendor/gitignore/SeamGen.gitignore
new file mode 100644
index 00000000000..a418cf376c5
--- /dev/null
+++ b/vendor/gitignore/SeamGen.gitignore
@@ -0,0 +1,26 @@
+/bootstrap/data
+/bootstrap/tmp
+/classes/
+/dist/
+/exploded-archives/
+/test-build/
+/test-output/
+/test-report/
+/target/
+temp-testng-customsuite.xml
+
+# based on http://stackoverflow.com/a/8865858/422476 I am removing inline comments
+
+#/classes/ all class files
+#/dist/ contains generated war files for deployment
+#/exploded-archives/ war content generation during deploy (or explode)
+#/test-build/ test compilation (ant target for Seam)
+#/test-output/ test results
+#/test-report/ test report generation for, e.g., Hudson
+#/target/ maven output folder
+#temp-testng-customsuite.xml generated when running test cases under Eclipse
+
+# Thanks to @VonC and @kraftan for their helpful answers on a related question
+# on StackOverflow.com:
+# http://stackoverflow.com/questions/4176687
+# /what-is-the-recommended-source-control-ignore-pattern-for-seam-projects
diff --git a/vendor/gitignore/SketchUp.gitignore b/vendor/gitignore/SketchUp.gitignore
new file mode 100644
index 00000000000..5160df3c6bf
--- /dev/null
+++ b/vendor/gitignore/SketchUp.gitignore
@@ -0,0 +1 @@
+*.skb
diff --git a/vendor/gitignore/Smalltalk.gitignore b/vendor/gitignore/Smalltalk.gitignore
new file mode 100644
index 00000000000..75272b23472
--- /dev/null
+++ b/vendor/gitignore/Smalltalk.gitignore
@@ -0,0 +1,18 @@
+# changes file
+*.changes
+
+# system image
+*.image
+
+# Pharo Smalltalk Debug log file
+PharoDebug.log
+
+# Squeak Smalltalk Debug log file
+SqueakDebug.log
+
+# Monticello package cache
+/package-cache
+
+# Metacello-github cache
+/github-cache
+github-*.zip
diff --git a/vendor/gitignore/Stella.gitignore b/vendor/gitignore/Stella.gitignore
new file mode 100644
index 00000000000..402a5438373
--- /dev/null
+++ b/vendor/gitignore/Stella.gitignore
@@ -0,0 +1,12 @@
+# Atari 2600 (Stella) support for multiple assemblers
+# - DASM
+# - CC65
+
+# Assembled binaries and object directories
+obj/
+a.out
+*.bin
+*.a26
+
+# Add in special Atari 7800-based binaries for good measure
+*.a78
diff --git a/vendor/gitignore/SugarCRM.gitignore b/vendor/gitignore/SugarCRM.gitignore
new file mode 100644
index 00000000000..842c3ec518b
--- /dev/null
+++ b/vendor/gitignore/SugarCRM.gitignore
@@ -0,0 +1,25 @@
+## SugarCRM
+# Ignore custom .htaccess stuff.
+/.htaccess
+# Ignore the cache directory completely.
+# This will break the current behaviour. Which was often leading to
+# the misuse of the repository as backup replacement.
+# For development the cache directory can be safely ignored and
+# therefore it is ignored.
+/cache/
+# Ignore some files and directories from the custom directory.
+/custom/history/
+/custom/modulebuilder/
+/custom/working/
+/custom/modules/*/Ext/
+/custom/application/Ext/
+# Custom configuration should also be ignored.
+/config.php
+/config_override.php
+# The silent upgrade scripts aren't needed.
+/silentUpgrade*.php
+# Logs files can safely be ignored.
+*.log
+# Ignore the new upload directories.
+/upload/
+/upload_backup/
diff --git a/vendor/gitignore/Swift.gitignore b/vendor/gitignore/Swift.gitignore
new file mode 100644
index 00000000000..8a29fa52af4
--- /dev/null
+++ b/vendor/gitignore/Swift.gitignore
@@ -0,0 +1,63 @@
+# Xcode
+#
+# gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore
+
+## Build generated
+build/
+DerivedData/
+
+## Various settings
+*.pbxuser
+!default.pbxuser
+*.mode1v3
+!default.mode1v3
+*.mode2v3
+!default.mode2v3
+*.perspectivev3
+!default.perspectivev3
+xcuserdata/
+
+## Other
+*.moved-aside
+*.xcuserstate
+
+## Obj-C/Swift specific
+*.hmap
+*.ipa
+
+## Playgrounds
+timeline.xctimeline
+playground.xcworkspace
+
+# Swift Package Manager
+#
+# Add this line if you want to avoid checking in source code from Swift Package Manager dependencies.
+# Packages/
+.build/
+
+# CocoaPods
+#
+# We recommend against adding the Pods directory to your .gitignore. However
+# you should judge for yourself, the pros and cons are mentioned at:
+# https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
+#
+# Pods/
+
+# Carthage
+#
+# Add this line if you want to avoid checking in source code from Carthage dependencies.
+# Carthage/Checkouts
+
+Carthage/Build
+
+# fastlane
+#
+# It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the
+# screenshots whenever they are needed.
+# For more information about the recommended setup visit:
+# https://github.com/fastlane/fastlane/blob/master/fastlane/docs/Gitignore.md
+
+fastlane/report.xml
+fastlane/Preview.html
+fastlane/screenshots
+fastlane/test_output
diff --git a/vendor/gitignore/Symfony.gitignore b/vendor/gitignore/Symfony.gitignore
new file mode 100644
index 00000000000..7d56f982f81
--- /dev/null
+++ b/vendor/gitignore/Symfony.gitignore
@@ -0,0 +1,48 @@
+# Cache and logs (Symfony2)
+/app/cache/*
+/app/logs/*
+!app/cache/.gitkeep
+!app/logs/.gitkeep
+
+# Email spool folder
+/app/spool/*
+
+# Cache, session files and logs (Symfony3)
+/var/cache/*
+/var/logs/*
+/var/sessions/*
+!var/cache/.gitkeep
+!var/logs/.gitkeep
+!var/sessions/.gitkeep
+
+# Parameters
+/app/config/parameters.yml
+/app/config/parameters.ini
+
+# Managed by Composer
+/app/bootstrap.php.cache
+/var/bootstrap.php.cache
+/bin/*
+!bin/console
+!bin/symfony_requirements
+/vendor/
+
+# Assets and user uploads
+/web/bundles/
+/web/uploads/
+
+# Assets managed by Bower
+/web/assets/vendor/
+
+# PHPUnit
+/app/phpunit.xml
+/phpunit.xml
+
+# Build data
+/build/
+
+# Composer PHAR
+/composer.phar
+
+# Backup entities generated with doctrine:generate:entities command
+*/Entity/*~
diff --git a/vendor/gitignore/SymphonyCMS.gitignore b/vendor/gitignore/SymphonyCMS.gitignore
new file mode 100644
index 00000000000..671c7ff9e32
--- /dev/null
+++ b/vendor/gitignore/SymphonyCMS.gitignore
@@ -0,0 +1,6 @@
+manifest/cache/
+manifest/logs/
+manifest/tmp/
+symphony/
+workspace/uploads/
+install-log.txt
diff --git a/vendor/gitignore/TeX.gitignore b/vendor/gitignore/TeX.gitignore
new file mode 100644
index 00000000000..4123a577c47
--- /dev/null
+++ b/vendor/gitignore/TeX.gitignore
@@ -0,0 +1,180 @@
+## Core latex/pdflatex auxiliary files:
+*.aux
+*.lof
+*.log
+*.lot
+*.fls
+*.out
+*.toc
+*.fmt
+*.fot
+*.cb
+*.cb2
+
+## Intermediate documents:
+*.dvi
+*-converted-to.*
+# these rules might exclude image files for figures etc.
+# *.ps
+# *.eps
+# *.pdf
+
+## Bibliography auxiliary files (bibtex/biblatex/biber):
+*.bbl
+*.bcf
+*.blg
+*-blx.aux
+*-blx.bib
+*.brf
+*.run.xml
+
+## Build tool auxiliary files:
+*.fdb_latexmk
+*.synctex
+*.synctex.gz
+*.synctex.gz(busy)
+*.pdfsync
+
+## Auxiliary and intermediate files from other packages:
+# algorithms
+*.alg
+*.loa
+
+# achemso
+acs-*.bib
+
+# amsthm
+*.thm
+
+# beamer
+*.nav
+*.snm
+*.vrb
+
+# cprotect
+*.cpt
+
+# fixme
+*.lox
+
+#(r)(e)ledmac/(r)(e)ledpar
+*.end
+*.?end
+*.[1-9]
+*.[1-9][0-9]
+*.[1-9][0-9][0-9]
+*.[1-9]R
+*.[1-9][0-9]R
+*.[1-9][0-9][0-9]R
+*.eledsec[1-9]
+*.eledsec[1-9]R
+*.eledsec[1-9][0-9]
+*.eledsec[1-9][0-9]R
+*.eledsec[1-9][0-9][0-9]
+*.eledsec[1-9][0-9][0-9]R
+
+# glossaries
+*.acn
+*.acr
+*.glg
+*.glo
+*.gls
+*.glsdefs
+
+# gnuplottex
+*-gnuplottex-*
+
+# hyperref
+*.brf
+
+# knitr
+*-concordance.tex
+# TODO Comment the next line if you want to keep your tikz graphics files
+*.tikz
+*-tikzDictionary
+
+# listings
+*.lol
+
+# makeidx
+*.idx
+*.ilg
+*.ind
+*.ist
+
+# minitoc
+*.maf
+*.mlf
+*.mlt
+*.mtc
+*.mtc[0-9]
+*.mtc[1-9][0-9]
+
+# minted
+_minted*
+*.pyg
+
+# morewrites
+*.mw
+
+# mylatexformat
+*.fmt
+
+# nomencl
+*.nlo
+
+# sagetex
+*.sagetex.sage
+*.sagetex.py
+*.sagetex.scmd
+
+# sympy
+*.sout
+*.sympy
+sympy-plots-for-*.tex/
+
+# pdfcomment
+*.upa
+*.upb
+
+# pythontex
+*.pytxcode
+pythontex-files-*/
+
+# thmtools
+*.loe
+
+# TikZ & PGF
+*.dpth
+*.md5
+*.auxlock
+
+# todonotes
+*.tdo
+
+# xindy
+*.xdy
+
+# xypic precompiled matrices
+*.xyc
+
+# endfloat
+*.ttt
+*.fff
+
+# Latexian
+TSWLatexianTemp*
+
+## Editors:
+# WinEdt
+*.bak
+*.sav
+
+# Texpad
+.texpadtmp
+
+# Kile
+*.backup
+
+# KBibTeX
+*~[0-9]*
diff --git a/vendor/gitignore/Terraform.gitignore b/vendor/gitignore/Terraform.gitignore
new file mode 100644
index 00000000000..7868d16d216
--- /dev/null
+++ b/vendor/gitignore/Terraform.gitignore
@@ -0,0 +1,3 @@
+# Compiled files
+*.tfstate
+*.tfstate.backup
diff --git a/vendor/gitignore/Textpattern.gitignore b/vendor/gitignore/Textpattern.gitignore
new file mode 100644
index 00000000000..3805636d622
--- /dev/null
+++ b/vendor/gitignore/Textpattern.gitignore
@@ -0,0 +1,11 @@
+.htaccess
+css.php
+rpc/
+sites/site*/admin/
+sites/site*/private/
+sites/site*/public/admin/
+sites/site*/public/setup/
+sites/site*/public/theme/
+textpattern/
+HISTORY.txt
+README.txt
diff --git a/vendor/gitignore/TurboGears2.gitignore b/vendor/gitignore/TurboGears2.gitignore
new file mode 100644
index 00000000000..122b3de221f
--- /dev/null
+++ b/vendor/gitignore/TurboGears2.gitignore
@@ -0,0 +1,20 @@
+*.py[co]
+
+# Default development database
+devdata.db
+
+# Default data directory
+data/*
+
+# Packages
+*.egg
+*.egg-info
+dist
+build
+
+# Installer logs
+pip-log.txt
+
+# Unit test / coverage reports
+.coverage
+.tox
diff --git a/vendor/gitignore/Typo3.gitignore b/vendor/gitignore/Typo3.gitignore
new file mode 100644
index 00000000000..cb024fefe99
--- /dev/null
+++ b/vendor/gitignore/Typo3.gitignore
@@ -0,0 +1,20 @@
+## TYPO3 v6.2
+# Ignore several upload and file directories.
+/fileadmin/user_upload/
+/fileadmin/_temp_/
+/fileadmin/_processed_/
+/uploads/
+# Ignore cache
+/typo3conf/temp_CACHED*
+/typo3conf/temp_fieldInfo.php
+/typo3conf/deprecation_*.log
+/typo3conf/AdditionalConfiguration.php
+# Ignore system folders, you should have them symlinked.
+# If not comment out the following entries.
+/typo3
+/typo3_src
+/typo3_src-*
+/.htaccess
+/index.php
+# Ignore temp directory.
+/typo3temp/
diff --git a/vendor/gitignore/Umbraco.gitignore b/vendor/gitignore/Umbraco.gitignore
new file mode 100644
index 00000000000..ea05e1fb2a9
--- /dev/null
+++ b/vendor/gitignore/Umbraco.gitignore
@@ -0,0 +1,19 @@
+# Note: VisualStudio gitignore rules may also be relevant
+
+# Umbraco
+# Ignore unimportant folders generated by Umbraco
+**/App_Data/Logs/
+**/App_Data/[Pp]review/
+**/App_Data/TEMP/
+**/App_Data/NuGetBackup/
+
+# Ignore Umbraco content cache file
+**/App_Data/umbraco.config
+
+# Don't ignore Umbraco packages (VisualStudio.gitignore mistakes this for a NuGet packages folder)
+# Make sure to include details from VisualStudio.gitignore BEFORE this
+!**/App_Data/[Pp]ackages/
+!**/[Uu]mbraco/[Dd]eveloper/[Pp]ackages
+
+# ImageProcessor DiskCache
+**/App_Data/cache/
diff --git a/vendor/gitignore/Unity.gitignore b/vendor/gitignore/Unity.gitignore
new file mode 100644
index 00000000000..5aafcbb7f1d
--- /dev/null
+++ b/vendor/gitignore/Unity.gitignore
@@ -0,0 +1,30 @@
+/[Ll]ibrary/
+/[Tt]emp/
+/[Oo]bj/
+/[Bb]uild/
+/[Bb]uilds/
+/Assets/AssetStoreTools*
+
+# Autogenerated VS/MD solution and project files
+ExportedObj/
+*.csproj
+*.unityproj
+*.sln
+*.suo
+*.tmp
+*.user
+*.userprefs
+*.pidb
+*.booproj
+*.svd
+
+
+# Unity3D generated meta files
+*.pidb.meta
+
+# Unity3D Generated File On Crash Reports
+sysinfo.txt
+
+# Builds
+*.apk
+*.unitypackage
diff --git a/vendor/gitignore/UnrealEngine.gitignore b/vendor/gitignore/UnrealEngine.gitignore
new file mode 100644
index 00000000000..75b1186b0af
--- /dev/null
+++ b/vendor/gitignore/UnrealEngine.gitignore
@@ -0,0 +1,62 @@
+# Visual Studio 2015 user specific files
+.vs/
+
+# Compiled Object files
+*.slo
+*.lo
+*.o
+*.obj
+
+# Precompiled Headers
+*.gch
+*.pch
+
+# Compiled Dynamic libraries
+*.so
+*.dylib
+*.dll
+
+# Fortran module files
+*.mod
+
+# Compiled Static libraries
+*.lai
+*.la
+*.a
+*.lib
+
+# Executables
+*.exe
+*.out
+*.app
+*.ipa
+
+# These project files can be generated by the engine
+*.xcodeproj
+*.sln
+*.suo
+*.opensdf
+*.sdf
+*.VC.opendb
+
+# Precompiled Assets
+SourceArt/**/*.png
+SourceArt/**/*.tga
+
+# Binary Files
+Binaries/*
+
+# Builds
+Build/*
+
+# Don't ignore icon files in Build
+!Build/**/*.ico
+
+# Configuration files generated by the Editor
+Saved/*
+
+# Compiled source files for the engine to use
+Intermediate/*
+
+# Cache files for the editor to use
+DerivedDataCache/*
diff --git a/vendor/gitignore/VVVV.gitignore b/vendor/gitignore/VVVV.gitignore
new file mode 100644
index 00000000000..5df4324603e
--- /dev/null
+++ b/vendor/gitignore/VVVV.gitignore
@@ -0,0 +1,6 @@
+
+# .v4p backup files
+*~.xml
+
+# Dynamic plugins .dll
+bin/
diff --git a/vendor/gitignore/VisualStudio.gitignore b/vendor/gitignore/VisualStudio.gitignore
new file mode 100644
index 00000000000..f1e3d20e056
--- /dev/null
+++ b/vendor/gitignore/VisualStudio.gitignore
@@ -0,0 +1,252 @@
+## Ignore Visual Studio temporary files, build results, and
+## files generated by popular Visual Studio add-ons.
+
+# User-specific files
+*.suo
+*.user
+*.userosscache
+*.sln.docstates
+
+# User-specific files (MonoDevelop/Xamarin Studio)
+*.userprefs
+
+# Build results
+[Dd]ebug/
+[Dd]ebugPublic/
+[Rr]elease/
+[Rr]eleases/
+x64/
+x86/
+bld/
+[Bb]in/
+[Oo]bj/
+[Ll]og/
+
+# Visual Studio 2015 cache/options directory
+.vs/
+# Uncomment if you have tasks that create the project's static files in wwwroot
+#wwwroot/
+
+# MSTest test Results
+[Tt]est[Rr]esult*/
+[Bb]uild[Ll]og.*
+
+# NUNIT
+*.VisualState.xml
+TestResult.xml
+
+# Build Results of an ATL Project
+[Dd]ebugPS/
+[Rr]eleasePS/
+dlldata.c
+
+# DNX
+project.lock.json
+artifacts/
+
+*_i.c
+*_p.c
+*_i.h
+*.ilk
+*.meta
+*.obj
+*.pch
+*.pdb
+*.pgc
+*.pgd
+*.rsp
+*.sbr
+*.tlb
+*.tli
+*.tlh
+*.tmp
+*.tmp_proj
+*.log
+*.vspscc
+*.vssscc
+.builds
+*.pidb
+*.svclog
+*.scc
+
+# Chutzpah Test files
+_Chutzpah*
+
+# Visual C++ cache files
+ipch/
+*.aps
+*.ncb
+*.opendb
+*.opensdf
+*.sdf
+*.cachefile
+*.VC.db
+*.VC.VC.opendb
+
+# Visual Studio profiler
+*.psess
+*.vsp
+*.vspx
+*.sap
+
+# TFS 2012 Local Workspace
+$tf/
+
+# Guidance Automation Toolkit
+*.gpState
+
+# ReSharper is a .NET coding add-in
+_ReSharper*/
+*.[Rr]e[Ss]harper
+*.DotSettings.user
+
+# JustCode is a .NET coding add-in
+.JustCode
+
+# TeamCity is a build add-in
+_TeamCity*
+
+# DotCover is a Code Coverage Tool
+*.dotCover
+
+# NCrunch
+_NCrunch_*
+.*crunch*.local.xml
+nCrunchTemp_*
+
+# MightyMoose
+*.mm.*
+AutoTest.Net/
+
+# Web workbench (sass)
+.sass-cache/
+
+# Installshield output folder
+[Ee]xpress/
+
+# DocProject is a documentation generator add-in
+DocProject/buildhelp/
+DocProject/Help/*.HxT
+DocProject/Help/*.HxC
+DocProject/Help/*.hhc
+DocProject/Help/*.hhk
+DocProject/Help/*.hhp
+DocProject/Help/Html2
+DocProject/Help/html
+
+# Click-Once directory
+publish/
+
+# Publish Web Output
+*.[Pp]ublish.xml
+*.azurePubxml
+# TODO: Comment the next line if you want to checkin your web deploy settings
+# but database connection strings (with potential passwords) will be unencrypted
+*.pubxml
+*.publishproj
+
+# Microsoft Azure Web App publish settings. Comment the next line if you want to
+# checkin your Azure Web App publish settings, but sensitive information contained
+# in these scripts will be unencrypted
+PublishScripts/
+
+# NuGet Packages
+*.nupkg
+# The packages folder can be ignored because of Package Restore
+**/packages/*
+# except build/, which is used as an MSBuild target.
+!**/packages/build/
+# Uncomment if necessary however generally it will be regenerated when needed
+#!**/packages/repositories.config
+# NuGet v3's project.json files produces more ignoreable files
+*.nuget.props
+*.nuget.targets
+
+# Microsoft Azure Build Output
+csx/
+*.build.csdef
+
+# Microsoft Azure Emulator
+ecf/
+rcf/
+
+# Windows Store app package directories and files
+AppPackages/
+BundleArtifacts/
+Package.StoreAssociation.xml
+_pkginfo.txt
+
+# Visual Studio cache files
+# files ending in .cache can be ignored
+*.[Cc]ache
+# but keep track of directories ending in .cache
+!*.[Cc]ache/
+
+# Others
+ClientBin/
+~$*
+*~
+*.dbmdl
+*.dbproj.schemaview
+*.pfx
+*.publishsettings
+node_modules/
+orleans.codegen.cs
+
+# Since there are multiple workflows, uncomment next line to ignore bower_components
+# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
+#bower_components/
+
+# RIA/Silverlight projects
+Generated_Code/
+
+# Backup & report files from converting an old project file
+# to a newer Visual Studio version. Backup files are not needed,
+# because we have git ;-)
+_UpgradeReport_Files/
+Backup*/
+UpgradeLog*.XML
+UpgradeLog*.htm
+
+# SQL Server files
+*.mdf
+*.ldf
+
+# Business Intelligence projects
+*.rdl.data
+*.bim.layout
+*.bim_*.settings
+
+# Microsoft Fakes
+FakesAssemblies/
+
+# GhostDoc plugin setting file
+*.GhostDoc.xml
+
+# Node.js Tools for Visual Studio
+.ntvs_analysis.dat
+
+# Visual Studio 6 build log
+*.plg
+
+# Visual Studio 6 workspace options file
+*.opt
+
+# Visual Studio LightSwitch build output
+**/*.HTMLClient/GeneratedArtifacts
+**/*.DesktopClient/GeneratedArtifacts
+**/*.DesktopClient/ModelManifest.xml
+**/*.Server/GeneratedArtifacts
+**/*.Server/ModelManifest.xml
+_Pvt_Extensions
+
+# Paket dependency manager
+.paket/paket.exe
+paket-files/
+
+# FAKE - F# Make
+.fake/
+
+# JetBrains Rider
+.idea/
+*.sln.iml
diff --git a/vendor/gitignore/Waf.gitignore b/vendor/gitignore/Waf.gitignore
new file mode 100644
index 00000000000..48e8d8f7be4
--- /dev/null
+++ b/vendor/gitignore/Waf.gitignore
@@ -0,0 +1,4 @@
+# for projects that use Waf for building: http://code.google.com/p/waf/
+.waf-*
+.waf3-*
+.lock-*
diff --git a/vendor/gitignore/WordPress.gitignore b/vendor/gitignore/WordPress.gitignore
new file mode 100644
index 00000000000..97923503c4c
--- /dev/null
+++ b/vendor/gitignore/WordPress.gitignore
@@ -0,0 +1,18 @@
+*.log
+wp-config.php
+wp-content/advanced-cache.php
+wp-content/backup-db/
+wp-content/backups/
+wp-content/blogs.dir/
+wp-content/cache/
+wp-content/upgrade/
+wp-content/uploads/
+wp-content/wp-cache-config.php
+wp-content/plugins/hello.php
+
+/.htaccess
+/license.txt
+/readme.html
+/sitemap.xml
+/sitemap.xml.gz
+
diff --git a/vendor/gitignore/Xojo.gitignore b/vendor/gitignore/Xojo.gitignore
new file mode 100644
index 00000000000..1b036dd4f2e
--- /dev/null
+++ b/vendor/gitignore/Xojo.gitignore
@@ -0,0 +1,11 @@
+# Xojo (formerly REALbasic and Real Studio)
+
+Builds*
+*.debug
+*.debug.app
+Debug*.exe
+Debug*/Debug*.exe
+Debug*/Debug*\ Libs
+*.rbuistate
+*.xojo_uistate
+*.obsolete
diff --git a/vendor/gitignore/Yeoman.gitignore b/vendor/gitignore/Yeoman.gitignore
new file mode 100644
index 00000000000..7170d72018d
--- /dev/null
+++ b/vendor/gitignore/Yeoman.gitignore
@@ -0,0 +1,6 @@
+node_modules/
+bower_components/
+*.log
+
+build/
+dist/
diff --git a/vendor/gitignore/Yii.gitignore b/vendor/gitignore/Yii.gitignore
new file mode 100644
index 00000000000..70f087546f2
--- /dev/null
+++ b/vendor/gitignore/Yii.gitignore
@@ -0,0 +1,6 @@
+assets/*
+!assets/.gitignore
+protected/runtime/*
+!protected/runtime/.gitignore
+protected/data/*.db
+themes/classic/views/
diff --git a/vendor/gitignore/ZendFramework.gitignore b/vendor/gitignore/ZendFramework.gitignore
new file mode 100644
index 00000000000..80adb154900
--- /dev/null
+++ b/vendor/gitignore/ZendFramework.gitignore
@@ -0,0 +1,25 @@
+# Composer files
+composer.phar
+vendor/
+
+# Local configs
+config/autoload/*.local.php
+
+# Binary gettext files
+*.mo
+
+# Data
+data/logs/
+data/cache/
+data/sessions/
+data/tmp/
+temp/
+
+#Doctrine 2
+data/DoctrineORMModule/Proxy/
+data/DoctrineORMModule/cache/
+
+
+# Legacy ZF1
+demos/
+extras/documentation
diff --git a/vendor/gitignore/Zephir.gitignore b/vendor/gitignore/Zephir.gitignore
new file mode 100644
index 00000000000..839cb5d7070
--- /dev/null
+++ b/vendor/gitignore/Zephir.gitignore
@@ -0,0 +1,26 @@
+# Cache files, generates by Zephir
+.temp/
+.libs/
+
+# Object files, generates by linker
+*.lo
+*.la
+*.o
+*.loT
+
+# Files generated by configure and Zephir,
+# not required for extension compilation.
+ext/build/
+ext/modules/
+ext/Makefile*
+ext/config*
+ext/acinclude.m4
+ext/aclocal.m4
+ext/autom4te*
+ext/install-sh
+ext/ltmain.sh
+ext/missing
+ext/mkinstalldirs
+ext/run-tests.php
+ext/.deps
+ext/libtool