Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitlab-ci.yml214
-rw-r--r--CHANGELOG.md260
-rw-r--r--README.md2
-rw-r--r--VERSION2
-rw-r--r--app/assets/javascripts/blob/blob_fork_suggestion.js53
-rw-r--r--app/assets/javascripts/blob/notebook/index.js6
-rw-r--r--app/assets/javascripts/commit/pipelines/pipelines_table.js23
-rw-r--r--app/assets/javascripts/dispatcher.js3
-rw-r--r--app/assets/javascripts/due_date_select.js3
-rw-r--r--app/assets/javascripts/environments/components/environment.js2
-rw-r--r--app/assets/javascripts/environments/components/environment_actions.js100
-rw-r--r--app/assets/javascripts/environments/components/environment_actions.vue103
-rw-r--r--app/assets/javascripts/environments/components/environment_item.vue (renamed from app/assets/javascripts/environments/components/environment_item.js)240
-rw-r--r--app/assets/javascripts/environments/components/environments_table.js97
-rw-r--r--app/assets/javascripts/environments/components/environments_table.vue117
-rw-r--r--app/assets/javascripts/environments/folder/environments_folder_view.js2
-rw-r--r--app/assets/javascripts/issuable_form.js3
-rw-r--r--app/assets/javascripts/lib/utils/common_utils.js5
-rw-r--r--app/assets/javascripts/member_expiration_date.js3
-rw-r--r--app/assets/javascripts/notebook/cells/code.vue58
-rw-r--r--app/assets/javascripts/notebook/cells/code/index.vue57
-rw-r--r--app/assets/javascripts/notebook/cells/index.js2
-rw-r--r--app/assets/javascripts/notebook/cells/markdown.vue98
-rw-r--r--app/assets/javascripts/notebook/cells/output/html.vue22
-rw-r--r--app/assets/javascripts/notebook/cells/output/image.vue27
-rw-r--r--app/assets/javascripts/notebook/cells/output/index.vue83
-rw-r--r--app/assets/javascripts/notebook/cells/prompt.vue30
-rw-r--r--app/assets/javascripts/notebook/index.vue75
-rw-r--r--app/assets/javascripts/notebook/lib/highlight.js22
-rw-r--r--app/assets/javascripts/pipelines/components/empty_state.vue2
-rw-r--r--app/assets/javascripts/shortcuts.js7
-rw-r--r--app/assets/javascripts/user_tabs.js22
-rw-r--r--app/assets/stylesheets/framework/blocks.scss1
-rw-r--r--app/assets/stylesheets/framework/dropdowns.scss71
-rw-r--r--app/assets/stylesheets/framework/header.scss1
-rw-r--r--app/assets/stylesheets/framework/nav.scss2
-rw-r--r--app/assets/stylesheets/framework/typography.scss29
-rw-r--r--app/assets/stylesheets/framework/variables.scss6
-rw-r--r--app/assets/stylesheets/pages/note_form.scss1
-rw-r--r--app/assets/stylesheets/pages/notes.scss4
-rw-r--r--app/assets/stylesheets/pages/search.scss15
-rw-r--r--app/controllers/admin/groups_controller.rb8
-rw-r--r--app/controllers/projects/milestones_controller.rb1
-rw-r--r--app/helpers/ci_status_helper.rb25
-rw-r--r--app/helpers/icons_helper.rb5
-rw-r--r--app/helpers/submodule_helper.rb12
-rw-r--r--app/models/ci/pipeline.rb20
-rw-r--r--app/models/concerns/cache_markdown_field.rb126
-rw-r--r--app/models/concerns/routable.rb15
-rw-r--r--app/models/group.rb2
-rw-r--r--app/models/individual_note_discussion.rb4
-rw-r--r--app/models/issue.rb2
-rw-r--r--app/models/member.rb28
-rw-r--r--app/models/members/group_member.rb12
-rw-r--r--app/models/members/project_member.rb4
-rw-r--r--app/models/out_of_context_discussion.rb6
-rw-r--r--app/models/project_team.rb4
-rw-r--r--app/services/ci/expire_pipeline_cache_service.rb51
-rw-r--r--app/services/users/migrate_to_ghost_user_service.rb34
-rw-r--r--app/views/projects/_last_commit.html.haml3
-rw-r--r--app/views/projects/new.html.haml5
-rw-r--r--app/views/projects/triggers/_form.html.haml2
-rw-r--r--app/views/shared/_personal_access_tokens_form.html.haml3
-rw-r--r--app/views/shared/milestones/_form_dates.html.haml4
-rw-r--r--app/views/shared/milestones/_issuable.html.haml13
-rw-r--r--app/views/users/show.html.haml10
-rw-r--r--app/workers/clear_database_cache_worker.rb24
-rw-r--r--app/workers/expire_pipeline_cache_worker.rb57
-rw-r--r--changelogs/unreleased/12818-ci-status-as-favicon.yml4
-rw-r--r--changelogs/unreleased/12818-expose-simple-cicd-status-endpoints-with-status-serializer-gitlab-ci-status-for-pipeline-job-and-merge-request.yml5
-rw-r--r--changelogs/unreleased/1440-db-backup-ssl-support.yml4
-rw-r--r--changelogs/unreleased/17325-rugged-gem-update.yml4
-rw-r--r--changelogs/unreleased/18471-restrict-tag-pushes-protected-tags.yml4
-rw-r--r--changelogs/unreleased/19742-permalink-blame-button-line-number-hash-links.yml4
-rw-r--r--changelogs/unreleased/20841-getting-started-better-empty-state-for-merge-requests-view.yml4
-rw-r--r--changelogs/unreleased/20914-project-home-width.yml4
-rw-r--r--changelogs/unreleased/2120-issues-search-bar-not-picking-up.yml4
-rw-r--r--changelogs/unreleased/21451-allow-disable-mr-link.yml4
-rw-r--r--changelogs/unreleased/22303-symbolic-in-tree.yml4
-rw-r--r--changelogs/unreleased/23363-use-strong-params-in-wikis-controller.yml4
-rw-r--r--changelogs/unreleased/23655-api-group-issues.yml4
-rw-r--r--changelogs/unreleased/23674-simplify-milestone-summary.yml4
-rw-r--r--changelogs/unreleased/23862-fix-group-project-count.yml4
-rw-r--r--changelogs/unreleased/24137-issuable-permalink.yml4
-rw-r--r--changelogs/unreleased/24166-close-builds-dropdown.yml4
-rw-r--r--changelogs/unreleased/24187-set-git-terminal-prompt-env-var-in-initializer.yml4
-rw-r--r--changelogs/unreleased/24215-closed-issues-board.yml4
-rw-r--r--changelogs/unreleased/24240-add-monitoring-endpoints.yml4
-rw-r--r--changelogs/unreleased/24421-personal-milestone-count-badges.yml4
-rw-r--r--changelogs/unreleased/24501-new-file-existing-branch.yml4
-rw-r--r--changelogs/unreleased/24784-system-notes-meta-data.yml4
-rw-r--r--changelogs/unreleased/24861-stringify-group-member-details.yml4
-rw-r--r--changelogs/unreleased/25188-polyfill-es-symbol.yml4
-rw-r--r--changelogs/unreleased/25332-make-file-templates-easy-to-use-and-discover.yml4
-rw-r--r--changelogs/unreleased/25515-delegate-single-discussion-to-new-issue.yml4
-rw-r--r--changelogs/unreleased/25556-prevent-users-from-disconnecting-gitlab-account-from-cas.yml4
-rw-r--r--changelogs/unreleased/26188-tag-creation-404-for-guests.yml4
-rw-r--r--changelogs/unreleased/26202-change-dropdown-style-slightly.yml4
-rw-r--r--changelogs/unreleased/26208-animate-drodowns.yml4
-rw-r--r--changelogs/unreleased/26236-monospace-gfm.yml4
-rw-r--r--changelogs/unreleased/26470-branch-names-with-reference-prefixes-results-in-buggy-branches.yml4
-rw-r--r--changelogs/unreleased/27114-add-undo-mark-all-as-done-to-todos.yml4
-rw-r--r--changelogs/unreleased/27114-add-undo-to-todos-in-the-done-tab.yml4
-rw-r--r--changelogs/unreleased/27174-filter-filters.yml4
-rw-r--r--changelogs/unreleased/27262-issue-recent-searches.yml4
-rw-r--r--changelogs/unreleased/27271-missing-time-spent-in-issue-webhook.yml4
-rw-r--r--changelogs/unreleased/27293-remove-repeated-labels.yml4
-rw-r--r--changelogs/unreleased/27503-feature-status-aria-labels.yml4
-rw-r--r--changelogs/unreleased/27574-pipelines-empty-state.yml4
-rw-r--r--changelogs/unreleased/27580-fix-show-go-back.yml4
-rw-r--r--changelogs/unreleased/27878-new-service-for-creating-user.yml4
-rw-r--r--changelogs/unreleased/27910-admin-can-create-project-in-all-groups.yml4
-rw-r--r--changelogs/unreleased/27988-fix-transient-failure-in-commits-api.yml5
-rw-r--r--changelogs/unreleased/28030-infinite-offset.yml4
-rw-r--r--changelogs/unreleased/28187-project-name-cut-off-with-nested-groups.yml4
-rw-r--r--changelogs/unreleased/28402-fix-starred-projects-filter-wrong-message-on-no-results.yml4
-rw-r--r--changelogs/unreleased/28424-labels-support-color-names-in-backend.yml4
-rw-r--r--changelogs/unreleased/28494-mini-pipeline-graph-commit-view.yml4
-rw-r--r--changelogs/unreleased/28574-jira-trigers.yml4
-rw-r--r--changelogs/unreleased/28614-harmonious-color-palette.yml4
-rw-r--r--changelogs/unreleased/28634-todos-margin.yml4
-rw-r--r--changelogs/unreleased/28660-fix-dismissable-error-close-not-visible-enough.yml4
-rw-r--r--changelogs/unreleased/28695-move-all-associated-records-to-ghost-user.yml4
-rw-r--r--changelogs/unreleased/28713-fe-style-guide.yml4
-rw-r--r--changelogs/unreleased/28732-expandable-folders.yml4
-rw-r--r--changelogs/unreleased/28799-todo-creation.yml4
-rw-r--r--changelogs/unreleased/28810-projectfinder-should-handle-more-options.yml4
-rw-r--r--changelogs/unreleased/28874-fix-milestone-issues-position-order-in-api.yml4
-rw-r--r--changelogs/unreleased/28899-linking-to-edit-file.yml5
-rw-r--r--changelogs/unreleased/28991-viewing-old-wiki-page-version-edit-button-exists.yml4
-rw-r--r--changelogs/unreleased/29014-create-issue-form-buttons-misaligned-on-mobile.yml4
-rw-r--r--changelogs/unreleased/29043-upgrade-vue-and-remove-warnings.yml4
-rw-r--r--changelogs/unreleased/29046-fix-github-importer-open-prs.yml4
-rw-r--r--changelogs/unreleased/29116-maxint-error.yml4
-rw-r--r--changelogs/unreleased/29128-profile-page-icons.yml4
-rw-r--r--changelogs/unreleased/29137-bulk-perform-async-should-specify-queue.yml4
-rw-r--r--changelogs/unreleased/29162-refactor-dropdown-milestone-spec.yml4
-rw-r--r--changelogs/unreleased/29189-discussion-button.yml4
-rw-r--r--changelogs/unreleased/29209-sign-up-form-name.yml4
-rw-r--r--changelogs/unreleased/29328-fix-transient-failure-in-model-user-spec.yml4
-rw-r--r--changelogs/unreleased/29341-add-metrics-button-env-overview.yml4
-rw-r--r--changelogs/unreleased/29364-private-projects-mr-fix.yml4
-rw-r--r--changelogs/unreleased/29405-fix-project-wiki-update.yml4
-rw-r--r--changelogs/unreleased/29414-fix-toggle-discussion-link-jump.yml4
-rw-r--r--changelogs/unreleased/29428-new-directory-from-existing-branch.yml4
-rw-r--r--changelogs/unreleased/29432-prevent-click-disabled-btn.yml4
-rw-r--r--changelogs/unreleased/29438-fix-trigger-webhook-for-ref-with-dot.yml4
-rw-r--r--changelogs/unreleased/29469-message-for-project-x-will-be-deleted-should-include-namespace.yml4
-rw-r--r--changelogs/unreleased/29483-spam-check-only-title-and-description.yml4
-rw-r--r--changelogs/unreleased/29492-useless-queries.yml4
-rw-r--r--changelogs/unreleased/29550-fix-quick-submit-on-preview.yml4
-rw-r--r--changelogs/unreleased/29555-align-all-todo.yml4
-rw-r--r--changelogs/unreleased/29575-polling.yml4
-rw-r--r--changelogs/unreleased/29662-allow-unauthenticated-branches-api.yml4
-rw-r--r--changelogs/unreleased/29669-redirect-referer-params.yml4
-rw-r--r--changelogs/unreleased/29670-jira-integration-documentation-improvment.yml4
-rw-r--r--changelogs/unreleased/29712-unnecessary-wait-for-ajax.yml4
-rw-r--r--changelogs/unreleased/29801-add-slash-slack-commands-to-api-doc.yml5
-rw-r--r--changelogs/unreleased/29828-change-search-hint-in-new-filters.yml4
-rw-r--r--changelogs/unreleased/29830-build-scroll-indicator.yml4
-rw-r--r--changelogs/unreleased/29843-project-subgroup-transfer.yml4
-rw-r--r--changelogs/unreleased/2989-run-cicd-pipelines-on-a-schedule-idea1-basic-backend-implementation.yml4
-rw-r--r--changelogs/unreleased/29897-remove-force-scroll-for-mr-changes-diff.yml4
-rw-r--r--changelogs/unreleased/29929-jira-doc.yml4
-rw-r--r--changelogs/unreleased/29930-fix-profile-cover-button-a11y.yml4
-rw-r--r--changelogs/unreleased/29950-vue-pagination-icons.yml4
-rw-r--r--changelogs/unreleased/30008-textarea-focus.yml4
-rw-r--r--changelogs/unreleased/30021-api-deploy_keys-can_push-is-not-honoured.yml4
-rw-r--r--changelogs/unreleased/30056-rename-milestones-empty.yml4
-rw-r--r--changelogs/unreleased/30112-fix-pipelines-sub-nav-highlight.yml4
-rw-r--r--changelogs/unreleased/30125-markdown-security.yml4
-rw-r--r--changelogs/unreleased/30195-document-search-param-on-api.yml4
-rw-r--r--changelogs/unreleased/30291-reopen-mr.yml4
-rw-r--r--changelogs/unreleased/30305-oauth-token-push-code.yml4
-rw-r--r--changelogs/unreleased/30306-transaction-while-moving-issues-to-ghost-user.yml4
-rw-r--r--changelogs/unreleased/30400-fix-blob-highlighting-in-search.yml4
-rw-r--r--changelogs/unreleased/30457-expire-note-destroy.yml4
-rw-r--r--changelogs/unreleased/30493-env-deploy-tooltip.yml5
-rw-r--r--changelogs/unreleased/30587-pipeline-icon-z.yml4
-rw-r--r--changelogs/unreleased/30588-fix-javascript-sourcemaps-w-chrome-breakpoints.yml4
-rw-r--r--changelogs/unreleased/30672-versioned-markdown-cache.yml4
-rw-r--r--changelogs/unreleased/30779-show-mr-subnav-issue-tracker.yml4
-rw-r--r--changelogs/unreleased/31193-ff-copy.yml4
-rw-r--r--changelogs/unreleased/4195-add-sorting-to-project-milestones.yml4
-rw-r--r--changelogs/unreleased/8998_skip_pending_commits_if_not_head.yml4
-rw-r--r--changelogs/unreleased/adam-finish-5993-closed-issuable.yml4
-rw-r--r--changelogs/unreleased/adam-prevent-two-issue-trackers.yml4
-rw-r--r--changelogs/unreleased/add-aria-to-icon.yml4
-rw-r--r--changelogs/unreleased/add-blob-copy-button.yml4
-rw-r--r--changelogs/unreleased/add-dimension-etag-caching-metrics.yml4
-rw-r--r--changelogs/unreleased/add-email-receiver-metrics.yml4
-rw-r--r--changelogs/unreleased/add-error-empty-states.yml4
-rw-r--r--changelogs/unreleased/add-field-for-group-name.yml4
-rw-r--r--changelogs/unreleased/add-issue-modal-loading-indicator.yml4
-rw-r--r--changelogs/unreleased/add-labels-to-issue-hook.yml4
-rw-r--r--changelogs/unreleased/add-test-backoff-util.yml4
-rw-r--r--changelogs/unreleased/add-todos-shortcut.yml4
-rw-r--r--changelogs/unreleased/add-ui-for-trigger-schedule.yml4
-rw-r--r--changelogs/unreleased/add_index_on_ci_builds_updated_at.yml4
-rw-r--r--changelogs/unreleased/add_quick_submit_for_snippets_form.yml4
-rw-r--r--changelogs/unreleased/add_remove_concurrent_index_to_database_helper.yml4
-rw-r--r--changelogs/unreleased/allow-resolving-conflicts-in-utf-8.yml4
-rw-r--r--changelogs/unreleased/award-emoji-button-smiley-animation.yml4
-rw-r--r--changelogs/unreleased/bug-api_milestone_merge_requests_scope.yml4
-rw-r--r--changelogs/unreleased/bugfix-systemhook.yml4
-rw-r--r--changelogs/unreleased/button-capitalization.yml4
-rw-r--r--changelogs/unreleased/calendar-tooltips.yml4
-rw-r--r--changelogs/unreleased/chore-23493-remaining-time-tooltip.yml5
-rw-r--r--changelogs/unreleased/clean_carrierwave_tempfiles.yml4
-rw-r--r--changelogs/unreleased/cleaner-additional-award-emoji-button.yml4
-rw-r--r--changelogs/unreleased/create-collapsed-todo-button.yml5
-rw-r--r--changelogs/unreleased/diff-discussion-buttons-spacing.yml4
-rw-r--r--changelogs/unreleased/dm-copy-code-as-gfm.yml4
-rw-r--r--changelogs/unreleased/dm-copy-diff-file-title-as-gfm.yml4
-rw-r--r--changelogs/unreleased/dm-fix-individual-notes-reply-attributes.yml5
-rw-r--r--changelogs/unreleased/dm-fix-position-tracer-for-hidden-lines.yml5
-rw-r--r--changelogs/unreleased/dz-cleanup-add-users.yml4
-rw-r--r--changelogs/unreleased/dz-fix-group-move.yml4
-rw-r--r--changelogs/unreleased/dz-fix-project-view.yml4
-rw-r--r--changelogs/unreleased/dz-hide-zero-counter.yml4
-rw-r--r--changelogs/unreleased/dz-refactor-admin-group-members.yml4
-rw-r--r--changelogs/unreleased/emoji-menu-duplicated-search-icon.yml4
-rw-r--r--changelogs/unreleased/enable-snippets-by-default.yml4
-rw-r--r--changelogs/unreleased/enforce-Ansi2html-output-encoding.yml4
-rw-r--r--changelogs/unreleased/environment-performance-improvements.yml4
-rw-r--r--changelogs/unreleased/es6-class-issue.yml4
-rw-r--r--changelogs/unreleased/feature-custom-lfs.yml4
-rw-r--r--changelogs/unreleased/feature-enforce-2fa-per-group.yml4
-rw-r--r--changelogs/unreleased/feature-gh-rake-task.yml4
-rw-r--r--changelogs/unreleased/feature-multi-level-container-registry-images.yml4
-rw-r--r--changelogs/unreleased/feature-tokens-rake-task.yml4
-rw-r--r--changelogs/unreleased/feature-use-gitaly-for-commit-is-ancestor.yml4
-rw-r--r--changelogs/unreleased/feature-use-gitaly-for-commit-show.yml4
-rw-r--r--changelogs/unreleased/file-import-export-path-disclosure.yml5
-rw-r--r--changelogs/unreleased/fix-29093.yml4
-rw-r--r--changelogs/unreleased/fix-29125.yml4
-rw-r--r--changelogs/unreleased/fix-admin-projects.yml4
-rw-r--r--changelogs/unreleased/fix-gb-dashboard-commit-status-caching.yml4
-rw-r--r--changelogs/unreleased/fix-gb-fix-blocked-pipeline-duration.yml4
-rw-r--r--changelogs/unreleased/fix-gb-fix-incorrect-commit-status-badge-text.yml4
-rw-r--r--changelogs/unreleased/fix-gb-remove-deprecated-pipeline-processing-code.yml4
-rw-r--r--changelogs/unreleased/fix-gh-import-status-check.yml4
-rw-r--r--changelogs/unreleased/fix-github-importer-slowness.yml4
-rw-r--r--changelogs/unreleased/fix-groups-long-url.yml4
-rw-r--r--changelogs/unreleased/fix-import-fork.yml4
-rw-r--r--changelogs/unreleased/fix-import-namespace.yml4
-rw-r--r--changelogs/unreleased/fix-issue-23237.yml4
-rw-r--r--changelogs/unreleased/fix-milestone-name-on-show.yml4
-rw-r--r--changelogs/unreleased/fix-missing-capitalisation-buttons.yml4
-rw-r--r--changelogs/unreleased/fix-orphan-notification-settings.yml4
-rw-r--r--changelogs/unreleased/fix-preloading-merge_request_diff.yml4
-rw-r--r--changelogs/unreleased/fix-project-visibility-setting.yml4
-rw-r--r--changelogs/unreleased/fix-trace-encoding.yml4
-rw-r--r--changelogs/unreleased/fix-trace-seeking.yml4
-rw-r--r--changelogs/unreleased/fix-user-profile-tabs-showing-raw-json-instead.yml5
-rw-r--r--changelogs/unreleased/fix_admin_monitoring_background.yml4
-rw-r--r--changelogs/unreleased/fix_link_in_readme.yml4
-rw-r--r--changelogs/unreleased/fix_rake_gitlab_check_sidekiq.yml4
-rw-r--r--changelogs/unreleased/fix_updated_field_in_issues-atom.yml4
-rw-r--r--changelogs/unreleased/fix_visibility_level.yml4
-rw-r--r--changelogs/unreleased/fix_wiki_commit_message.yml4
-rw-r--r--changelogs/unreleased/fl-remove-ujs-pipelines.yml4
-rw-r--r--changelogs/unreleased/form-focus-previous-incorrect-form.yml4
-rw-r--r--changelogs/unreleased/gitaly-refs.yml4
-rw-r--r--changelogs/unreleased/group-gear-setting-dropdown-to-tab.yml4
-rw-r--r--changelogs/unreleased/group-milestone-date-fields-fix.yml4
-rw-r--r--changelogs/unreleased/handle-failure-when-deleting-tags.yml4
-rw-r--r--changelogs/unreleased/hook_retries.yml4
-rw-r--r--changelogs/unreleased/introduce-polling-interval-multiplier.yml4
-rw-r--r--changelogs/unreleased/issue-boards-cant-drag-fix.yml4
-rw-r--r--changelogs/unreleased/issue-boards-new-search-bar.yml4
-rw-r--r--changelogs/unreleased/issue_27212.yml4
-rw-r--r--changelogs/unreleased/issue_29449.yml4
-rw-r--r--changelogs/unreleased/issue_91_ee_backport.yml4
-rw-r--r--changelogs/unreleased/issues-empty-state-not-centered.yml4
-rw-r--r--changelogs/unreleased/jej-group-name-disclosure.yml4
-rw-r--r--changelogs/unreleased/make-karma-fast-again.yml4
-rw-r--r--changelogs/unreleased/make_user_mentions_case_insensitive.yml4
-rw-r--r--changelogs/unreleased/menu-shortcut.yml4
-rw-r--r--changelogs/unreleased/metrics-button-misplaced.yml4
-rw-r--r--changelogs/unreleased/microsoft-teams-integration.yml4
-rw-r--r--changelogs/unreleased/mr-diffs-speed-up.yml4
-rw-r--r--changelogs/unreleased/mr-new-page-changing-url.yml4
-rw-r--r--changelogs/unreleased/mr-widget-bug-fix.yml5
-rw-r--r--changelogs/unreleased/mrchrisw-22740-merge-api.yml4
-rw-r--r--changelogs/unreleased/namespace-race-condition.yml4
-rw-r--r--changelogs/unreleased/new-resolvable-discussion.yml4
-rw-r--r--changelogs/unreleased/open-redirect-continue-params.yml4
-rw-r--r--changelogs/unreleased/open-redirect-host-field.yml4
-rw-r--r--changelogs/unreleased/optimise-builds-view.yml4
-rw-r--r--changelogs/unreleased/option-to-be-notified-of-own-activity.yml4
-rw-r--r--changelogs/unreleased/pages-debug-log.yml4
-rw-r--r--changelogs/unreleased/pipeline-tooltips-overflow.yml4
-rw-r--r--changelogs/unreleased/pipelines-build-tooltip.yml4
-rw-r--r--changelogs/unreleased/plantuml-filter-after-highlight.yml4
-rw-r--r--changelogs/unreleased/pms-lighter-colors.yml4
-rw-r--r--changelogs/unreleased/projects-list-line-breaks.yml4
-rw-r--r--changelogs/unreleased/quiet-pipelines.yml5
-rw-r--r--changelogs/unreleased/refresh-permissions-recent-users.yml4
-rw-r--r--changelogs/unreleased/remember-me-missasligned-mobile.yml4
-rw-r--r--changelogs/unreleased/remove_index_for_users-current_sign_in_at.yml4
-rw-r--r--changelogs/unreleased/remove_is_admin.yml4
-rw-r--r--changelogs/unreleased/rename_all_issues.yml4
-rw-r--r--changelogs/unreleased/rename_done_to_closed.yml4
-rw-r--r--changelogs/unreleased/replace_closing_mr_icon.yml4
-rw-r--r--changelogs/unreleased/scrollable-secondary-tabs.yml4
-rw-r--r--changelogs/unreleased/sh-add-index-to-system-note-metadata.yml4
-rw-r--r--changelogs/unreleased/sh-issue-29247-fix.yml5
-rw-r--r--changelogs/unreleased/sh-optimize-duplicate-routable-full-path.yml4
-rw-r--r--changelogs/unreleased/sh-optimize-milestone-polymorphic-url.yml4
-rw-r--r--changelogs/unreleased/sh-relax-wiki-slug-constraint.yml4
-rw-r--r--changelogs/unreleased/sh-remove-tags-from-explore.yml4
-rw-r--r--changelogs/unreleased/siemens-gitlab-ce-fix-subgroup-hide-button.yml4
-rw-r--r--changelogs/unreleased/simplify-docs-trigger.yml4
-rw-r--r--changelogs/unreleased/style-proc-cop.yml4
-rw-r--r--changelogs/unreleased/submodules-no-dotgit.yml4
-rw-r--r--changelogs/unreleased/tc-fix-pipeline-recipient.yml4
-rw-r--r--changelogs/unreleased/tc-fix-unplayable-build-action-404.yml4
-rw-r--r--changelogs/unreleased/tc-pipeline-show-trigger-date.yml4
-rw-r--r--changelogs/unreleased/tc-realtime-every-pipeline-on-mr.yml4
-rw-r--r--changelogs/unreleased/tc-show-pipeline-coverage-if-avail.yml4
-rw-r--r--changelogs/unreleased/time-tracking-color-not-consistent.yml4
-rw-r--r--changelogs/unreleased/update-issue-board-cards-design.yml4
-rw-r--r--changelogs/unreleased/update-test-bundle-ignored-files.yml4
-rw-r--r--changelogs/unreleased/usage-ping-port.yml4
-rw-r--r--changelogs/unreleased/use-corejs-polyfills.yml4
-rw-r--r--changelogs/unreleased/user-callout-showing-on-all-profiles.yml4
-rw-r--r--changelogs/unreleased/user-profile-join-date.yml4
-rw-r--r--changelogs/unreleased/zj-api-fix-build-events.yml4
-rw-r--r--changelogs/unreleased/zj-chat-notification-default-branch.yml4
-rw-r--r--changelogs/unreleased/zj-fk-ci-triggers.yml4
-rw-r--r--changelogs/unreleased/zj-kube-service-auto-fill.yml4
-rw-r--r--config/database.yml.mysql2
-rw-r--r--config/database.yml.postgresql5
-rw-r--r--config/gitlab.yml.example5
-rw-r--r--config/initializers/1_settings.rb6
-rw-r--r--config/initializers/rspec_profiling.rb2
-rw-r--r--config/sidekiq_queues.yml1
-rw-r--r--db/migrate/20170410133135_add_version_field_to_markdown_cache.rb25
-rw-r--r--db/migrate/20170423064036_add_index_on_ci_builds_updated_at.rb19
-rw-r--r--db/schema.rb16
-rw-r--r--doc/README.md1
-rw-r--r--doc/administration/gitaly/index.md2
-rw-r--r--doc/administration/high_availability/redis.md2
-rw-r--r--doc/administration/integration/plantuml.md2
-rw-r--r--doc/api/jobs.md2
-rw-r--r--doc/api/projects.md15
-rw-r--r--doc/api/services.md79
-rw-r--r--doc/api/users.md2
-rw-r--r--doc/ci/autodeploy/img/auto_deploy_dropdown.pngbin44380 -> 99422 bytes
-rw-r--r--doc/ci/autodeploy/index.md34
-rw-r--r--doc/ci/triggers/README.md28
-rw-r--r--doc/ci/triggers/img/trigger_schedule_create.pngbin0 -> 34264 bytes
-rw-r--r--doc/ci/triggers/img/trigger_schedule_edit.pngbin0 -> 18524 bytes
-rw-r--r--doc/ci/triggers/img/trigger_schedule_updated_next_run_at.pngbin0 -> 21896 bytes
-rw-r--r--doc/development/fe_guide/index.md2
-rw-r--r--doc/development/fe_guide/testing.md6
-rw-r--r--doc/development/fe_guide/vue.md18
-rw-r--r--doc/install/installation.md4
-rw-r--r--doc/raketasks/backup_restore.md10
-rw-r--r--doc/update/9.0-to-9.1.md11
-rw-r--r--doc/user/admin_area/monitoring/health_check.md76
-rw-r--r--doc/user/discussions/img/btn_new_issue_for_all_discussions.png (renamed from doc/user/project/merge_requests/img/btn_new_issue_for_all_discussions.png)bin29007 -> 29007 bytes
-rw-r--r--doc/user/discussions/img/comment_type_toggle.gifbin0 -> 70796 bytes
-rw-r--r--doc/user/discussions/img/discussion_comment.pngbin0 -> 57189 bytes
-rw-r--r--doc/user/discussions/img/discussion_view.png (renamed from doc/user/project/merge_requests/img/discussion_view.png)bin73821 -> 73821 bytes
-rw-r--r--doc/user/discussions/img/discussions_resolved.png (renamed from doc/user/project/merge_requests/img/discussions_resolved.png)bin4152 -> 4152 bytes
-rw-r--r--doc/user/discussions/img/new_issue_for_discussion.png (renamed from doc/user/project/merge_requests/img/new_issue_for_discussion.png)bin39563 -> 39563 bytes
-rw-r--r--doc/user/discussions/img/only_allow_merge_if_all_discussions_are_resolved.png (renamed from doc/user/project/merge_requests/img/only_allow_merge_if_all_discussions_are_resolved.png)bin17888 -> 17888 bytes
-rw-r--r--doc/user/discussions/img/only_allow_merge_if_all_discussions_are_resolved_msg.png (renamed from doc/user/project/merge_requests/img/only_allow_merge_if_all_discussions_are_resolved_msg.png)bin4962 -> 4962 bytes
-rw-r--r--doc/user/discussions/img/preview_issue_for_discussion.png (renamed from doc/user/project/merge_requests/img/preview_issue_for_discussion.png)bin82412 -> 82412 bytes
-rw-r--r--doc/user/discussions/img/preview_issue_for_discussions.png (renamed from doc/user/project/merge_requests/img/preview_issue_for_discussions.png)bin143871 -> 143871 bytes
-rw-r--r--doc/user/discussions/img/resolve_comment_button.png (renamed from doc/user/project/merge_requests/img/resolve_comment_button.png)bin4722 -> 4722 bytes
-rw-r--r--doc/user/discussions/img/resolve_discussion_button.png (renamed from doc/user/project/merge_requests/img/resolve_discussion_button.png)bin4683 -> 4683 bytes
-rw-r--r--doc/user/discussions/img/resolve_discussion_issue_notice.png (renamed from doc/user/project/merge_requests/img/resolve_discussion_issue_notice.png)bin10307 -> 10307 bytes
-rw-r--r--doc/user/discussions/img/resolve_discussion_open_issue.png (renamed from doc/user/project/merge_requests/img/resolve_discussion_open_issue.png)bin20967 -> 20967 bytes
-rw-r--r--doc/user/discussions/index.md150
-rw-r--r--doc/user/project/integrations/microsoft_teams.md6
-rw-r--r--doc/user/project/integrations/project_services.md1
-rw-r--r--doc/user/project/merge_requests/index.md2
-rw-r--r--doc/user/project/merge_requests/merge_request_discussion_resolution.md107
-rw-r--r--doc/user/project/milestones/index.md3
-rw-r--r--doc/workflow/README.md2
-rw-r--r--features/profile/profile.feature4
-rw-r--r--features/project/forked_merge_requests.feature3
-rw-r--r--features/steps/project/commits/commits.rb2
-rw-r--r--features/steps/project/forked_merge_requests.rb2
-rw-r--r--features/steps/project/merge_requests/acceptance.rb2
-rw-r--r--features/steps/project/merge_requests/revert.rb2
-rw-r--r--features/steps/project/source/browse_files.rb6
-rw-r--r--features/steps/project/source/markdown_render.rb2
-rw-r--r--features/steps/shared/authentication.rb51
-rw-r--r--features/support/login_helpers.rb19
-rw-r--r--lib/api/merge_requests.rb7
-rw-r--r--lib/api/projects.rb7
-rw-r--r--lib/backup/database.rb26
-rw-r--r--lib/banzai/renderer.rb41
-rw-r--r--lib/gitlab/auth.rb2
-rw-r--r--lib/gitlab/diff/position_tracer.rb9
-rw-r--r--lib/gitlab/email/handler/base_handler.rb4
-rw-r--r--lib/gitlab/email/handler/create_issue_handler.rb5
-rw-r--r--lib/gitlab/email/handler/create_note_handler.rb4
-rw-r--r--lib/gitlab/email/handler/unsubscribe_handler.rb4
-rw-r--r--lib/gitlab/email/receiver.rb5
-rw-r--r--lib/gitlab/git/encoding_helper.rb8
-rw-r--r--lib/gitlab/metrics.rb10
-rw-r--r--lib/gitlab/workhorse.rb2
-rw-r--r--lib/tasks/cache.rake7
-rw-r--r--lib/tasks/gitlab/gitaly.rake37
-rw-r--r--package.json2
-rwxr-xr-xscripts/prepare_build.sh60
-rw-r--r--scripts/utils.sh14
-rw-r--r--spec/controllers/admin/groups_controller_spec.rb24
-rw-r--r--spec/controllers/dashboard/todos_controller_spec.rb2
-rw-r--r--spec/controllers/projects/builds_controller_spec.rb42
-rw-r--r--spec/controllers/projects/builds_controller_specs.rb47
-rw-r--r--spec/controllers/projects/environments_controller_spec.rb2
-rw-r--r--spec/controllers/projects/labels_controller_spec.rb2
-rw-r--r--spec/controllers/projects/merge_requests_controller_spec.rb2
-rw-r--r--spec/controllers/projects/milestones_controller_spec.rb15
-rw-r--r--spec/controllers/projects/pipelines_controller_spec.rb2
-rw-r--r--spec/controllers/projects/todo_controller_spec.rb2
-rw-r--r--spec/features/admin/admin_labels_spec.rb2
-rw-r--r--spec/features/admin/admin_users_spec.rb2
-rw-r--r--spec/features/auto_deploy_spec.rb4
-rw-r--r--spec/features/boards/add_issues_modal_spec.rb1
-rw-r--r--spec/features/boards/boards_spec.rb1
-rw-r--r--spec/features/boards/new_issue_spec.rb1
-rw-r--r--spec/features/boards/sidebar_spec.rb1
-rw-r--r--spec/features/calendar_spec.rb4
-rw-r--r--spec/features/commits_spec.rb2
-rw-r--r--spec/features/copy_as_gfm_spec.rb2
-rw-r--r--spec/features/cycle_analytics_spec.rb4
-rw-r--r--spec/features/dashboard/datetime_on_tooltips_spec.rb2
-rw-r--r--spec/features/dashboard/groups_list_spec.rb2
-rw-r--r--spec/features/dashboard/project_member_activity_index_spec.rb2
-rw-r--r--spec/features/dashboard_issues_spec.rb2
-rw-r--r--spec/features/expand_collapse_diffs_spec.rb4
-rw-r--r--spec/features/explore/groups_list_spec.rb2
-rw-r--r--spec/features/gitlab_flavored_markdown_spec.rb28
-rw-r--r--spec/features/global_search_spec.rb2
-rw-r--r--spec/features/issues/award_emoji_spec.rb1
-rw-r--r--spec/features/issues/bulk_assignment_labels_spec.rb2
-rw-r--r--spec/features/issues/create_issue_for_single_discussion_in_merge_request_spec.rb (renamed from spec/features/issues/create_issue_for_single_discussion_in_merge_request.rb)6
-rw-r--r--spec/features/issues/filtered_search/dropdown_assignee_spec.rb1
-rw-r--r--spec/features/issues/filtered_search/dropdown_author_spec.rb1
-rw-r--r--spec/features/issues/filtered_search/dropdown_hint_spec.rb1
-rw-r--r--spec/features/issues/filtered_search/filter_issues_spec.rb1
-rw-r--r--spec/features/issues/filtered_search/recent_searches_spec.rb1
-rw-r--r--spec/features/issues/filtered_search/search_bar_spec.rb1
-rw-r--r--spec/features/issues/gfm_autocomplete_spec.rb1
-rw-r--r--spec/features/issues/issue_sidebar_spec.rb1
-rw-r--r--spec/features/issues/update_issues_spec.rb2
-rw-r--r--spec/features/issues/user_uses_slash_commands_spec.rb1
-rw-r--r--spec/features/issues_spec.rb24
-rw-r--r--spec/features/merge_requests/conflicts_spec.rb2
-rw-r--r--spec/features/merge_requests/create_new_mr_spec.rb8
-rw-r--r--spec/features/merge_requests/deleted_source_branch_spec.rb2
-rw-r--r--spec/features/merge_requests/diff_notes_avatars_spec.rb2
-rw-r--r--spec/features/merge_requests/filter_by_labels_spec.rb1
-rw-r--r--spec/features/merge_requests/filter_merge_requests_spec.rb1
-rw-r--r--spec/features/merge_requests/mini_pipeline_graph_spec.rb2
-rw-r--r--spec/features/merge_requests/pipelines_spec.rb2
-rw-r--r--spec/features/merge_requests/reset_filters_spec.rb1
-rw-r--r--spec/features/merge_requests/update_merge_requests_spec.rb2
-rw-r--r--spec/features/merge_requests/user_posts_notes_spec.rb (renamed from spec/features/merge_requests/user_posts_notes.rb)0
-rw-r--r--spec/features/merge_requests/user_uses_slash_commands_spec.rb1
-rw-r--r--spec/features/merge_requests/versions_spec.rb9
-rw-r--r--spec/features/merge_requests/widget_deployments_spec.rb2
-rw-r--r--spec/features/merge_requests/widget_spec.rb2
-rw-r--r--spec/features/milestone_spec.rb2
-rw-r--r--spec/features/milestones/milestones_spec.rb1
-rw-r--r--spec/features/participants_autocomplete_spec.rb4
-rw-r--r--spec/features/projects/blobs/blob_show_spec.rb1
-rw-r--r--spec/features/projects/blobs/edit_spec.rb1
-rw-r--r--spec/features/projects/blobs/user_create_spec.rb1
-rw-r--r--spec/features/projects/commit/cherry_pick_spec.rb1
-rw-r--r--spec/features/projects/commit/mini_pipeline_graph_spec.rb2
-rw-r--r--spec/features/projects/edit_spec.rb2
-rw-r--r--spec/features/projects/features_visibility_spec.rb3
-rw-r--r--spec/features/projects/files/creating_a_file_spec.rb2
-rw-r--r--spec/features/projects/files/dockerfile_dropdown_spec.rb2
-rw-r--r--spec/features/projects/files/editing_a_file_spec.rb2
-rw-r--r--spec/features/projects/files/files_sort_submodules_with_folders_spec.rb2
-rw-r--r--spec/features/projects/files/find_file_keyboard_spec.rb2
-rw-r--r--spec/features/projects/files/gitignore_dropdown_spec.rb2
-rw-r--r--spec/features/projects/files/gitlab_ci_yml_dropdown_spec.rb2
-rw-r--r--spec/features/projects/files/project_owner_creates_license_file_spec.rb2
-rw-r--r--spec/features/projects/files/project_owner_sees_link_to_create_license_file_in_empty_project_spec.rb2
-rw-r--r--spec/features/projects/files/undo_template_spec.rb15
-rw-r--r--spec/features/projects/issuable_templates_spec.rb12
-rw-r--r--spec/features/projects/labels/update_prioritization_spec.rb1
-rw-r--r--spec/features/projects/members/group_links_spec.rb2
-rw-r--r--spec/features/projects/members/master_adds_member_with_expiration_date_spec.rb1
-rw-r--r--spec/features/projects/members/user_requests_access_spec.rb11
-rw-r--r--spec/features/projects/ref_switcher_spec.rb1
-rw-r--r--spec/features/projects/user_create_dir_spec.rb1
-rw-r--r--spec/features/projects/view_on_env_spec.rb2
-rw-r--r--spec/features/projects_spec.rb14
-rw-r--r--spec/features/protected_branches_spec.rb4
-rw-r--r--spec/features/protected_tags_spec.rb4
-rw-r--r--spec/features/search_spec.rb8
-rw-r--r--spec/features/task_lists_spec.rb3
-rw-r--r--spec/features/todos/todos_filtering_spec.rb2
-rw-r--r--spec/features/todos/todos_spec.rb2
-rw-r--r--spec/features/u2f_spec.rb2
-rw-r--r--spec/features/users/projects_spec.rb2
-rw-r--r--spec/features/users/snippets_spec.rb2
-rw-r--r--spec/features/users_spec.rb1
-rw-r--r--spec/features/variables_spec.rb2
-rw-r--r--spec/helpers/ci_status_helper_spec.rb47
-rw-r--r--spec/helpers/icons_helper_spec.rb15
-rw-r--r--spec/helpers/submodule_helper_spec.rb12
-rw-r--r--spec/javascripts/blob/blob_fork_suggestion_spec.js31
-rw-r--r--spec/javascripts/commit/pipelines/pipelines_spec.js7
-rw-r--r--spec/javascripts/environments/environment_actions_spec.js2
-rw-r--r--spec/javascripts/environments/environment_item_spec.js2
-rw-r--r--spec/javascripts/environments/environment_table_spec.js2
-rw-r--r--spec/javascripts/fixtures/raw.rb24
-rw-r--r--spec/javascripts/notebook/cells/code_spec.js55
-rw-r--r--spec/javascripts/notebook/cells/markdown_spec.js41
-rw-r--r--spec/javascripts/notebook/cells/output/index_spec.js126
-rw-r--r--spec/javascripts/notebook/cells/prompt_spec.js56
-rw-r--r--spec/javascripts/notebook/index_spec.js98
-rw-r--r--spec/javascripts/notebook/lib/highlight_spec.js15
-rw-r--r--spec/javascripts/shortcuts_spec.js45
-rw-r--r--spec/lib/banzai/object_renderer_spec.rb4
-rw-r--r--spec/lib/banzai/redactor_spec.rb25
-rw-r--r--spec/lib/banzai/renderer_spec.rb69
-rw-r--r--spec/lib/gitlab/auth_spec.rb2
-rw-r--r--spec/lib/gitlab/diff/position_tracer_spec.rb9
-rw-r--r--spec/lib/gitlab/git/encoding_helper_spec.rb4
-rw-r--r--spec/lib/gitlab/other_markup_spec.rb (renamed from spec/lib/gitlab/other_markup.rb)4
-rw-r--r--spec/models/ci/pipeline_spec.rb91
-rw-r--r--spec/models/concerns/cache_markdown_field_spec.rb270
-rw-r--r--spec/models/concerns/routable_spec.rb18
-rw-r--r--spec/models/member_spec.rb25
-rw-r--r--spec/models/members/group_member_spec.rb4
-rw-r--r--spec/models/sent_notification_spec.rb8
-rw-r--r--spec/requests/api/access_requests_spec.rb4
-rw-r--r--spec/requests/api/award_emoji_spec.rb3
-rw-r--r--spec/requests/api/boards_spec.rb4
-rw-r--r--spec/requests/api/branches_spec.rb4
-rw-r--r--spec/requests/api/broadcast_messages_spec.rb4
-rw-r--r--spec/requests/api/commit_statuses_spec.rb4
-rw-r--r--spec/requests/api/commits_spec.rb3
-rw-r--r--spec/requests/api/deploy_keys_spec.rb4
-rw-r--r--spec/requests/api/deployments_spec.rb4
-rw-r--r--spec/requests/api/doorkeeper_access_spec.rb4
-rw-r--r--spec/requests/api/environments_spec.rb4
-rw-r--r--spec/requests/api/files_spec.rb3
-rw-r--r--spec/requests/api/groups_spec.rb3
-rw-r--r--spec/requests/api/helpers_spec.rb2
-rw-r--r--spec/requests/api/internal_spec.rb3
-rw-r--r--spec/requests/api/issues_spec.rb3
-rw-r--r--spec/requests/api/jobs_spec.rb4
-rw-r--r--spec/requests/api/keys_spec.rb4
-rw-r--r--spec/requests/api/labels_spec.rb4
-rw-r--r--spec/requests/api/lint_spec.rb4
-rw-r--r--spec/requests/api/members_spec.rb4
-rw-r--r--spec/requests/api/merge_request_diffs_spec.rb4
-rw-r--r--spec/requests/api/merge_requests_spec.rb17
-rw-r--r--spec/requests/api/milestones_spec.rb3
-rw-r--r--spec/requests/api/namespaces_spec.rb3
-rw-r--r--spec/requests/api/notes_spec.rb3
-rw-r--r--spec/requests/api/notification_settings_spec.rb4
-rw-r--r--spec/requests/api/oauth_tokens_spec.rb4
-rw-r--r--spec/requests/api/pipelines_spec.rb4
-rw-r--r--spec/requests/api/project_hooks_spec.rb3
-rw-r--r--spec/requests/api/project_snippets_spec.rb4
-rw-r--r--spec/requests/api/projects_spec.rb37
-rw-r--r--spec/requests/api/repositories_spec.rb3
-rw-r--r--spec/requests/api/runner_spec.rb1
-rw-r--r--spec/requests/api/runners_spec.rb4
-rw-r--r--spec/requests/api/services_spec.rb4
-rw-r--r--spec/requests/api/session_spec.rb4
-rw-r--r--spec/requests/api/settings_spec.rb4
-rw-r--r--spec/requests/api/sidekiq_metrics_spec.rb4
-rw-r--r--spec/requests/api/snippets_spec.rb3
-rw-r--r--spec/requests/api/system_hooks_spec.rb4
-rw-r--r--spec/requests/api/tags_spec.rb3
-rw-r--r--spec/requests/api/templates_spec.rb4
-rw-r--r--spec/requests/api/todos_spec.rb4
-rw-r--r--spec/requests/api/triggers_spec.rb2
-rw-r--r--spec/requests/api/users_spec.rb6
-rw-r--r--spec/requests/api/v3/award_emoji_spec.rb4
-rw-r--r--spec/requests/api/v3/boards_spec.rb4
-rw-r--r--spec/requests/api/v3/branches_spec.rb4
-rw-r--r--spec/requests/api/v3/broadcast_messages_spec.rb4
-rw-r--r--spec/requests/api/v3/builds_spec.rb4
-rw-r--r--spec/requests/api/v3/commits_spec.rb3
-rw-r--r--spec/requests/api/v3/deploy_keys_spec.rb4
-rw-r--r--spec/requests/api/v3/deployments_spec.rb4
-rw-r--r--spec/requests/api/v3/environments_spec.rb4
-rw-r--r--spec/requests/api/v3/files_spec.rb4
-rw-r--r--spec/requests/api/v3/groups_spec.rb3
-rw-r--r--spec/requests/api/v3/issues_spec.rb3
-rw-r--r--spec/requests/api/v3/labels_spec.rb4
-rw-r--r--spec/requests/api/v3/members_spec.rb4
-rw-r--r--spec/requests/api/v3/merge_request_diffs_spec.rb4
-rw-r--r--spec/requests/api/v3/merge_requests_spec.rb3
-rw-r--r--spec/requests/api/v3/milestones_spec.rb3
-rw-r--r--spec/requests/api/v3/notes_spec.rb4
-rw-r--r--spec/requests/api/v3/pipelines_spec.rb4
-rw-r--r--spec/requests/api/v3/project_hooks_spec.rb3
-rw-r--r--spec/requests/api/v3/project_snippets_spec.rb4
-rw-r--r--spec/requests/api/v3/projects_spec.rb3
-rw-r--r--spec/requests/api/v3/repositories_spec.rb3
-rw-r--r--spec/requests/api/v3/runners_spec.rb4
-rw-r--r--spec/requests/api/v3/services_spec.rb4
-rw-r--r--spec/requests/api/v3/settings_spec.rb4
-rw-r--r--spec/requests/api/v3/snippets_spec.rb3
-rw-r--r--spec/requests/api/v3/system_hooks_spec.rb4
-rw-r--r--spec/requests/api/v3/tags_spec.rb3
-rw-r--r--spec/requests/api/v3/templates_spec.rb4
-rw-r--r--spec/requests/api/v3/todos_spec.rb4
-rw-r--r--spec/requests/api/v3/triggers_spec.rb2
-rw-r--r--spec/requests/api/v3/users_spec.rb4
-rw-r--r--spec/requests/api/variables_spec.rb4
-rw-r--r--spec/requests/api/version_spec.rb4
-rw-r--r--spec/requests/ci/api/builds_spec.rb2
-rw-r--r--spec/requests/ci/api/runners_spec.rb1
-rw-r--r--spec/requests/ci/api/triggers_spec.rb2
-rw-r--r--spec/requests/git_http_spec.rb4
-rw-r--r--spec/requests/openid_connect_spec.rb2
-rw-r--r--spec/requests/projects/cycle_analytics_events_spec.rb4
-rw-r--r--spec/services/ci/expire_pipeline_cache_service_spec.rb27
-rw-r--r--spec/services/users/migrate_to_ghost_user_service_spec.rb18
-rw-r--r--spec/support/features/issuable_slash_commands_shared_examples.rb1
-rw-r--r--spec/support/login_helpers.rb4
-rw-r--r--spec/support/markdown_feature.rb4
-rw-r--r--spec/support/services/migrate_to_ghost_user_service_shared_examples.rb52
-rw-r--r--spec/support/test_env.rb10
-rw-r--r--spec/support/wait_for_ajax.rb5
-rw-r--r--spec/views/projects/_last_commit.html.haml_spec.rb22
-rw-r--r--spec/views/projects/commit/_commit_box.html.haml_spec.rb34
-rw-r--r--spec/workers/expire_pipeline_cache_worker_spec.rb44
-rw-r--r--vendor/assets/javascripts/notebooklab.js5733
-rw-r--r--yarn.lock36
639 files changed, 3975 insertions, 8314 deletions
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index f188ee29223..12385b293c0 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -1,4 +1,4 @@
-image: "dev.gitlab.org:5005/gitlab/gitlab-build-images:ruby-2.3.3-golang-1.8-git-2.7-phantomjs-2.1-node-7.1"
+image: "dev.gitlab.org:5005/gitlab/gitlab-build-images:ruby-2.3.3-golang-1.8-git-2.7-phantomjs-2.1-node-7.1-postgresql-9.6"
cache:
key: "ruby-233"
@@ -10,8 +10,6 @@ variables:
RAILS_ENV: "test"
NODE_ENV: "test"
SIMPLECOV: "true"
- SETUP_DB: "true"
- USE_BUNDLE_INSTALL: "true"
GIT_DEPTH: "20"
PHANTOMJS_VERSION: "2.1.1"
GET_SOURCES_ATTEMPTS: "3"
@@ -19,12 +17,9 @@ variables:
KNAPSACK_SPINACH_SUITE_REPORT_PATH: knapsack/${CI_PROJECT_NAME}/spinach_report-master.json
before_script:
- - source ./scripts/prepare_build.sh
- - cp config/gitlab.yml.example config/gitlab.yml
- bundle --version
- - '[ "$USE_BUNDLE_INSTALL" != "true" ] || retry bundle install --without postgres production --jobs $(nproc) --clean $FLAGS'
- - retry gem install knapsack fog-aws mime-types
- - '[ "$SETUP_DB" != "true" ] || bundle exec rake db:drop db:create db:schema:load db:migrate add_limits_mysql'
+ - . scripts/utils.sh
+ - ./scripts/prepare_build.sh
stages:
- prepare
@@ -52,20 +47,34 @@ stages:
paths:
- knapsack/
-.use-db: &use-db
+.use-pg: &use-pg
+ services:
+ - postgres:latest
+ - redis:alpine
+
+.use-mysql: &use-mysql
services:
- mysql:latest
- redis:alpine
+.only-master-and-ee-or-mysql: &only-master-and-ee-or-mysql
+ only:
+ - /\-(?i)mysql$/
+ - master@gitlab-org/gitlab-ce
+ - master@gitlab/gitlabhq
+ - tags@gitlab-org/gitlab-ce
+ - tags@gitlab/gitlabhq
+ - //@gitlab-org/gitlab-ee
+ - //@gitlab/gitlab-ee
+
.rspec-knapsack: &rspec-knapsack
stage: test
<<: *dedicated-runner
- <<: *use-db
script:
- JOB_NAME=( $CI_JOB_NAME )
- - export CI_NODE_INDEX=${JOB_NAME[1]}
- - export CI_NODE_TOTAL=${JOB_NAME[2]}
- - export KNAPSACK_REPORT_PATH=knapsack/${CI_PROJECT_NAME}/${JOB_NAME[0]}_node_${CI_NODE_INDEX}_${CI_NODE_TOTAL}_report.json
+ - export CI_NODE_INDEX=${JOB_NAME[-2]}
+ - export CI_NODE_TOTAL=${JOB_NAME[-1]}
+ - export KNAPSACK_REPORT_PATH=knapsack/${CI_PROJECT_NAME}/${JOB_NAME[0]}_${JOB_NAME[1]}_node_${CI_NODE_INDEX}_${CI_NODE_TOTAL}_report.json
- export KNAPSACK_GENERATE_REPORT=true
- export CACHE_CLASSES=true
- cp ${KNAPSACK_RSPEC_SUITE_REPORT_PATH} ${KNAPSACK_REPORT_PATH}
@@ -78,15 +87,23 @@ stages:
- knapsack/
- tmp/capybara/
+.rspec-knapsack-pg: &rspec-knapsack-pg
+ <<: *rspec-knapsack
+ <<: *use-pg
+
+.rspec-knapsack-mysql: &rspec-knapsack-mysql
+ <<: *rspec-knapsack
+ <<: *use-mysql
+ <<: *only-master-and-ee-or-mysql
+
.spinach-knapsack: &spinach-knapsack
stage: test
<<: *dedicated-runner
- <<: *use-db
script:
- JOB_NAME=( $CI_JOB_NAME )
- - export CI_NODE_INDEX=${JOB_NAME[1]}
- - export CI_NODE_TOTAL=${JOB_NAME[2]}
- - export KNAPSACK_REPORT_PATH=knapsack/${CI_PROJECT_NAME}/${JOB_NAME[0]}_node_${CI_NODE_INDEX}_${CI_NODE_TOTAL}_report.json
+ - export CI_NODE_INDEX=${JOB_NAME[-2]}
+ - export CI_NODE_TOTAL=${JOB_NAME[-1]}
+ - export KNAPSACK_REPORT_PATH=knapsack/${CI_PROJECT_NAME}/${JOB_NAME[0]}_${JOB_NAME[1]}_node_${CI_NODE_INDEX}_${CI_NODE_TOTAL}_report.json
- export KNAPSACK_GENERATE_REPORT=true
- export CACHE_CLASSES=true
- cp ${KNAPSACK_SPINACH_SUITE_REPORT_PATH} ${KNAPSACK_REPORT_PATH}
@@ -99,6 +116,15 @@ stages:
- knapsack/
- tmp/capybara/
+.spinach-knapsack-pg: &spinach-knapsack-pg
+ <<: *spinach-knapsack
+ <<: *use-pg
+
+.spinach-knapsack-mysql: &spinach-knapsack-mysql
+ <<: *spinach-knapsack
+ <<: *use-mysql
+ <<: *only-master-and-ee-or-mysql
+
# Prepare and merge knapsack tests
knapsack:
<<: *knapsack-state
@@ -116,8 +142,8 @@ update-knapsack:
<<: *dedicated-runner
stage: post-test
script:
- - scripts/merge-reports ${KNAPSACK_RSPEC_SUITE_REPORT_PATH} knapsack/${CI_PROJECT_NAME}/rspec_node_*.json
- - scripts/merge-reports ${KNAPSACK_SPINACH_SUITE_REPORT_PATH} knapsack/${CI_PROJECT_NAME}/spinach_node_*.json
+ - scripts/merge-reports ${KNAPSACK_RSPEC_SUITE_REPORT_PATH} knapsack/${CI_PROJECT_NAME}/rspec_pg_node_*.json
+ - scripts/merge-reports ${KNAPSACK_SPINACH_SUITE_REPORT_PATH} knapsack/${CI_PROJECT_NAME}/spinach_pg_node_*.json
- '[[ -z ${KNAPSACK_S3_BUCKET} ]] || scripts/sync-reports put $KNAPSACK_S3_BUCKET $KNAPSACK_RSPEC_SUITE_REPORT_PATH $KNAPSACK_SPINACH_SUITE_REPORT_PATH'
- rm -f knapsack/${CI_PROJECT_NAME}/*_node_*.json
only:
@@ -127,7 +153,7 @@ update-knapsack:
- master@gitlab/gitlab-ee
setup-test-env:
- <<: *use-db
+ <<: *use-pg
<<: *dedicated-runner
stage: prepare
script:
@@ -142,37 +168,69 @@ setup-test-env:
- public/assets
- tmp/tests
-rspec 0 20: *rspec-knapsack
-rspec 1 20: *rspec-knapsack
-rspec 2 20: *rspec-knapsack
-rspec 3 20: *rspec-knapsack
-rspec 4 20: *rspec-knapsack
-rspec 5 20: *rspec-knapsack
-rspec 6 20: *rspec-knapsack
-rspec 7 20: *rspec-knapsack
-rspec 8 20: *rspec-knapsack
-rspec 9 20: *rspec-knapsack
-rspec 10 20: *rspec-knapsack
-rspec 11 20: *rspec-knapsack
-rspec 12 20: *rspec-knapsack
-rspec 13 20: *rspec-knapsack
-rspec 14 20: *rspec-knapsack
-rspec 15 20: *rspec-knapsack
-rspec 16 20: *rspec-knapsack
-rspec 17 20: *rspec-knapsack
-rspec 18 20: *rspec-knapsack
-rspec 19 20: *rspec-knapsack
-
-spinach 0 10: *spinach-knapsack
-spinach 1 10: *spinach-knapsack
-spinach 2 10: *spinach-knapsack
-spinach 3 10: *spinach-knapsack
-spinach 4 10: *spinach-knapsack
-spinach 5 10: *spinach-knapsack
-spinach 6 10: *spinach-knapsack
-spinach 7 10: *spinach-knapsack
-spinach 8 10: *spinach-knapsack
-spinach 9 10: *spinach-knapsack
+rspec pg 0 20: *rspec-knapsack-pg
+rspec pg 1 20: *rspec-knapsack-pg
+rspec pg 2 20: *rspec-knapsack-pg
+rspec pg 3 20: *rspec-knapsack-pg
+rspec pg 4 20: *rspec-knapsack-pg
+rspec pg 5 20: *rspec-knapsack-pg
+rspec pg 6 20: *rspec-knapsack-pg
+rspec pg 7 20: *rspec-knapsack-pg
+rspec pg 8 20: *rspec-knapsack-pg
+rspec pg 9 20: *rspec-knapsack-pg
+rspec pg 10 20: *rspec-knapsack-pg
+rspec pg 11 20: *rspec-knapsack-pg
+rspec pg 12 20: *rspec-knapsack-pg
+rspec pg 13 20: *rspec-knapsack-pg
+rspec pg 14 20: *rspec-knapsack-pg
+rspec pg 15 20: *rspec-knapsack-pg
+rspec pg 16 20: *rspec-knapsack-pg
+rspec pg 17 20: *rspec-knapsack-pg
+rspec pg 18 20: *rspec-knapsack-pg
+rspec pg 19 20: *rspec-knapsack-pg
+
+rspec mysql 0 20: *rspec-knapsack-mysql
+rspec mysql 1 20: *rspec-knapsack-mysql
+rspec mysql 2 20: *rspec-knapsack-mysql
+rspec mysql 3 20: *rspec-knapsack-mysql
+rspec mysql 4 20: *rspec-knapsack-mysql
+rspec mysql 5 20: *rspec-knapsack-mysql
+rspec mysql 6 20: *rspec-knapsack-mysql
+rspec mysql 7 20: *rspec-knapsack-mysql
+rspec mysql 8 20: *rspec-knapsack-mysql
+rspec mysql 9 20: *rspec-knapsack-mysql
+rspec mysql 10 20: *rspec-knapsack-mysql
+rspec mysql 11 20: *rspec-knapsack-mysql
+rspec mysql 12 20: *rspec-knapsack-mysql
+rspec mysql 13 20: *rspec-knapsack-mysql
+rspec mysql 14 20: *rspec-knapsack-mysql
+rspec mysql 15 20: *rspec-knapsack-mysql
+rspec mysql 16 20: *rspec-knapsack-mysql
+rspec mysql 17 20: *rspec-knapsack-mysql
+rspec mysql 18 20: *rspec-knapsack-mysql
+rspec mysql 19 20: *rspec-knapsack-mysql
+
+spinach pg 0 10: *spinach-knapsack-pg
+spinach pg 1 10: *spinach-knapsack-pg
+spinach pg 2 10: *spinach-knapsack-pg
+spinach pg 3 10: *spinach-knapsack-pg
+spinach pg 4 10: *spinach-knapsack-pg
+spinach pg 5 10: *spinach-knapsack-pg
+spinach pg 6 10: *spinach-knapsack-pg
+spinach pg 7 10: *spinach-knapsack-pg
+spinach pg 8 10: *spinach-knapsack-pg
+spinach pg 9 10: *spinach-knapsack-pg
+
+spinach mysql 0 10: *spinach-knapsack-mysql
+spinach mysql 1 10: *spinach-knapsack-mysql
+spinach mysql 2 10: *spinach-knapsack-mysql
+spinach mysql 3 10: *spinach-knapsack-mysql
+spinach mysql 4 10: *spinach-knapsack-mysql
+spinach mysql 5 10: *spinach-knapsack-mysql
+spinach mysql 6 10: *spinach-knapsack-mysql
+spinach mysql 7 10: *spinach-knapsack-mysql
+spinach mysql 8 10: *spinach-knapsack-mysql
+spinach mysql 9 10: *spinach-knapsack-mysql
# Other generic tests
.ruby-static-analysis: &ruby-static-analysis
@@ -228,24 +286,37 @@ rake ee_compat_check:
paths:
- ee_compat_check/patches/*.patch
-rake db:migrate:reset:
+.db-migrate-reset: &db-migrate-reset
stage: test
- <<: *use-db
<<: *dedicated-runner
script:
- bundle exec rake db:migrate:reset
-rake db:rollback:
+rake pg db:migrate:reset:
+ <<: *db-migrate-reset
+ <<: *use-pg
+
+rake mysql db:migrate:reset:
+ <<: *db-migrate-reset
+ <<: *use-mysql
+
+.db-rollback: &db-rollback
stage: test
- <<: *use-db
<<: *dedicated-runner
script:
- bundle exec rake db:rollback STEP=120
- bundle exec rake db:migrate
-rake db:seed_fu:
+rake pg db:rollback:
+ <<: *db-rollback
+ <<: *use-pg
+
+rake mysql db:rollback:
+ <<: *db-rollback
+ <<: *use-mysql
+
+.db-seed_fu: &db-seed_fu
stage: test
- <<: *use-db
<<: *dedicated-runner
variables:
SIZE: "1"
@@ -261,6 +332,14 @@ rake db:seed_fu:
paths:
- log/development.log
+rake pg db:seed_fu:
+ <<: *db-seed_fu
+ <<: *use-pg
+
+rake mysql db:seed_fu:
+ <<: *db-seed_fu
+ <<: *use-mysql
+
rake gitlab:assets:compile:
stage: test
<<: *dedicated-runner
@@ -285,7 +364,7 @@ rake karma:
paths:
- vendor/ruby
stage: test
- <<: *use-db
+ <<: *use-pg
<<: *dedicated-runner
variables:
BABEL_ENV: "coverage"
@@ -342,9 +421,8 @@ bundler:audit:
script:
- "bundle exec bundle-audit check --update --ignore CVE-2016-4658"
-migration paths:
+.migration-paths: &migration-paths
stage: test
- <<: *use-db
<<: *dedicated-runner
variables:
SETUP_DB: "false"
@@ -356,13 +434,21 @@ migration paths:
script:
- git fetch origin v8.14.10
- git checkout -f FETCH_HEAD
- - bundle install --without postgres production --jobs $(nproc) $FLAGS --retry=3
+ - bundle install $BUNDLE_INSTALL_FLAGS
- bundle exec rake db:drop db:create db:schema:load db:seed_fu
- git checkout $CI_COMMIT_SHA
- - bundle install --without postgres production --jobs $(nproc) $FLAGS --retry=3
- - source scripts/prepare_build.sh
+ - bundle install $BUNDLE_INSTALL_FLAGS
+ - . scripts/prepare_build.sh
- bundle exec rake db:migrate
+migration pg paths:
+ <<: *migration-paths
+ <<: *use-pg
+
+migration mysql paths:
+ <<: *migration-paths
+ <<: *use-mysql
+
coverage:
stage: post-test
services: []
@@ -409,7 +495,7 @@ trigger_docs:
before_script:
- apk update && apk add curl
variables:
- GIT_STRATEGY: none
+ GIT_STRATEGY: "none"
cache: {}
artifacts: {}
script:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 4047a5b6f32..977a7927615 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,6 +2,266 @@
documentation](doc/development/changelog.md) for instructions on adding your own
entry.
+## 9.1.0 (2017-04-22)
+
+- Added merge requests empty state. !7342
+- Add option to start a new resolvable discussion in an MR. !7527
+- Hide form inputs for group member without editing rights. !7816
+- Create a new issue for a single discussion in a Merge Request. !8266 (Bob Van Landuyt)
+- Adding non_archived scope for counting projects. !8305 (Naveen Kumar)
+- Don't show links to tag a commit for users that are not permitted. !8407
+- New file from interface on existing branch. !8427 (Jacopo Beschi @jacopo-beschi)
+- Strip reference prefixes on branch creation. !8498 (Matthieu Tardy)
+- Support 2FA requirement per-group. !8763 (Markus Koller)
+- Add Undo to Todos in the Done tab. !8782 (Jacopo Beschi @jacopo-beschi)
+- Shows 'Go Back' link only when browser history is available. !9017
+- Implement user create service. !9220 (George Andrinopoulos)
+- Incorporate Gitaly client for refs service. !9291
+- Cancel pending pipelines if commits not HEAD. !9362 (Rydkin Maxim)
+- Add indication for closed or merged issuables in GFM. !9462 (Adam Buckland)
+- Periodically clean up temporary upload files to recover storage space. !9466 (blackst0ne)
+- Use toggle button to expand / collapse mulit-nested groups. !9501
+- Fixes dismissable error close is not visible enough. !9516
+- Fixes an issue in the new merge request form, where a tag would be selected instead of a branch when they have the same names. !9535 (Weiqing Chu)
+- Expose CI/CD status API endpoints with Gitlab::Ci::Status facility on pipeline, job and merge request for favicon. !9561 (dosuken123)
+- Use Gitaly for CommitController#show. !9629
+- Order milestone issues by position ascending in api. !9635 (George Andrinopoulos)
+- Convert Issue into ES6 class. !9636 (winniehell)
+- Link issuable reference to itself in meta-header. !9641 (mhasbini)
+- Add ability to disable Merge Request URL on push. !9663 (Alex Sanford)
+- ProjectsFinder should handle more options. !9682 (Jacopo Beschi @jacopo-beschi)
+- Fix create issue form buttons are misaligned on mobile. !9706 (TM Lee)
+- Labels support color names in backend. !9725 (Dongqing Hu)
+- Standardize on core-js for es2015 polyfills. !9749
+- Fix GitHub Import deleting branches for open PRs from a fork. !9758
+- Do not show LFS object when LFS is disabled. !9779 (Christopher Bartz)
+- Fix symlink icon in project tree. !9780 (mhasbini)
+- Fix bug when system hook for deploy key. !9796 (billy.lb)
+- Make authorized projects worker use a specific queue instead of the default one. !9813
+- Simplify trigger_docs build job for CE and EE. !9820 (winniehell)
+- Add `aria-label` for feature status accessibility. !9830
+- Add dashboard and group milestones count badges. !9836 (Alex Braha Stoll)
+- Use Gitaly for Repository#is_ancestor. !9864
+- After copying a diff file or blob path, pasting it into a comment field will format it as Markdown. !9876
+- Fix visibility level on new project page. !9885 (blackst0ne)
+- Fix xml.updated field in rss/atom feeds. !9889 (blackst0ne)
+- Add Undo mark all as done to Todos. !9890 (Jacopo Beschi @jacopo-beschi)
+- Add a name field to the group form. !9891 (Douglas Lovell)
+- Add custom attributes in factories. !9892 (George Andrinopoulos)
+- Resolve project pipeline status caching problem on dashboard. !9895
+- Display error message when deleting tag in web UI fails. !9906
+- Add quick submit for snippet forms. !9911 (blackst0ne)
+- New directory from interface on existing branch. !9921 (Jacopo Beschi @jacopo-beschi)
+- Removes UJS from pipelines tables. !9929
+- Fix project title validation, prevent clicking on disabled button. !9931
+- Show correct user & creation time in heading of the pipeline page. !9936
+- Include time tracking attributes in webhooks payload. !9942
+- Add `requirements: { id: /.+/ }` for all projects and groups namespaced API routes. !9944
+- Improved UX for the environments metrics view. !9946
+- Remove whitespace in group links. !9947 (Xurxo Méndez Pérez)
+- Adds Frontend Styleguide to documentation. !9961
+- Add metadata to system notes. !9964
+- When viewing old wiki page version, edit button should be disabled. !9966 (TM Lee)
+- Added labels array to the issue web hook returned object. !9972
+- Upgrade VueJS to v2.2.4 and disable dev mode warnings. !9981
+- Only add code coverage instrumentation when generating coverage report. !9987
+- Fix Project Wiki update. !9990 (Dongqing Hu)
+- Fix trigger webhook for ref with a dot. !10001 (George Andrinopoulos)
+- Fix quick submit short-cut on preview tab for comments. !10002
+- Add option to receive email notifications about your own activity. !10032 (Richard Macklin)
+- Rename 'All issues' to 'Open issues' in Add issues modal. !10042 (blackst0ne)
+- Disable pipeline and environment actions that are not playable. !10052
+- Added clarification to the Jira integration documentation. !10066 (Matthew Bender)
+- Move milestone summary content into the sidebar. !10096
+- Replace closing MR icon. !10103 (blackst0ne)
+- Add support for multi-level container image repository names. !10109 (André Guede)
+- Add ECMAScript polyfills for Symbol and Array.find. !10120
+- Add tooltip to user's calendar activities. !10123 (Alex Argunov)
+- Resolve "Run CI/CD pipelines on a schedule" - "Basic backend implementation". !10133 (dosuken123)
+- Change hint on first row of filters dropdown to `Press Enter or click to search`. !10138
+- Remove useless queries with false conditions (e.g 1=0). !10141 (mhasbini)
+- Show CI status as Favicon on Pipelines, Job and MR pages. !10144
+- Update color palette to a more harmonious and consistent one. !10154
+- Add tooltip and accessibility for profile cover buttons. !10182
+- Change Done column to Closed in issue boards. !10198 (blackst0ne)
+- Add metrics button to environments overview page. !10234
+- Force unlimited terminal size when checking processes via call to ps. !10246 (Sebastian Reitenbach)
+- Fix sub-nav highlighting for `Environments` and `Jobs` pages. !10254
+- Drop support for correctly processing legacy pipelines. !10266
+- Fix project creation failure due to race condition in namespace directory creation. !10268 (Robin Bobbitt)
+- Introduced error/empty states for the environments performance metrics. !10271
+- Improve performance of GitHub importer for large repositories. !10273
+- Introduce "polling_interval_multiplier" as application setting. !10280
+- Prevent users from disconnecting GitLab account from CAS. !10282
+- Clearly show who triggered the pipeline in email. !10283
+- Make user mentions case-insensitive. !10285 (blackst0ne)
+- Update rugged to 0.25.1.1. !10286 (Elan Ruusamäe)
+- Handle parsing OpenBSD ps output properly to display sidekiq infos on admin->monitoring->background. !10303 (Sebastian Reitenbach)
+- Log errors during generating of Gitlab Pages to debug log. !10335 (Danilo Bargen)
+- Update issue board cards design. !10353
+- Tags can be protected, restricting creation of matching tags by user role. !10356
+- Set GIT_TERMINAL_PROMPT env variable in initializer. !10372
+- Remove index for users.current sign in at. !10401 (blackst0ne)
+- Include reopened MRs when searching for opened ones. !10407
+- Integrates Microsoft Teams webhooks with GitLab. !10412
+- Fix subgroup repository disappearance if group was moved. !10414
+- Add /-/readiness /-/liveness and /-/metrics endpoints to track application health. !10416
+- Changed capitalisation of buttons across GitLab. !10418
+- Fix blob highlighting in search. !10420
+- Add remove_concurrent_index to database helper. !10441 (blackst0ne)
+- Fix wiki commit message. !10464 (blackst0ne)
+- Deleting a user should not delete associated records. !10467
+- Include endpoint in metrics for ETag caching middleware. !10495
+- Change project view default for existing users and anonymous visitors to files+readme. !10498
+- Hide header counters for issue/mr/todos if zero. !10506
+- Remove the User#is_admin? method. !10520 (blackst0ne)
+- Removed Milestone#is_empty?. !10523 (Jacopo Beschi @jacopo-beschi)
+- Add UI for Trigger Schedule. !10533 (dosuken123)
+- Add foreign key for ci_trigger_requests on ci_triggers. !10537
+- Upgrade webpack to v2.3.3 and webpack-dev-server to v2.4.2. !10552
+- Bugfix: POST /projects/:id/hooks and PUT /projects/:id/hook/:hook_id no longer ignore the the job_events param in the V4 API. !10586
+- Fix MR widget bug that merged a MR when Merge when pipeline succeeds was clicked via the dropdown. !10611
+- Hide new subgroup button if user has no permission to create one. !10627
+- Fix PlantUML integration in GFM. !10651
+- Show sub-nav under Merge Requests when issue tracker is non-default. !10658
+- Fix bad query for PostgreSQL showing merge requests list. !10666
+- Fix invalid encoding when showing some traces. !10681
+- Add lighter colors and fix existing light colors. !10690
+- Fix another case where trace does not have proper encoding set. !10728
+- Fix trace cannot be written due to encoding. !10758
+- Replace builds_enabled with jobs_enabled in projects API v4. !10786 (winniehell)
+- Add retry to system hook worker. !10801
+- Fix error when an issue reference has a pending deleting project. !10843
+- Update permalink/blame buttons with line number fragment hash.
+- Limit line length for project home page.
+- Fix filtered search input width for IE.
+- Update wikis_controller.rb to use strong params.
+- Fix API group/issues default state filter. (Alexander Randa)
+- Prevent builds dropdown to close when the user clicks in a build.
+- Display all closed issues in “done” board list.
+- Remove no-new annotation from file_template_mediator.js.
+- Changed dropdown style slightly.
+- Change gfm textarea to use monospace font.
+- Prevent filtering issues by multiple Milestones or Authors.
+- Recent search history for issues.
+- Remove duplicated tokens in issuable search bar.
+- Adds empty and error state to pipelines.
+- Allow admin to view all namespaces. (George Andrinopoulos)
+- allow offset query parameter for infinite list pages.
+- Fix wrong message on starred projects filtering. (George Andrinopoulos)
+- Adds pipeline mini-graph to system information box in Commit View.
+- Remove confusing placeholder for JIRA transition_id.
+- Remove extra margin at bottom of todos page.
+- Add back expandable folder behavior.
+- Create todos only for new mentions.
+- Linking to blob edit page handles anonymous users and users without enough permissions to edit directly.
+- Fix projects_limit RangeError on user create. (Alexander Randa)
+- Add helpful icons to profile events.
+- Refactor dropdown_milestone_spec.rb. (George Andrinopoulos)
+- Fix alignment of resolve button.
+- Change label for name on sign up form.
+- Don’t show source project name when user does not have access.
+- Update toggle buttons to be <button>.
+- Display full project name with namespace upon deletion.
+- Spam check only when spammable attributes have changed.
+- align Mark all as done with other Done buttons on Todos page.
+- Adds polling utility function for vue resource.
+- Allow unauthenticated access to some Branch API GET endpoints.
+- Fix redirection after login when the referer have params. (mhasbini)
+- fix sidebar padding for build and wiki pages.
+- Correctly update paths when changing a child group.
+- Add shortcuts and counters to MRs and issues in navbar.
+- Remove forced scroll into view when switching to Changes MR tab.
+- Fix link to Jira service documentation.
+- consistent icons in vue and kaminari pagers.
+- refocus textarea after attaching a file.
+- Enable creation of deploy keys with write access via the API.
+- Disable invalid service templates.
+- Remove the class attribute from the whitelist for HTML generated from Markdown.
+- Add search optional param and docs for V4.
+- Fix issue's note cache expiration after delete. (mhasbini)
+- Fixes HTML structure that was preventing the tooltip to disappear when hovering out of the button.
+- fix Status icons overlapping sidebar on mobile.
+- Add dropdown sort to project milestones. (George Andrinopoulos)
+- Prevent more than one issue tracker to be active for the same project. (luisdgs19)
+- Add copy button to blob header and use icon for Raw button.
+- Add metrics events for incoming emails.
+- Shows loading icon in issue boards modal when changing filters.
+- Added tests for the w.gl.utils.backOff promise.
+- Add `g t` global shortcut to go to todos.
+- Fix conflict resolution when files contain valid UTF-8 characters.
+- Added award emoji animation and improved active state.
+- Fixes milestone/merge_requests endpoint to actually scope the result. (Joren De Groof)
+- Added remaining_time method to milestoneish, specs and updated the milestone_helper milestone_remaining_days method to correctly return the correct remaining time. (Michael Robinson)
+- Removed unnecessary 'add' text in additional award emoji button.
+- adds todo functionality to closed issuable sidebar and changes todo bell icon to check-square.
+- Copy code as GFM from diffs, blobs and GFM code blocks.
+- Removed the duplicated search icon in the award emoji menu.
+- Enable snippets for new projects by default.
+- Add rake task to import GitHub projects from the command line.
+- New rake task to reset all email and private tokens.
+- Fix path disclosure in project import/export.
+- Fix 'Object not found - no match for id (sha)' when importing GitHub Pull Requests.
+- Display custom hook error messages when automatic merge is enabled.
+- Fix layout of projects page on admin area.
+- Fix encoding issue exporting a project.
+- Periodically mark projects that are stuck in importing as failed.
+- Skip groups validation on the client.
+- Fix Import/Export MR diffs not showing and missing forked MRs.
+- Create subgroups if they don't exist while importing projects.
+- Fix Milestone name on show page. (Raveesh)
+- Fix missing capitalisation on views.
+- Removed orphaned notification settings without a namespace.
+- Fix restricted project visibility setting available to users.
+- Moved the gear settings dropdown to a tab in the groups view.
+- Fixed group milestone date dropdowns not opening.
+- Fixed bug in issue boards which stopped cards being able to be dragged.
+- Added new filtered search bar to issue boards.
+- Add closed_at field to issues.
+- Do not set closed_at to nil when issue is reopened.
+- Centered issues empty state.
+- Fixed private group name disclosure via new/update forms.
+- Add keyboard shortcuts to main menu.
+- Moved the monitoring button inside the show view for the environments page.
+- Speed up initial rendering of MR diffs page.
+- Fixed tabs on new merge request page causing incorrect URLs.
+- Fix for open redirect vulnerability using continue[to] in URL when requesting project import status.
+- Fix for open redirect vulnerabilities in todos, issues, and MR controllers.
+- Optimise builds endpoint.
+- Fixed pipeline actions tooltips overflowing.
+- Fixed job tooltip being cut-off.
+- Fixed projects list lines breaking.
+- Only email pipeline creators; only email for successful pipelines with custom settings.
+- Reset users.authorized_projects_populated to automatically refresh user permissions.
+- Corrected alignment for the remember-me checkbox in the login view.
+- Fixed tabs not scrolling on mobile.
+- Add unique index for notes_id to system note metadata table.
+- Handle SSH keys that have multiple spaces between each marker.
+- Don't delete a branch involved in an open merge request in "Delete all merged branches" service.
+- Relax constraint on Wiki IDs, since subdirectories can contain spaces.
+- Remove Tags filter from Projects Explore dropdown.
+- Enable Style/Proc cop for rubocop. (mhasbini)
+- Show the build/pipeline coverage if it is available.
+- Corrected time tracking icon color in the issuable side bar.
+- update test_bundle.js ignored files.
+- Add usage ping to CE.
+- User callout only shows on current users profile.
+- Removed the hours & minutes from the users start date on their profile.
+- Only send chat notifications for the default branch.
+- Don't fill in the default kubernetes namespace.
+
+## 9.0.6 (2017-04-21)
+
+- Bugfix: POST /projects/:id/hooks and PUT /projects/:id/hook/:hook_id no longer ignore the the job_events param in the V4 API. !10586
+- Fix MR widget bug that merged a MR when Merge when pipeline succeeds was clicked via the dropdown. !10611
+- Fix PlantUML integration in GFM. !10651
+- Show sub-nav under Merge Requests when issue tracker is non-default. !10658
+- Fix restricted project visibility setting available to users.
+- Removed orphaned notification settings without a namespace.
+- Fix issue's note cache expiration after delete. (mhasbini)
+- Display custom hook error messages when automatic merge is enabled.
+- Fix filtered search input width for IE.
+
## 9.0.5 (2017-04-10)
- Add shortcuts and counters to MRs and issues in navbar.
diff --git a/README.md b/README.md
index f0e3b52ef6f..10d69efdc6b 100644
--- a/README.md
+++ b/README.md
@@ -73,7 +73,7 @@ One small thing you also have to do when installing it yourself is to copy the e
cp config/unicorn.rb.example.development config/unicorn.rb
-Instructions on how to start GitLab and how to run the tests can be found in the [development section of the GitLab Development Kit](https://gitlab.com/gitlab-org/gitlab-development-kit#development).
+Instructions on how to start GitLab and how to run the tests can be found in the [getting started section of the GitLab Development Kit](https://gitlab.com/gitlab-org/gitlab-development-kit#getting-started).
## Software stack
diff --git a/VERSION b/VERSION
index c3996a4a61f..5c906509f70 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-9.1.0-pre
+9.2.0-pre
diff --git a/app/assets/javascripts/blob/blob_fork_suggestion.js b/app/assets/javascripts/blob/blob_fork_suggestion.js
index 3baf81905fe..47c431fb809 100644
--- a/app/assets/javascripts/blob/blob_fork_suggestion.js
+++ b/app/assets/javascripts/blob/blob_fork_suggestion.js
@@ -16,47 +16,44 @@ const defaults = {
class BlobForkSuggestion {
constructor(options) {
this.elementMap = Object.assign({}, defaults, options);
- this.onClickWrapper = this.onClick.bind(this);
-
- document.addEventListener('click', this.onClickWrapper);
+ this.onOpenButtonClick = this.onOpenButtonClick.bind(this);
+ this.onCancelButtonClick = this.onCancelButtonClick.bind(this);
}
- showSuggestionSection(forkPath, action = 'edit') {
- [].forEach.call(this.elementMap.suggestionSections, (suggestionSection) => {
- suggestionSection.classList.remove('hidden');
- });
+ init() {
+ this.bindEvents();
- [].forEach.call(this.elementMap.forkButtons, (forkButton) => {
- forkButton.setAttribute('href', forkPath);
- });
+ return this;
+ }
- [].forEach.call(this.elementMap.actionTextPieces, (actionTextPiece) => {
- // eslint-disable-next-line no-param-reassign
- actionTextPiece.textContent = action;
- });
+ bindEvents() {
+ $(this.elementMap.openButtons).on('click', this.onOpenButtonClick);
+ $(this.elementMap.cancelButtons).on('click', this.onCancelButtonClick);
}
- hideSuggestionSection() {
- [].forEach.call(this.elementMap.suggestionSections, (suggestionSection) => {
- suggestionSection.classList.add('hidden');
- });
+ showSuggestionSection(forkPath, action = 'edit') {
+ $(this.elementMap.suggestionSections).removeClass('hidden');
+ $(this.elementMap.forkButtons).attr('href', forkPath);
+ $(this.elementMap.actionTextPieces).text(action);
}
- onClick(e) {
- const el = e.target;
+ hideSuggestionSection() {
+ $(this.elementMap.suggestionSections).addClass('hidden');
+ }
- if ([].includes.call(this.elementMap.openButtons, el)) {
- const { forkPath, action } = el.dataset;
- this.showSuggestionSection(forkPath, action);
- }
+ onOpenButtonClick(e) {
+ const forkPath = $(e.currentTarget).attr('data-fork-path');
+ const action = $(e.currentTarget).attr('data-action');
+ this.showSuggestionSection(forkPath, action);
+ }
- if ([].includes.call(this.elementMap.cancelButtons, el)) {
- this.hideSuggestionSection();
- }
+ onCancelButtonClick() {
+ this.hideSuggestionSection();
}
destroy() {
- document.removeEventListener('click', this.onClickWrapper);
+ $(this.elementMap.openButtons).off('click', this.onOpenButtonClick);
+ $(this.elementMap.cancelButtons).off('click', this.onCancelButtonClick);
}
}
diff --git a/app/assets/javascripts/blob/notebook/index.js b/app/assets/javascripts/blob/notebook/index.js
index 9b8bfbfc8c0..36fe8a7184f 100644
--- a/app/assets/javascripts/blob/notebook/index.js
+++ b/app/assets/javascripts/blob/notebook/index.js
@@ -1,10 +1,9 @@
/* eslint-disable no-new */
import Vue from 'vue';
import VueResource from 'vue-resource';
-import NotebookLab from 'vendor/notebooklab';
+import notebookLab from '../../notebook/index.vue';
Vue.use(VueResource);
-Vue.use(NotebookLab);
export default () => {
const el = document.getElementById('js-notebook-viewer');
@@ -19,6 +18,9 @@ export default () => {
json: {},
};
},
+ components: {
+ notebookLab,
+ },
template: `
<div class="container-fluid md prepend-top-default append-bottom-default">
<div
diff --git a/app/assets/javascripts/commit/pipelines/pipelines_table.js b/app/assets/javascripts/commit/pipelines/pipelines_table.js
index 7438faeadf4..68a1c1de1df 100644
--- a/app/assets/javascripts/commit/pipelines/pipelines_table.js
+++ b/app/assets/javascripts/commit/pipelines/pipelines_table.js
@@ -55,7 +55,15 @@ export default Vue.component('pipelines-table', {
},
shouldRenderEmptyState() {
- return !this.state.pipelines.length && !this.isLoading;
+ return !this.state.pipelines.length &&
+ !this.isLoading &&
+ !this.hasError;
+ },
+
+ shouldRenderTable() {
+ return !this.isLoading &&
+ this.state.pipelines.length > 0 &&
+ !this.hasError;
},
},
@@ -145,8 +153,12 @@ export default Vue.component('pipelines-table', {
template: `
<div class="content-list pipelines">
- <div class="realtime-loading" v-if="isLoading">
- <i class="fa fa-spinner fa-spin"></i>
+ <div
+ class="realtime-loading"
+ v-if="isLoading">
+ <i
+ class="fa fa-spinner fa-spin"
+ aria-hidden="true" />
</div>
<empty-state
@@ -155,8 +167,9 @@ export default Vue.component('pipelines-table', {
<error-state v-if="shouldRenderErrorState" />
- <div class="table-holder"
- v-if="!isLoading && state.pipelines.length > 0">
+ <div
+ class="table-holder"
+ v-if="shouldRenderTable">
<pipelines-table-component
:pipelines="state.pipelines"
:service="service" />
diff --git a/app/assets/javascripts/dispatcher.js b/app/assets/javascripts/dispatcher.js
index 20db2698ba8..b20673cd03c 100644
--- a/app/assets/javascripts/dispatcher.js
+++ b/app/assets/javascripts/dispatcher.js
@@ -97,7 +97,8 @@ const ShortcutsBlob = require('./shortcuts_blob');
cancelButtons: document.querySelectorAll('.js-cancel-fork-suggestion-button'),
suggestionSections: document.querySelectorAll('.js-file-fork-suggestion-section'),
actionTextPieces: document.querySelectorAll('.js-file-fork-suggestion-section-action'),
- });
+ })
+ .init();
}
switch (page) {
diff --git a/app/assets/javascripts/due_date_select.js b/app/assets/javascripts/due_date_select.js
index dd95b6530f6..a8fc5b41fb4 100644
--- a/app/assets/javascripts/due_date_select.js
+++ b/app/assets/javascripts/due_date_select.js
@@ -170,8 +170,9 @@ class DueDateSelectors {
const $datePicker = $(this);
const calendar = new Pikaday({
field: $datePicker.get(0),
- theme: 'gitlab-theme',
+ theme: 'gitlab-theme animate-picker',
format: 'yyyy-mm-dd',
+ container: $datePicker.parent().get(0),
onSelect(dateText) {
$datePicker.val(dateFormat(new Date(dateText), 'yyyy-mm-dd'));
}
diff --git a/app/assets/javascripts/environments/components/environment.js b/app/assets/javascripts/environments/components/environment.js
index 0518422e475..f7175e412da 100644
--- a/app/assets/javascripts/environments/components/environment.js
+++ b/app/assets/javascripts/environments/components/environment.js
@@ -2,7 +2,7 @@
/* global Flash */
import Vue from 'vue';
import EnvironmentsService from '../services/environments_service';
-import EnvironmentTable from './environments_table';
+import EnvironmentTable from './environments_table.vue';
import EnvironmentsStore from '../stores/environments_store';
import TablePaginationComponent from '../../vue_shared/components/table_pagination';
import '../../lib/utils/common_utils';
diff --git a/app/assets/javascripts/environments/components/environment_actions.js b/app/assets/javascripts/environments/components/environment_actions.js
deleted file mode 100644
index 313e78e573a..00000000000
--- a/app/assets/javascripts/environments/components/environment_actions.js
+++ /dev/null
@@ -1,100 +0,0 @@
-/* global Flash */
-/* eslint-disable no-new */
-
-import playIconSvg from 'icons/_icon_play.svg';
-import eventHub from '../event_hub';
-
-export default {
- props: {
- actions: {
- type: Array,
- required: false,
- default: () => [],
- },
-
- service: {
- type: Object,
- required: true,
- },
- },
-
- data() {
- return {
- playIconSvg,
- isLoading: false,
- };
- },
-
- computed: {
- title() {
- return 'Deploy to...';
- },
- },
-
- methods: {
- onClickAction(endpoint) {
- this.isLoading = true;
-
- $(this.$refs.tooltip).tooltip('destroy');
-
- this.service.postAction(endpoint)
- .then(() => {
- this.isLoading = false;
- eventHub.$emit('refreshEnvironments');
- })
- .catch(() => {
- this.isLoading = false;
- new Flash('An error occured while making the request.');
- });
- },
-
- isActionDisabled(action) {
- if (action.playable === undefined) {
- return false;
- }
-
- return !action.playable;
- },
- },
-
- template: `
- <div class="btn-group" role="group">
- <button
- type="button"
- class="dropdown btn btn-default dropdown-new js-dropdown-play-icon-container has-tooltip"
- data-container="body"
- data-toggle="dropdown"
- ref="tooltip"
- :title="title"
- :aria-label="title"
- :disabled="isLoading">
- <span>
- <span v-html="playIconSvg"></span>
- <i
- class="fa fa-caret-down"
- aria-hidden="true"/>
- <i
- v-if="isLoading"
- class="fa fa-spinner fa-spin"
- aria-hidden="true"/>
- </span>
- </button>
-
- <ul class="dropdown-menu dropdown-menu-align-right">
- <li v-for="action in actions">
- <button
- type="button"
- class="js-manual-action-link no-btn btn"
- @click="onClickAction(action.play_path)"
- :class="{ 'disabled': isActionDisabled(action) }"
- :disabled="isActionDisabled(action)">
- ${playIconSvg}
- <span>
- {{action.name}}
- </span>
- </button>
- </li>
- </ul>
- </div>
- `,
-};
diff --git a/app/assets/javascripts/environments/components/environment_actions.vue b/app/assets/javascripts/environments/components/environment_actions.vue
new file mode 100644
index 00000000000..e81c97260d7
--- /dev/null
+++ b/app/assets/javascripts/environments/components/environment_actions.vue
@@ -0,0 +1,103 @@
+<script>
+/* global Flash */
+/* eslint-disable no-new */
+
+import playIconSvg from 'icons/_icon_play.svg';
+import eventHub from '../event_hub';
+
+export default {
+ props: {
+ actions: {
+ type: Array,
+ required: false,
+ default: () => [],
+ },
+
+ service: {
+ type: Object,
+ required: true,
+ },
+ },
+
+ data() {
+ return {
+ playIconSvg,
+ isLoading: false,
+ };
+ },
+
+ computed: {
+ title() {
+ return 'Deploy to...';
+ },
+ },
+
+ methods: {
+ onClickAction(endpoint) {
+ this.isLoading = true;
+
+ $(this.$refs.tooltip).tooltip('destroy');
+
+ this.service.postAction(endpoint)
+ .then(() => {
+ this.isLoading = false;
+ eventHub.$emit('refreshEnvironments');
+ })
+ .catch(() => {
+ this.isLoading = false;
+ new Flash('An error occured while making the request.');
+ });
+ },
+
+ isActionDisabled(action) {
+ if (action.playable === undefined) {
+ return false;
+ }
+
+ return !action.playable;
+ },
+ },
+};
+</script>
+<template>
+ <div
+ class="btn-group"
+ role="group">
+ <button
+ type="button"
+ class="dropdown btn btn-default dropdown-new js-dropdown-play-icon-container has-tooltip"
+ data-container="body"
+ data-toggle="dropdown"
+ ref="tooltip"
+ :title="title"
+ :aria-label="title"
+ :disabled="isLoading">
+ <span>
+ <span v-html="playIconSvg"></span>
+ <i
+ class="fa fa-caret-down"
+ aria-hidden="true"/>
+ <i
+ v-if="isLoading"
+ class="fa fa-spinner fa-spin"
+ aria-hidden="true"/>
+ </span>
+ </button>
+
+ <ul class="dropdown-menu dropdown-menu-align-right">
+ <li v-for="action in actions">
+ <button
+ type="button"
+ class="js-manual-action-link no-btn btn"
+ @click="onClickAction(action.play_path)"
+ :class="{ disabled: isActionDisabled(action) }"
+ :disabled="isActionDisabled(action)">
+ <span v-html="playIconSvg"></span>
+ <span>
+ {{action.name}}
+ </span>
+ </button>
+ </li>
+ </ul>
+ </div>
+</template>
diff --git a/app/assets/javascripts/environments/components/environment_item.js b/app/assets/javascripts/environments/components/environment_item.vue
index 0b174cf97da..73679de6039 100644
--- a/app/assets/javascripts/environments/components/environment_item.js
+++ b/app/assets/javascripts/environments/components/environment_item.vue
@@ -1,6 +1,7 @@
+<script>
import Timeago from 'timeago.js';
import '../../lib/utils/text_utility';
-import ActionsComponent from './environment_actions';
+import ActionsComponent from './environment_actions.vue';
import ExternalUrlComponent from './environment_external_url.vue';
import StopComponent from './environment_stop.vue';
import RollbackComponent from './environment_rollback.vue';
@@ -434,117 +435,140 @@ export default {
eventHub.$emit('toggleFolder', this.model, this.folderUrl);
},
},
-
- template: `
- <tr :class="{ 'js-child-row': model.isChildren }">
- <td>
- <a v-if="!model.isFolder"
- class="environment-name"
- :class="{ 'prepend-left-default': model.isChildren }"
- :href="environmentPath">
- {{model.name}}
- </a>
- <span v-else
- class="folder-name"
- @click="onClickFolder"
- role="button">
-
- <span class="folder-icon">
- <i
- v-show="model.isOpen"
- class="fa fa-caret-down"
- aria-hidden="true" />
- <i
- v-show="!model.isOpen"
- class="fa fa-caret-right"
- aria-hidden="true"/>
- </span>
-
- <span class="folder-icon">
- <i class="fa fa-folder" aria-hidden="true"></i>
- </span>
-
- <span>
- {{model.folderName}}
- </span>
-
- <span class="badge">
- {{model.size}}
- </span>
+};
+</script>
+<template>
+ <tr :class="{ 'js-child-row': model.isChildren }">
+ <td>
+ <a
+ v-if="!model.isFolder"
+ class="environment-name"
+ :class="{ 'prepend-left-default': model.isChildren }"
+ :href="environmentPath">
+ {{model.name}}
+ </a>
+ <span
+ v-else
+ class="folder-name"
+ @click="onClickFolder"
+ role="button">
+
+ <span class="folder-icon">
+ <i
+ v-show="model.isOpen"
+ class="fa fa-caret-down"
+ aria-hidden="true" />
+ <i
+ v-show="!model.isOpen"
+ class="fa fa-caret-right"
+ aria-hidden="true"/>
</span>
- </td>
- <td class="deployment-column">
- <span v-if="shouldRenderDeploymentID">
- {{deploymentInternalId}}
+ <span class="folder-icon">
+ <i
+ class="fa fa-folder"
+ aria-hidden="true" />
</span>
- <span v-if="!model.isFolder && deploymentHasUser">
- by
- <a :href="deploymentUser.web_url" class="js-deploy-user-container">
- <img class="avatar has-tooltip s20"
- :src="deploymentUser.avatar_url"
- :alt="userImageAltDescription"
- :title="deploymentUser.username" />
- </a>
+ <span>
+ {{model.folderName}}
</span>
- </td>
- <td class="environments-build-cell">
- <a v-if="shouldRenderBuildName"
- class="build-link"
- :href="buildPath">
- {{buildName}}
- </a>
- </td>
-
- <td>
- <div v-if="!model.isFolder && hasLastDeploymentKey" class="js-commit-component">
- <commit-component
- :tag="commitTag"
- :commit-ref="commitRef"
- :commit-url="commitUrl"
- :short-sha="commitShortSha"
- :title="commitTitle"
- :author="commitAuthor"/>
- </div>
- <p v-if="!model.isFolder && !hasLastDeploymentKey" class="commit-title">
- No deployments yet
- </p>
- </td>
-
- <td>
- <span v-if="!model.isFolder && canShowDate"
- class="environment-created-date-timeago">
- {{createdDate}}
+ <span class="badge">
+ {{model.size}}
</span>
- </td>
-
- <td class="environments-actions">
- <div v-if="!model.isFolder" class="btn-group pull-right" role="group">
- <actions-component v-if="hasManualActions && canCreateDeployment"
- :service="service"
- :actions="manualActions"/>
-
- <external-url-component v-if="externalURL && canReadEnvironment"
- :external-url="externalURL"/>
-
- <monitoring-button-component v-if="monitoringUrl && canReadEnvironment"
- :monitoring-url="monitoringUrl"/>
-
- <terminal-button-component v-if="model && model.terminal_path"
- :terminal-path="model.terminal_path"/>
-
- <stop-component v-if="hasStopAction && canCreateDeployment"
- :stop-url="model.stop_path"
- :service="service"/>
-
- <rollback-component v-if="canRetry && canCreateDeployment"
- :is-last-deployment="isLastDeployment"
- :retry-url="retryUrl"
- :service="service"/>
- </div>
- </td>
- </tr>
- `,
-};
+ </span>
+ </td>
+
+ <td class="deployment-column">
+ <span v-if="shouldRenderDeploymentID">
+ {{deploymentInternalId}}
+ </span>
+
+ <span v-if="!model.isFolder && deploymentHasUser">
+ by
+ <a
+ :href="deploymentUser.web_url"
+ class="js-deploy-user-container">
+ <img
+ class="avatar has-tooltip s20"
+ :src="deploymentUser.avatar_url"
+ :alt="userImageAltDescription"
+ :title="deploymentUser.username" />
+ </a>
+ </span>
+ </td>
+
+ <td class="environments-build-cell">
+ <a
+ v-if="shouldRenderBuildName"
+ class="build-link"
+ :href="buildPath">
+ {{buildName}}
+ </a>
+ </td>
+
+ <td>
+ <div
+ v-if="!model.isFolder && hasLastDeploymentKey"
+ class="js-commit-component">
+ <commit-component
+ :tag="commitTag"
+ :commit-ref="commitRef"
+ :commit-url="commitUrl"
+ :short-sha="commitShortSha"
+ :title="commitTitle"
+ :author="commitAuthor"/>
+ </div>
+ <p
+ v-if="!model.isFolder && !hasLastDeploymentKey"
+ class="commit-title">
+ No deployments yet
+ </p>
+ </td>
+
+ <td>
+ <span
+ v-if="!model.isFolder && canShowDate"
+ class="environment-created-date-timeago">
+ {{createdDate}}
+ </span>
+ </td>
+
+ <td class="environments-actions">
+ <div
+ v-if="!model.isFolder"
+ class="btn-group pull-right"
+ role="group">
+
+ <actions-component
+ v-if="hasManualActions && canCreateDeployment"
+ :service="service"
+ :actions="manualActions"/>
+
+ <external-url-component
+ v-if="externalURL && canReadEnvironment"
+ :external-url="externalURL"/>
+
+ <monitoring-button-component
+ v-if="monitoringUrl && canReadEnvironment"
+ :monitoring-url="monitoringUrl"/>
+
+ <terminal-button-component
+ v-if="model && model.terminal_path"
+ :terminal-path="model.terminal_path"/>
+
+ <stop-component
+ v-if="hasStopAction && canCreateDeployment"
+ :stop-url="model.stop_path"
+ :service="service"/>
+
+ <rollback-component
+ v-if="canRetry && canCreateDeployment"
+ :is-last-deployment="isLastDeployment"
+ :retry-url="retryUrl"
+ :service="service"/>
+ </div>
+ </td>
+ </tr>
+</template>
diff --git a/app/assets/javascripts/environments/components/environments_table.js b/app/assets/javascripts/environments/components/environments_table.js
deleted file mode 100644
index 5e6af3a1d45..00000000000
--- a/app/assets/javascripts/environments/components/environments_table.js
+++ /dev/null
@@ -1,97 +0,0 @@
-/**
- * Render environments table.
- */
-import EnvironmentTableRowComponent from './environment_item';
-
-export default {
- components: {
- 'environment-item': EnvironmentTableRowComponent,
- },
-
- props: {
- environments: {
- type: Array,
- required: true,
- default: () => ([]),
- },
-
- canReadEnvironment: {
- type: Boolean,
- required: false,
- default: false,
- },
-
- canCreateDeployment: {
- type: Boolean,
- required: false,
- default: false,
- },
-
- service: {
- type: Object,
- required: true,
- },
-
- isLoadingFolderContent: {
- type: Boolean,
- required: false,
- default: false,
- },
- },
-
- methods: {
- folderUrl(model) {
- return `${window.location.pathname}/folders/${model.folderName}`;
- },
- },
-
- template: `
- <table class="table ci-table">
- <thead>
- <tr>
- <th class="environments-name">Environment</th>
- <th class="environments-deploy">Last deployment</th>
- <th class="environments-build">Job</th>
- <th class="environments-commit">Commit</th>
- <th class="environments-date">Updated</th>
- <th class="environments-actions"></th>
- </tr>
- </thead>
- <tbody>
- <template v-for="model in environments"
- v-bind:model="model">
- <tr is="environment-item"
- :model="model"
- :can-create-deployment="canCreateDeployment"
- :can-read-environment="canReadEnvironment"
- :service="service"></tr>
-
- <template v-if="model.isFolder && model.isOpen && model.children && model.children.length > 0">
- <tr v-if="isLoadingFolderContent">
- <td colspan="6" class="text-center">
- <i class="fa fa-spin fa-spinner fa-2x" aria-hidden="true"/>
- </td>
- </tr>
-
- <template v-else>
- <tr is="environment-item"
- v-for="children in model.children"
- :model="children"
- :can-create-deployment="canCreateDeployment"
- :can-read-environment="canReadEnvironment"
- :service="service"></tr>
-
- <tr>
- <td colspan="6" class="text-center">
- <a :href="folderUrl(model)" class="btn btn-default">
- Show all
- </a>
- </td>
- </tr>
- </template>
- </template>
- </template>
- </tbody>
- </table>
- `,
-};
diff --git a/app/assets/javascripts/environments/components/environments_table.vue b/app/assets/javascripts/environments/components/environments_table.vue
new file mode 100644
index 00000000000..87f7cb4a536
--- /dev/null
+++ b/app/assets/javascripts/environments/components/environments_table.vue
@@ -0,0 +1,117 @@
+<script>
+/**
+ * Render environments table.
+ */
+import EnvironmentTableRowComponent from './environment_item.vue';
+
+export default {
+ components: {
+ 'environment-item': EnvironmentTableRowComponent,
+ },
+
+ props: {
+ environments: {
+ type: Array,
+ required: true,
+ default: () => ([]),
+ },
+
+ canReadEnvironment: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
+
+ canCreateDeployment: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
+
+ service: {
+ type: Object,
+ required: true,
+ },
+
+ isLoadingFolderContent: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
+ },
+
+ methods: {
+ folderUrl(model) {
+ return `${window.location.pathname}/folders/${model.folderName}`;
+ },
+ },
+};
+</script>
+<template>
+ <table class="table ci-table">
+ <thead>
+ <tr>
+ <th class="environments-name">
+ Environment
+ </th>
+ <th class="environments-deploy">
+ Last deployment
+ </th>
+ <th class="environments-build">
+ Job
+ </th>
+ <th class="environments-commit">
+ Commit
+ </th>
+ <th class="environments-date">
+ Updated
+ </th>
+ <th class="environments-actions"></th>
+ </tr>
+ </thead>
+ <tbody>
+ <template
+ v-for="model in environments"
+ v-bind:model="model">
+ <tr
+ is="environment-item"
+ :model="model"
+ :can-create-deployment="canCreateDeployment"
+ :can-read-environment="canReadEnvironment"
+ :service="service" />
+
+ <template v-if="model.isFolder && model.isOpen && model.children && model.children.length > 0">
+ <tr v-if="isLoadingFolderContent">
+ <td colspan="6" class="text-center">
+ <i
+ class="fa fa-spin fa-spinner fa-2x"
+ aria-hidden="true" />
+ </td>
+ </tr>
+
+ <template v-else>
+ <tr
+ is="environment-item"
+ v-for="children in model.children"
+ :model="children"
+ :can-create-deployment="canCreateDeployment"
+ :can-read-environment="canReadEnvironment"
+ :service="service" />
+
+ <tr>
+ <td
+ colspan="6"
+ class="text-center">
+ <a
+ :href="folderUrl(model)"
+ class="btn btn-default">
+ Show all
+ </a>
+ </td>
+ </tr>
+ </template>
+ </template>
+ </template>
+ </tbody>
+ </table>
+</template>
diff --git a/app/assets/javascripts/environments/folder/environments_folder_view.js b/app/assets/javascripts/environments/folder/environments_folder_view.js
index d2514593e3a..05d44f77d1d 100644
--- a/app/assets/javascripts/environments/folder/environments_folder_view.js
+++ b/app/assets/javascripts/environments/folder/environments_folder_view.js
@@ -2,7 +2,7 @@
/* global Flash */
import Vue from 'vue';
import EnvironmentsService from '../services/environments_service';
-import EnvironmentTable from '../components/environments_table';
+import EnvironmentTable from '../components/environments_table.vue';
import EnvironmentsStore from '../stores/environments_store';
import TablePaginationComponent from '../../vue_shared/components/table_pagination';
import '../../lib/utils/common_utils';
diff --git a/app/assets/javascripts/issuable_form.js b/app/assets/javascripts/issuable_form.js
index de184ab2675..687c2bb6110 100644
--- a/app/assets/javascripts/issuable_form.js
+++ b/app/assets/javascripts/issuable_form.js
@@ -39,8 +39,9 @@
if ($issuableDueDate.length) {
calendar = new Pikaday({
field: $issuableDueDate.get(0),
- theme: 'gitlab-theme',
+ theme: 'gitlab-theme animate-picker',
format: 'yyyy-mm-dd',
+ container: $issuableDueDate.parent().get(0),
onSelect: function(dateText) {
$issuableDueDate.val(dateFormat(new Date(dateText), 'yyyy-mm-dd'));
}
diff --git a/app/assets/javascripts/lib/utils/common_utils.js b/app/assets/javascripts/lib/utils/common_utils.js
index 01c4b9821d3..8058672eaa9 100644
--- a/app/assets/javascripts/lib/utils/common_utils.js
+++ b/app/assets/javascripts/lib/utils/common_utils.js
@@ -169,7 +169,10 @@
w.gl.utils.getSelectedFragment = () => {
const selection = window.getSelection();
if (selection.rangeCount === 0) return null;
- const documentFragment = selection.getRangeAt(0).cloneContents();
+ const documentFragment = document.createDocumentFragment();
+ for (let i = 0; i < selection.rangeCount; i += 1) {
+ documentFragment.appendChild(selection.getRangeAt(i).cloneContents());
+ }
if (documentFragment.textContent.length === 0) return null;
return documentFragment;
diff --git a/app/assets/javascripts/member_expiration_date.js b/app/assets/javascripts/member_expiration_date.js
index 129d2dc5f0a..e034729bd39 100644
--- a/app/assets/javascripts/member_expiration_date.js
+++ b/app/assets/javascripts/member_expiration_date.js
@@ -18,9 +18,10 @@
const calendar = new Pikaday({
field: $input.get(0),
- theme: 'gitlab-theme',
+ theme: 'gitlab-theme animate-picker',
format: 'yyyy-mm-dd',
minDate: new Date(),
+ container: $input.parent().get(0),
onSelect(dateText) {
$input.val(dateFormat(new Date(dateText), 'yyyy-mm-dd'));
diff --git a/app/assets/javascripts/notebook/cells/code.vue b/app/assets/javascripts/notebook/cells/code.vue
new file mode 100644
index 00000000000..b8a16356576
--- /dev/null
+++ b/app/assets/javascripts/notebook/cells/code.vue
@@ -0,0 +1,58 @@
+<template>
+ <div class="cell">
+ <code-cell
+ type="input"
+ :raw-code="rawInputCode"
+ :count="cell.execution_count"
+ :code-css-class="codeCssClass" />
+ <output-cell
+ v-if="hasOutput"
+ :count="cell.execution_count"
+ :output="output"
+ :code-css-class="codeCssClass" />
+ </div>
+</template>
+
+<script>
+import CodeCell from './code/index.vue';
+import OutputCell from './output/index.vue';
+
+export default {
+ components: {
+ 'code-cell': CodeCell,
+ 'output-cell': OutputCell,
+ },
+ props: {
+ cell: {
+ type: Object,
+ required: true,
+ },
+ codeCssClass: {
+ type: String,
+ required: false,
+ default: '',
+ },
+ },
+ computed: {
+ rawInputCode() {
+ if (this.cell.source) {
+ return this.cell.source.join('');
+ }
+
+ return '';
+ },
+ hasOutput() {
+ return this.cell.outputs.length;
+ },
+ output() {
+ return this.cell.outputs[0];
+ },
+ },
+};
+</script>
+
+<style scoped>
+.cell {
+ flex-direction: column;
+}
+</style>
diff --git a/app/assets/javascripts/notebook/cells/code/index.vue b/app/assets/javascripts/notebook/cells/code/index.vue
new file mode 100644
index 00000000000..31b30f601e2
--- /dev/null
+++ b/app/assets/javascripts/notebook/cells/code/index.vue
@@ -0,0 +1,57 @@
+<template>
+ <div :class="type">
+ <prompt
+ :type="promptType"
+ :count="count" />
+ <pre
+ class="language-python"
+ :class="codeCssClass"
+ ref="code"
+ v-text="code">
+ </pre>
+ </div>
+</template>
+
+<script>
+ import Prism from '../../lib/highlight';
+ import Prompt from '../prompt.vue';
+
+ export default {
+ components: {
+ prompt: Prompt,
+ },
+ props: {
+ count: {
+ type: Number,
+ required: false,
+ default: 0,
+ },
+ codeCssClass: {
+ type: String,
+ required: false,
+ default: '',
+ },
+ type: {
+ type: String,
+ required: true,
+ },
+ rawCode: {
+ type: String,
+ required: true,
+ },
+ },
+ computed: {
+ code() {
+ return this.rawCode;
+ },
+ promptType() {
+ const type = this.type.split('put')[0];
+
+ return type.charAt(0).toUpperCase() + type.slice(1);
+ },
+ },
+ mounted() {
+ Prism.highlightElement(this.$refs.code);
+ },
+ };
+</script>
diff --git a/app/assets/javascripts/notebook/cells/index.js b/app/assets/javascripts/notebook/cells/index.js
new file mode 100644
index 00000000000..e4c255609fe
--- /dev/null
+++ b/app/assets/javascripts/notebook/cells/index.js
@@ -0,0 +1,2 @@
+export { default as MarkdownCell } from './markdown.vue';
+export { default as CodeCell } from './code.vue';
diff --git a/app/assets/javascripts/notebook/cells/markdown.vue b/app/assets/javascripts/notebook/cells/markdown.vue
new file mode 100644
index 00000000000..3e8240d10ec
--- /dev/null
+++ b/app/assets/javascripts/notebook/cells/markdown.vue
@@ -0,0 +1,98 @@
+<template>
+ <div class="cell text-cell">
+ <prompt />
+ <div class="markdown" v-html="markdown"></div>
+ </div>
+</template>
+
+<script>
+ /* global katex */
+ import marked from 'marked';
+ import Prompt from './prompt.vue';
+
+ const renderer = new marked.Renderer();
+
+ /*
+ Regex to match KaTex blocks.
+
+ Supports the following:
+
+ \begin{equation}<math>\end{equation}
+ $$<math>$$
+ inline $<math>$
+
+ The matched text then goes through the KaTex renderer & then outputs the HTML
+ */
+ const katexRegexString = `(
+ ^\\\\begin{[a-zA-Z]+}\\s
+ |
+ ^\\$\\$
+ |
+ \\s\\$(?!\\$)
+ )
+ (.+?)
+ (
+ \\s\\\\end{[a-zA-Z]+}$
+ |
+ \\$\\$$
+ |
+ \\$
+ )
+ `.replace(/\s/g, '').trim();
+
+ renderer.paragraph = (t) => {
+ let text = t;
+ let inline = false;
+
+ if (typeof katex !== 'undefined') {
+ const katexString = text.replace(/\\/g, '\\');
+ const matches = new RegExp(katexRegexString, 'gi').exec(katexString);
+
+ if (matches && matches.length > 0) {
+ if (matches[1].trim() === '$' && matches[3].trim() === '$') {
+ inline = true;
+
+ text = `${katexString.replace(matches[0], '')} ${katex.renderToString(matches[2])}`;
+ } else {
+ text = katex.renderToString(matches[2]);
+ }
+ }
+ }
+
+ return `<p class="${inline ? 'inline-katex' : ''}">${text}</p>`;
+ };
+
+ marked.setOptions({
+ sanitize: true,
+ renderer,
+ });
+
+ export default {
+ components: {
+ prompt: Prompt,
+ },
+ props: {
+ cell: {
+ type: Object,
+ required: true,
+ },
+ },
+ computed: {
+ markdown() {
+ return marked(this.cell.source.join(''));
+ },
+ },
+ };
+</script>
+
+<style>
+.markdown .katex {
+ display: block;
+ text-align: center;
+}
+
+.markdown .inline-katex .katex {
+ display: inline;
+ text-align: initial;
+}
+</style>
diff --git a/app/assets/javascripts/notebook/cells/output/html.vue b/app/assets/javascripts/notebook/cells/output/html.vue
new file mode 100644
index 00000000000..0f39cd138df
--- /dev/null
+++ b/app/assets/javascripts/notebook/cells/output/html.vue
@@ -0,0 +1,22 @@
+<template>
+ <div class="output">
+ <prompt />
+ <div v-html="rawCode"></div>
+ </div>
+</template>
+
+<script>
+import Prompt from '../prompt.vue';
+
+export default {
+ props: {
+ rawCode: {
+ type: String,
+ required: true,
+ },
+ },
+ components: {
+ prompt: Prompt,
+ },
+};
+</script>
diff --git a/app/assets/javascripts/notebook/cells/output/image.vue b/app/assets/javascripts/notebook/cells/output/image.vue
new file mode 100644
index 00000000000..f3b873bbc0f
--- /dev/null
+++ b/app/assets/javascripts/notebook/cells/output/image.vue
@@ -0,0 +1,27 @@
+<template>
+ <div class="output">
+ <prompt />
+ <img
+ :src="'data:' + outputType + ';base64,' + rawCode" />
+ </div>
+</template>
+
+<script>
+import Prompt from '../prompt.vue';
+
+export default {
+ props: {
+ outputType: {
+ type: String,
+ required: true,
+ },
+ rawCode: {
+ type: String,
+ required: true,
+ },
+ },
+ components: {
+ prompt: Prompt,
+ },
+};
+</script>
diff --git a/app/assets/javascripts/notebook/cells/output/index.vue b/app/assets/javascripts/notebook/cells/output/index.vue
new file mode 100644
index 00000000000..23c9ea78939
--- /dev/null
+++ b/app/assets/javascripts/notebook/cells/output/index.vue
@@ -0,0 +1,83 @@
+<template>
+ <component :is="componentName"
+ type="output"
+ :outputType="outputType"
+ :count="count"
+ :raw-code="rawCode"
+ :code-css-class="codeCssClass" />
+</template>
+
+<script>
+import CodeCell from '../code/index.vue';
+import Html from './html.vue';
+import Image from './image.vue';
+
+export default {
+ props: {
+ codeCssClass: {
+ type: String,
+ required: false,
+ default: '',
+ },
+ count: {
+ type: Number,
+ required: false,
+ default: 0,
+ },
+ output: {
+ type: Object,
+ requred: true,
+ },
+ },
+ components: {
+ 'code-cell': CodeCell,
+ 'html-output': Html,
+ 'image-output': Image,
+ },
+ data() {
+ return {
+ outputType: '',
+ };
+ },
+ computed: {
+ componentName() {
+ if (this.output.text) {
+ return 'code-cell';
+ } else if (this.output.data['image/png']) {
+ this.outputType = 'image/png';
+
+ return 'image-output';
+ } else if (this.output.data['text/html']) {
+ this.outputType = 'text/html';
+
+ return 'html-output';
+ } else if (this.output.data['image/svg+xml']) {
+ this.outputType = 'image/svg+xml';
+
+ return 'html-output';
+ }
+
+ this.outputType = 'text/plain';
+ return 'code-cell';
+ },
+ rawCode() {
+ if (this.output.text) {
+ return this.output.text.join('');
+ }
+
+ return this.dataForType(this.outputType);
+ },
+ },
+ methods: {
+ dataForType(type) {
+ let data = this.output.data[type];
+
+ if (typeof data === 'object') {
+ data = data.join('');
+ }
+
+ return data;
+ },
+ },
+};
+</script>
diff --git a/app/assets/javascripts/notebook/cells/prompt.vue b/app/assets/javascripts/notebook/cells/prompt.vue
new file mode 100644
index 00000000000..4540e4248d8
--- /dev/null
+++ b/app/assets/javascripts/notebook/cells/prompt.vue
@@ -0,0 +1,30 @@
+<template>
+ <div class="prompt">
+ <span v-if="type && count">
+ {{ type }} [{{ count }}]:
+ </span>
+ </div>
+</template>
+
+<script>
+ export default {
+ props: {
+ type: {
+ type: String,
+ required: false,
+ },
+ count: {
+ type: Number,
+ required: false,
+ },
+ },
+ };
+</script>
+
+<style scoped>
+.prompt {
+ padding: 0 10px;
+ min-width: 7em;
+ font-family: monospace;
+}
+</style>
diff --git a/app/assets/javascripts/notebook/index.vue b/app/assets/javascripts/notebook/index.vue
new file mode 100644
index 00000000000..fd62c1231ef
--- /dev/null
+++ b/app/assets/javascripts/notebook/index.vue
@@ -0,0 +1,75 @@
+<template>
+ <div v-if="hasNotebook">
+ <component
+ v-for="(cell, index) in cells"
+ :is="cellType(cell.cell_type)"
+ :cell="cell"
+ :key="index"
+ :code-css-class="codeCssClass" />
+ </div>
+</template>
+
+<script>
+ import {
+ MarkdownCell,
+ CodeCell,
+ } from './cells';
+
+ export default {
+ components: {
+ 'code-cell': CodeCell,
+ 'markdown-cell': MarkdownCell,
+ },
+ props: {
+ notebook: {
+ type: Object,
+ required: true,
+ },
+ codeCssClass: {
+ type: String,
+ required: false,
+ default: '',
+ },
+ },
+ methods: {
+ cellType(type) {
+ return `${type}-cell`;
+ },
+ },
+ computed: {
+ cells() {
+ if (this.notebook.worksheets) {
+ const data = {
+ cells: [],
+ };
+
+ return this.notebook.worksheets.reduce((cellData, sheet) => {
+ const cellDataCopy = cellData;
+ cellDataCopy.cells = cellDataCopy.cells.concat(sheet.cells);
+ return cellDataCopy;
+ }, data).cells;
+ }
+
+ return this.notebook.cells;
+ },
+ hasNotebook() {
+ return Object.keys(this.notebook).length;
+ },
+ },
+ };
+</script>
+
+<style>
+.cell,
+.input,
+.output {
+ display: flex;
+ width: 100%;
+ margin-bottom: 10px;
+}
+
+.cell pre {
+ margin: 0;
+ width: 100%;
+}
+</style>
diff --git a/app/assets/javascripts/notebook/lib/highlight.js b/app/assets/javascripts/notebook/lib/highlight.js
new file mode 100644
index 00000000000..74ade6d2edf
--- /dev/null
+++ b/app/assets/javascripts/notebook/lib/highlight.js
@@ -0,0 +1,22 @@
+import Prism from 'prismjs';
+import 'prismjs/components/prism-python';
+import 'prismjs/plugins/custom-class/prism-custom-class';
+
+Prism.plugins.customClass.map({
+ comment: 'c',
+ error: 'err',
+ operator: 'o',
+ constant: 'kc',
+ namespace: 'kn',
+ keyword: 'k',
+ string: 's',
+ number: 'm',
+ 'attr-name': 'na',
+ builtin: 'nb',
+ entity: 'ni',
+ function: 'nf',
+ tag: 'nt',
+ variable: 'nv',
+});
+
+export default Prism;
diff --git a/app/assets/javascripts/pipelines/components/empty_state.vue b/app/assets/javascripts/pipelines/components/empty_state.vue
index ba158bc4a1e..3db64339a62 100644
--- a/app/assets/javascripts/pipelines/components/empty_state.vue
+++ b/app/assets/javascripts/pipelines/components/empty_state.vue
@@ -13,7 +13,7 @@ export default {
</script>
<template>
- <div class="row empty-state">
+ <div class="row empty-state js-empty-state">
<div class="col-xs-12">
<div class="svg-content" v-html="pipelinesEmptyStateSVG" />
</div>
diff --git a/app/assets/javascripts/shortcuts.js b/app/assets/javascripts/shortcuts.js
index 5b6bb2bf3f5..85659d7fa39 100644
--- a/app/assets/javascripts/shortcuts.js
+++ b/app/assets/javascripts/shortcuts.js
@@ -57,8 +57,11 @@ import findAndFollowLink from './shortcuts_dashboard_navigation';
Shortcuts.prototype.toggleMarkdownPreview = function(e) {
// Check if short-cut was triggered while in Write Mode
- if ($(e.target).hasClass('js-note-text')) {
- $('.js-md-preview-button').focus();
+ const $target = $(e.target);
+ const $form = $target.closest('form');
+
+ if ($target.hasClass('js-note-text')) {
+ $('.js-md-preview-button', $form).focus();
}
return $(document).triggerHandler('markdown-preview:toggle', [e]);
};
diff --git a/app/assets/javascripts/user_tabs.js b/app/assets/javascripts/user_tabs.js
index 5db0d936ad8..ce7eb76dc71 100644
--- a/app/assets/javascripts/user_tabs.js
+++ b/app/assets/javascripts/user_tabs.js
@@ -94,15 +94,17 @@ content on the Users#show page.
e.preventDefault();
$('.tab-pane.active').empty();
- this.loadTab($(e.target).attr('href'), this.getCurrentAction());
+ const endpoint = $(e.target).attr('href');
+ this.loadTab(this.getCurrentAction(), endpoint);
}
tabShown(event) {
const $target = $(event.target);
const action = $target.data('action');
const source = $target.attr('href');
- this.setTab(source, action);
- return this.setCurrentAction(source, action);
+ const endpoint = $target.data('endpoint');
+ this.setTab(action, endpoint);
+ return this.setCurrentAction(source);
}
activateTab(action) {
@@ -110,27 +112,27 @@ content on the Users#show page.
.tab('show');
}
- setTab(source, action) {
+ setTab(action, endpoint) {
if (this.loaded[action]) {
return;
}
if (action === 'activity') {
- this.loadActivities(source);
+ this.loadActivities();
}
const loadableActions = ['groups', 'contributed', 'projects', 'snippets'];
if (loadableActions.indexOf(action) > -1) {
- return this.loadTab(source, action);
+ return this.loadTab(action, endpoint);
}
}
- loadTab(source, action) {
+ loadTab(action, endpoint) {
return $.ajax({
beforeSend: () => this.toggleLoading(true),
complete: () => this.toggleLoading(false),
dataType: 'json',
type: 'GET',
- url: source,
+ url: endpoint,
success: (data) => {
const tabSelector = `div#${action}`;
this.$parentEl.find(tabSelector).html(data.html);
@@ -140,7 +142,7 @@ content on the Users#show page.
});
}
- loadActivities(source) {
+ loadActivities() {
if (this.loaded['activity']) {
return;
}
@@ -155,7 +157,7 @@ content on the Users#show page.
.toggle(status);
}
- setCurrentAction(source, action) {
+ setCurrentAction(source) {
let new_state = source;
new_state = new_state.replace(/\/+$/, '');
new_state += this._location.search + this._location.hash;
diff --git a/app/assets/stylesheets/framework/blocks.scss b/app/assets/stylesheets/framework/blocks.scss
index 52425262925..f3e2a5db0a6 100644
--- a/app/assets/stylesheets/framework/blocks.scss
+++ b/app/assets/stylesheets/framework/blocks.scss
@@ -230,7 +230,6 @@
float: right;
margin-top: 8px;
padding-bottom: 8px;
- border-bottom: 1px solid $border-color;
}
}
diff --git a/app/assets/stylesheets/framework/dropdowns.scss b/app/assets/stylesheets/framework/dropdowns.scss
index b87e712c763..30d785464ac 100644
--- a/app/assets/stylesheets/framework/dropdowns.scss
+++ b/app/assets/stylesheets/framework/dropdowns.scss
@@ -14,14 +14,32 @@
}
}
+@mixin set-visible {
+ transform: translateY(0);
+ visibility: visible;
+ opacity: 1;
+ transition-duration: 100ms, 150ms, 25ms;
+ transition-delay: 35ms, 50ms, 25ms;
+}
+
+@mixin set-invisible {
+ transform: translateY(-10px);
+ visibility: hidden;
+ opacity: 0;
+ transition-property: opacity, transform, visibility;
+ transition-duration: 70ms, 250ms, 250ms;
+ transition-timing-function: linear, $dropdown-animation-timing;
+ transition-delay: 25ms, 50ms, 0ms;
+}
+
.open {
.dropdown-menu,
.dropdown-menu-nav {
display: block;
+ @include set-visible;
@media (max-width: $screen-xs-max) {
width: 100%;
- min-width: 240px;
}
}
@@ -161,8 +179,9 @@
.dropdown-menu,
.dropdown-menu-nav {
- display: none;
+ display: block;
position: absolute;
+ width: 100%;
top: 100%;
left: 0;
z-index: 9;
@@ -176,6 +195,12 @@
border: 1px solid $dropdown-border-color;
border-radius: $border-radius-base;
box-shadow: 0 2px 4px $dropdown-shadow-color;
+ overflow: hidden;
+ @include set-invisible;
+
+ @media (max-width: $screen-sm-min) {
+ width: 100%;
+ }
&.is-loading {
.dropdown-content {
@@ -252,6 +277,23 @@
}
}
+.filtered-search-box-input-container .dropdown-menu,
+.filtered-search-box-input-container .dropdown-menu-nav,
+.comment-type-dropdown .dropdown-menu {
+ display: none;
+ opacity: 1;
+ visibility: visible;
+ transform: translateY(0);
+}
+
+.filtered-search-box-input-container {
+ .dropdown-menu,
+ .dropdown-menu-nav {
+ max-width: 280px;
+ width: auto;
+ }
+}
+
.dropdown-menu-drop-up {
top: auto;
bottom: 100%;
@@ -326,6 +368,10 @@
.dropdown-select {
width: $dropdown-width;
+
+ @media (max-width: $screen-sm-min) {
+ width: 100%;
+ }
}
.dropdown-menu-align-right {
@@ -568,3 +614,24 @@
.droplab-item-ignore {
pointer-events: none;
}
+
+.pika-single.animate-picker.is-bound,
+.pika-single.animate-picker.is-bound.is-hidden {
+ /*
+ * Having `!important` is not recommended but
+ * since `pikaday` sets positioning inline
+ * there's no way it can be gracefully overridden
+ * using config options.
+ */
+ position: absolute !important;
+ display: block;
+}
+
+.pika-single.animate-picker.is-bound {
+ @include set-visible;
+}
+
+.pika-single.animate-picker.is-bound.is-hidden {
+ @include set-invisible;
+ overflow: hidden;
+}
diff --git a/app/assets/stylesheets/framework/header.scss b/app/assets/stylesheets/framework/header.scss
index 0077ea41d3b..6d9218310eb 100644
--- a/app/assets/stylesheets/framework/header.scss
+++ b/app/assets/stylesheets/framework/header.scss
@@ -329,6 +329,7 @@ header {
.header-user {
.dropdown-menu-nav {
+ width: auto;
min-width: 140px;
margin-top: -5px;
diff --git a/app/assets/stylesheets/framework/nav.scss b/app/assets/stylesheets/framework/nav.scss
index e6d808717f3..b6cf5101d60 100644
--- a/app/assets/stylesheets/framework/nav.scss
+++ b/app/assets/stylesheets/framework/nav.scss
@@ -110,7 +110,7 @@
.top-area {
@include clearfix;
- border-bottom: 1px solid $white-normal;
+ border-bottom: 1px solid $border-color;
.nav-text {
padding-top: 16px;
diff --git a/app/assets/stylesheets/framework/typography.scss b/app/assets/stylesheets/framework/typography.scss
index 664539e93e1..1839cadcc10 100644
--- a/app/assets/stylesheets/framework/typography.scss
+++ b/app/assets/stylesheets/framework/typography.scss
@@ -338,3 +338,32 @@ h4 {
.idiff.addition {
background: $line-added-dark;
}
+
+
+/**
+ * form text input i.e. search bar, comments, forms, etc.
+ */
+input,
+textarea {
+ &::-webkit-input-placeholder {
+ color: $placeholder-text-color;
+ }
+
+ // support firefox 19+ vendor prefix
+ &::-moz-placeholder {
+ color: $placeholder-text-color;
+ opacity: 1; // FF defaults to 0.54
+ }
+
+ // scss-lint:disable PseudoElement
+ // support Edge vendor prefix
+ &::-ms-input-placeholder {
+ color: $placeholder-text-color;
+ }
+
+ // scss-lint:disable PseudoElement
+ // support IE vendor prefix
+ &:-ms-input-placeholder {
+ color: $placeholder-text-color;
+ }
+}
diff --git a/app/assets/stylesheets/framework/variables.scss b/app/assets/stylesheets/framework/variables.scss
index 3ef6ec3f912..49741c963df 100644
--- a/app/assets/stylesheets/framework/variables.scss
+++ b/app/assets/stylesheets/framework/variables.scss
@@ -111,6 +111,7 @@ $gl-gray: $gl-text-color;
$gl-gray-dark: #313236;
$gl-header-color: #4c4e54;
$gl-header-nav-hover-color: #434343;
+$placeholder-text-color: rgba(0, 0, 0, .42);
/*
* Lists
@@ -561,3 +562,8 @@ $filter-name-text-color: rgba(0, 0, 0, 0.55);
$filter-value-text-color: rgba(0, 0, 0, 0.85);
$filter-name-selected-color: #ebebeb;
$filter-value-selected-color: #d7d7d7;
+
+/*
+Animation Functions
+*/
+$dropdown-animation-timing: cubic-bezier(0.23, 1, 0.32, 1);
diff --git a/app/assets/stylesheets/pages/note_form.scss b/app/assets/stylesheets/pages/note_form.scss
index b637994adf8..03d1c3067c7 100644
--- a/app/assets/stylesheets/pages/note_form.scss
+++ b/app/assets/stylesheets/pages/note_form.scss
@@ -387,6 +387,7 @@
@media (max-width: $screen-xs-max) {
display: flex;
width: 100%;
+ margin-bottom: 10px;
.comment-btn {
flex-grow: 1;
diff --git a/app/assets/stylesheets/pages/notes.scss b/app/assets/stylesheets/pages/notes.scss
index 2ea2ff8362b..98b93cca6e3 100644
--- a/app/assets/stylesheets/pages/notes.scss
+++ b/app/assets/stylesheets/pages/notes.scss
@@ -386,6 +386,10 @@ ul.notes {
.note-headline-meta {
display: inline-block;
white-space: nowrap;
+
+ .system-note-message {
+ white-space: normal;
+ }
}
/**
diff --git a/app/assets/stylesheets/pages/search.scss b/app/assets/stylesheets/pages/search.scss
index 543d2ece3df..b9818ffcf42 100644
--- a/app/assets/stylesheets/pages/search.scss
+++ b/app/assets/stylesheets/pages/search.scss
@@ -124,7 +124,13 @@ input[type="checkbox"]:hover {
// Custom dropdown positioning
.dropdown-menu {
- top: 37px;
+ transition-property: opacity, transform;
+ transition-duration: 250ms, 250ms;
+ transition-delay: 0ms, 25ms;
+ transition-timing-function: $dropdown-animation-timing;
+ transform: translateY(0);
+ opacity: 0;
+ display: block;
left: -5px;
padding: 0;
@@ -156,6 +162,13 @@ input[type="checkbox"]:hover {
color: $layout-link-gray;
}
}
+
+ .dropdown-menu {
+ transition-duration: 100ms, 75ms;
+ transition-delay: 75ms, 100ms;
+ transform: translateY(13px);
+ opacity: 1;
+ }
}
&.has-value {
diff --git a/app/controllers/admin/groups_controller.rb b/app/controllers/admin/groups_controller.rb
index f28bbdeff5a..fc8d4d02ddf 100644
--- a/app/controllers/admin/groups_controller.rb
+++ b/app/controllers/admin/groups_controller.rb
@@ -43,9 +43,13 @@ class Admin::GroupsController < Admin::ApplicationController
end
def members_update
- @group.add_users(params[:user_ids].split(','), params[:access_level], current_user: current_user)
+ status = Members::CreateService.new(@group, current_user, params).execute
- redirect_to [:admin, @group], notice: 'Users were successfully added.'
+ if status
+ redirect_to [:admin, @group], notice: 'Users were successfully added.'
+ else
+ redirect_to [:admin, @group], alert: 'No users specified.'
+ end
end
def destroy
diff --git a/app/controllers/projects/milestones_controller.rb b/app/controllers/projects/milestones_controller.rb
index 408c0c60cb0..d0dd524c484 100644
--- a/app/controllers/projects/milestones_controller.rb
+++ b/app/controllers/projects/milestones_controller.rb
@@ -23,6 +23,7 @@ class Projects::MilestonesController < Projects::ApplicationController
respond_to do |format|
format.html do
+ @project_namespace = @project.namespace.becomes(Namespace)
@milestones = @milestones.includes(:project)
@milestones = @milestones.page(params[:page])
end
diff --git a/app/helpers/ci_status_helper.rb b/app/helpers/ci_status_helper.rb
index 2de9e0de310..32b1e7822af 100644
--- a/app/helpers/ci_status_helper.rb
+++ b/app/helpers/ci_status_helper.rb
@@ -1,10 +1,16 @@
+##
+# DEPRECATED
+#
+# These helpers are deprecated in favor of detailed CI/CD statuses.
+#
+# See 'detailed_status?` method and `Gitlab::Ci::Status` module.
+#
module CiStatusHelper
def ci_status_path(pipeline)
project = pipeline.project
namespace_project_pipeline_path(project.namespace, project, pipeline)
end
- # Is used by Commit and Merge Request Widget
def ci_label_for_status(status)
if detailed_status?(status)
return status.label
@@ -22,6 +28,23 @@ module CiStatusHelper
end
end
+ def ci_text_for_status(status)
+ if detailed_status?(status)
+ return status.text
+ end
+
+ case status
+ when 'success'
+ 'passed'
+ when 'success_with_warnings'
+ 'passed'
+ when 'manual'
+ 'blocked'
+ else
+ status
+ end
+ end
+
def ci_status_for_statuseable(subject)
status = subject.try(:status) || 'not found'
status.humanize
diff --git a/app/helpers/icons_helper.rb b/app/helpers/icons_helper.rb
index ab3ef454e1c..55fa81e95ef 100644
--- a/app/helpers/icons_helper.rb
+++ b/app/helpers/icons_helper.rb
@@ -7,6 +7,11 @@ module IconsHelper
# font-awesome-rails gem, but should we ever use a different icon pack in the
# future we won't have to change hundreds of method calls.
def icon(names, options = {})
+ if (options.keys & %w[aria-hidden aria-label]).empty?
+ # Add `aria-hidden` if there are no aria's set
+ options['aria-hidden'] = true
+ end
+
options.include?(:base) ? fa_stacked_icon(names, options) : fa_icon(names, options)
end
diff --git a/app/helpers/submodule_helper.rb b/app/helpers/submodule_helper.rb
index fb95f2b565e..a762b320d56 100644
--- a/app/helpers/submodule_helper.rb
+++ b/app/helpers/submodule_helper.rb
@@ -5,7 +5,7 @@ module SubmoduleHelper
def submodule_links(submodule_item, ref = nil, repository = @repository)
url = repository.submodule_url_for(ref, submodule_item.path)
- return url, nil unless url =~ /([^\/:]+)\/([^\/]+\.git)\Z/
+ return url, nil unless url =~ /([^\/:]+)\/([^\/]+(?:\.git)?)\Z/
namespace = $1
project = $2
@@ -37,14 +37,16 @@ module SubmoduleHelper
end
def self_url?(url, namespace, project)
- return true if url == [Gitlab.config.gitlab.url, '/', namespace, '/',
- project, '.git'].join('')
- url == gitlab_shell.url_to_repo([namespace, '/', project].join(''))
+ url_no_dotgit = url.chomp('.git')
+ return true if url_no_dotgit == [Gitlab.config.gitlab.url, '/', namespace, '/',
+ project].join('')
+ url_with_dotgit = url_no_dotgit + '.git'
+ url_with_dotgit == gitlab_shell.url_to_repo([namespace, '/', project].join(''))
end
def relative_self_url?(url)
# (./)?(../repo.git) || (./)?(../../project/repo.git) )
- url =~ /\A((\.\/)?(\.\.\/))(?!(\.\.)|(.*\/)).*\.git\z/ || url =~ /\A((\.\/)?(\.\.\/){2})(?!(\.\.))([^\/]*)\/(?!(\.\.)|(.*\/)).*\.git\z/
+ url =~ /\A((\.\/)?(\.\.\/))(?!(\.\.)|(.*\/)).*(\.git)?\z/ || url =~ /\A((\.\/)?(\.\.\/){2})(?!(\.\.))([^\/]*)\/(?!(\.\.)|(.*\/)).*(\.git)?\z/
end
def standard_links(host, namespace, project, commit)
diff --git a/app/models/ci/pipeline.rb b/app/models/ci/pipeline.rb
index 445247f1b41..4be4aa9ffe2 100644
--- a/app/models/ci/pipeline.rb
+++ b/app/models/ci/pipeline.rb
@@ -75,29 +75,32 @@ module Ci
pipeline.update_duration
end
+ before_transition any => [:manual] do |pipeline|
+ pipeline.update_duration
+ end
+
before_transition canceled: any - [:canceled] do |pipeline|
pipeline.auto_canceled_by = nil
end
after_transition [:created, :pending] => :running do |pipeline|
- pipeline.run_after_commit { PipelineMetricsWorker.perform_async(id) }
+ pipeline.run_after_commit { PipelineMetricsWorker.perform_async(pipeline.id) }
end
after_transition any => [:success] do |pipeline|
- pipeline.run_after_commit { PipelineMetricsWorker.perform_async(id) }
+ pipeline.run_after_commit { PipelineMetricsWorker.perform_async(pipeline.id) }
end
after_transition [:created, :pending, :running] => :success do |pipeline|
- pipeline.run_after_commit { PipelineSuccessWorker.perform_async(id) }
+ pipeline.run_after_commit { PipelineSuccessWorker.perform_async(pipeline.id) }
end
after_transition do |pipeline, transition|
next if transition.loopback?
pipeline.run_after_commit do
- PipelineHooksWorker.perform_async(id)
- Ci::ExpirePipelineCacheService.new(project, nil)
- .execute(pipeline)
+ PipelineHooksWorker.perform_async(pipeline.id)
+ ExpirePipelineCacheWorker.perform_async(pipeline.id)
end
end
@@ -385,6 +388,11 @@ module Ci
.select { |merge_request| merge_request.head_pipeline.try(:id) == self.id }
end
+ # All the merge requests for which the current pipeline runs/ran against
+ def all_merge_requests
+ @all_merge_requests ||= project.merge_requests.where(source_branch: ref)
+ end
+
def detailed_status(current_user)
Gitlab::Ci::Status::Pipeline::Factory
.new(self, current_user)
diff --git a/app/models/concerns/cache_markdown_field.rb b/app/models/concerns/cache_markdown_field.rb
index 8ea95beed79..2eedc143968 100644
--- a/app/models/concerns/cache_markdown_field.rb
+++ b/app/models/concerns/cache_markdown_field.rb
@@ -8,6 +8,14 @@
#
# Corresponding foo_html, bar_html and baz_html fields should exist.
module CacheMarkdownField
+ extend ActiveSupport::Concern
+
+ # Increment this number every time the renderer changes its output
+ CACHE_VERSION = 1
+
+ # changes to these attributes cause the cache to be invalidates
+ INVALIDATED_BY = %w[author project].freeze
+
# Knows about the relationship between markdown and html field names, and
# stores the rendering contexts for the latter
class FieldData
@@ -30,60 +38,71 @@ module CacheMarkdownField
end
end
- # Dynamic registries don't really work in Rails as it's not guaranteed that
- # every class will be loaded, so hardcode the list.
- CACHING_CLASSES = %w[
- AbuseReport
- Appearance
- ApplicationSetting
- BroadcastMessage
- Issue
- Label
- MergeRequest
- Milestone
- Namespace
- Note
- Project
- Release
- Snippet
- ].freeze
-
- def self.caching_classes
- CACHING_CLASSES.map(&:constantize)
- end
-
def skip_project_check?
false
end
- extend ActiveSupport::Concern
+ # Returns the default Banzai render context for the cached markdown field.
+ def banzai_render_context(field)
+ raise ArgumentError.new("Unknown field: #{field.inspect}") unless
+ cached_markdown_fields.markdown_fields.include?(field)
- included do
- cattr_reader :cached_markdown_fields do
- FieldData.new
- end
+ # Always include a project key, or Banzai complains
+ project = self.project if self.respond_to?(:project)
+ context = cached_markdown_fields[field].merge(project: project)
- # Returns the default Banzai render context for the cached markdown field.
- def banzai_render_context(field)
- raise ArgumentError.new("Unknown field: #{field.inspect}") unless
- cached_markdown_fields.markdown_fields.include?(field)
+ # Banzai is less strict about authors, so don't always have an author key
+ context[:author] = self.author if self.respond_to?(:author)
- # Always include a project key, or Banzai complains
- project = self.project if self.respond_to?(:project)
- context = cached_markdown_fields[field].merge(project: project)
+ context
+ end
- # Banzai is less strict about authors, so don't always have an author key
- context[:author] = self.author if self.respond_to?(:author)
+ # Update every column in a row if any one is invalidated, as we only store
+ # one version per row
+ def refresh_markdown_cache!(do_update: false)
+ options = { skip_project_check: skip_project_check? }
- context
- end
+ updates = cached_markdown_fields.markdown_fields.map do |markdown_field|
+ [
+ cached_markdown_fields.html_field(markdown_field),
+ Banzai::Renderer.cacheless_render_field(self, markdown_field, options)
+ ]
+ end.to_h
+ updates['cached_markdown_version'] = CacheMarkdownField::CACHE_VERSION
- # Allow callers to look up the cache field name, rather than hardcoding it
- def markdown_cache_field_for(field)
- raise ArgumentError.new("Unknown field: #{field}") unless
- cached_markdown_fields.markdown_fields.include?(field)
+ updates.each {|html_field, data| write_attribute(html_field, data) }
- cached_markdown_fields.html_field(field)
+ update_columns(updates) if persisted? && do_update
+ end
+
+ def cached_html_up_to_date?(markdown_field)
+ html_field = cached_markdown_fields.html_field(markdown_field)
+
+ markdown_changed = attribute_changed?(markdown_field) || false
+ html_changed = attribute_changed?(html_field) || false
+
+ CacheMarkdownField::CACHE_VERSION == cached_markdown_version &&
+ (html_changed || markdown_changed == html_changed)
+ end
+
+ def invalidated_markdown_cache?
+ cached_markdown_fields.html_fields.any? {|html_field| attribute_invalidated?(html_field) }
+ end
+
+ def attribute_invalidated?(attr)
+ __send__("#{attr}_invalidated?")
+ end
+
+ def cached_html_for(markdown_field)
+ raise ArgumentError.new("Unknown field: #{field}") unless
+ cached_markdown_fields.markdown_fields.include?(markdown_field)
+
+ __send__(cached_markdown_fields.html_field(markdown_field))
+ end
+
+ included do
+ cattr_reader :cached_markdown_fields do
+ FieldData.new
end
# Always exclude _html fields from attributes (including serialization).
@@ -92,12 +111,16 @@ module CacheMarkdownField
def attributes
attrs = attributes_before_markdown_cache
+ attrs.delete('cached_markdown_version')
+
cached_markdown_fields.html_fields.each do |field|
attrs.delete(field)
end
attrs
end
+
+ before_save :refresh_markdown_cache!, if: :invalidated_markdown_cache?
end
class_methods do
@@ -107,31 +130,18 @@ module CacheMarkdownField
# a corresponding _html field. Any custom rendering options may be provided
# as a context.
def cache_markdown_field(markdown_field, context = {})
- raise "Add #{self} to CacheMarkdownField::CACHING_CLASSES" unless
- CacheMarkdownField::CACHING_CLASSES.include?(self.to_s)
-
cached_markdown_fields[markdown_field] = context
html_field = cached_markdown_fields.html_field(markdown_field)
- cache_method = "#{markdown_field}_cache_refresh".to_sym
invalidation_method = "#{html_field}_invalidated?".to_sym
- define_method(cache_method) do
- options = { skip_project_check: skip_project_check? }
- html = Banzai::Renderer.cacheless_render_field(self, markdown_field, options)
- __send__("#{html_field}=", html)
- true
- end
-
# The HTML becomes invalid if any dependent fields change. For now, assume
# author and project invalidate the cache in all circumstances.
define_method(invalidation_method) do
changed_fields = changed_attributes.keys
- invalidations = changed_fields & [markdown_field.to_s, "author", "project"]
- !invalidations.empty?
+ invalidations = changed_fields & [markdown_field.to_s, *INVALIDATED_BY]
+ !invalidations.empty? || !cached_html_up_to_date?(markdown_field)
end
-
- before_save cache_method, if: invalidation_method
end
end
end
diff --git a/app/models/concerns/routable.rb b/app/models/concerns/routable.rb
index aca99feee53..b28e05d0c28 100644
--- a/app/models/concerns/routable.rb
+++ b/app/models/concerns/routable.rb
@@ -163,7 +163,20 @@ module Routable
end
end
+ # Every time `project.namespace.becomes(Namespace)` is called for polymorphic_path,
+ # a new instance is instantiated, and we end up duplicating the same query to retrieve
+ # the route. Caching this per request ensures that even if we have multiple instances,
+ # we will not have to duplicate work, avoiding N+1 queries in some cases.
def full_path
+ return uncached_full_path unless RequestStore.active?
+
+ key = "routable/full_path/#{self.class.name}/#{self.id}"
+ RequestStore[key] ||= uncached_full_path
+ end
+
+ private
+
+ def uncached_full_path
if route && route.path.present?
@full_path ||= route.path
else
@@ -173,8 +186,6 @@ module Routable
end
end
- private
-
def full_name_changed?
name_changed? || parent_changed?
end
diff --git a/app/models/group.rb b/app/models/group.rb
index 106084175ff..cbc10b00cf5 100644
--- a/app/models/group.rb
+++ b/app/models/group.rb
@@ -125,7 +125,7 @@ class Group < Namespace
end
def add_users(users, access_level, current_user: nil, expires_at: nil)
- GroupMember.add_users_to_group(
+ GroupMember.add_users(
self,
users,
access_level,
diff --git a/app/models/individual_note_discussion.rb b/app/models/individual_note_discussion.rb
index c3f21c55240..6be8ca45739 100644
--- a/app/models/individual_note_discussion.rb
+++ b/app/models/individual_note_discussion.rb
@@ -10,4 +10,8 @@ class IndividualNoteDiscussion < Discussion
def individual_note?
true
end
+
+ def reply_attributes
+ super.tap { |attrs| attrs.delete(:discussion_id) }
+ end
end
diff --git a/app/models/issue.rb b/app/models/issue.rb
index d39ae3a6c92..305fc01f041 100644
--- a/app/models/issue.rb
+++ b/app/models/issue.rb
@@ -199,7 +199,7 @@ class Issue < ActiveRecord::Base
# Returns `true` if the current issue can be viewed by either a logged in User
# or an anonymous user.
def visible_to_user?(user = nil)
- return false unless project.feature_available?(:issues, user)
+ return false unless project && project.feature_available?(:issues, user)
user ? readable_by?(user) : publicly_visible?
end
diff --git a/app/models/member.rb b/app/models/member.rb
index 0545bd4eedf..97fba501759 100644
--- a/app/models/member.rb
+++ b/app/models/member.rb
@@ -151,6 +151,22 @@ class Member < ActiveRecord::Base
member
end
+ def add_users(source, users, access_level, current_user: nil, expires_at: nil)
+ return [] unless users.present?
+
+ self.transaction do
+ users.map do |user|
+ add_user(
+ source,
+ user,
+ access_level,
+ current_user: current_user,
+ expires_at: expires_at
+ )
+ end
+ end
+ end
+
def access_levels
Gitlab::Access.sym_options
end
@@ -173,18 +189,6 @@ class Member < ActiveRecord::Base
# There is no current user for bulk actions, in which case anything is allowed
!current_user || current_user.can?(:"update_#{member.type.underscore}", member)
end
-
- def add_users_to_source(source, users, access_level, current_user: nil, expires_at: nil)
- users.each do |user|
- add_user(
- source,
- user,
- access_level,
- current_user: current_user,
- expires_at: expires_at
- )
- end
- end
end
def real_source_type
diff --git a/app/models/members/group_member.rb b/app/models/members/group_member.rb
index 483425cd30f..28e10bc6172 100644
--- a/app/models/members/group_member.rb
+++ b/app/models/members/group_member.rb
@@ -21,18 +21,6 @@ class GroupMember < Member
Gitlab::Access.sym_options_with_owner
end
- def self.add_users_to_group(group, users, access_level, current_user: nil, expires_at: nil)
- self.transaction do
- add_users_to_source(
- group,
- users,
- access_level,
- current_user: current_user,
- expires_at: expires_at
- )
- end
- end
-
def group
source
end
diff --git a/app/models/members/project_member.rb b/app/models/members/project_member.rb
index 912820b51ac..b3a91feb091 100644
--- a/app/models/members/project_member.rb
+++ b/app/models/members/project_member.rb
@@ -16,7 +16,7 @@ class ProjectMember < Member
before_destroy :delete_member_todos
class << self
- # Add users to project teams with passed access option
+ # Add users to projects with passed access option
#
# access can be an integer representing a access code
# or symbol like :master representing role
@@ -39,7 +39,7 @@ class ProjectMember < Member
project_ids.each do |project_id|
project = Project.find(project_id)
- add_users_to_source(
+ add_users(
project,
users,
access_level,
diff --git a/app/models/out_of_context_discussion.rb b/app/models/out_of_context_discussion.rb
index 85794630f70..4227c40b69a 100644
--- a/app/models/out_of_context_discussion.rb
+++ b/app/models/out_of_context_discussion.rb
@@ -15,8 +15,12 @@ class OutOfContextDiscussion < Discussion
def self.override_discussion_id(note)
discussion_id(note)
end
-
+
def self.note_class
Note
end
+
+ def reply_attributes
+ super.tap { |attrs| attrs.delete(:discussion_id) }
+ end
end
diff --git a/app/models/project_team.rb b/app/models/project_team.rb
index 6d6644053f8..543b9b293e0 100644
--- a/app/models/project_team.rb
+++ b/app/models/project_team.rb
@@ -50,8 +50,8 @@ class ProjectTeam
end
def add_users(users, access_level, current_user: nil, expires_at: nil)
- ProjectMember.add_users_to_projects(
- [project.id],
+ ProjectMember.add_users(
+ project,
users,
access_level,
current_user: current_user,
diff --git a/app/services/ci/expire_pipeline_cache_service.rb b/app/services/ci/expire_pipeline_cache_service.rb
deleted file mode 100644
index 91d9c1d2ba1..00000000000
--- a/app/services/ci/expire_pipeline_cache_service.rb
+++ /dev/null
@@ -1,51 +0,0 @@
-module Ci
- class ExpirePipelineCacheService < BaseService
- attr_reader :pipeline
-
- def execute(pipeline)
- @pipeline = pipeline
- store = Gitlab::EtagCaching::Store.new
-
- store.touch(project_pipelines_path)
- store.touch(commit_pipelines_path) if pipeline.commit
- store.touch(new_merge_request_pipelines_path)
- merge_requests_pipelines_paths.each { |path| store.touch(path) }
-
- Gitlab::Cache::Ci::ProjectPipelineStatus.update_for_pipeline(@pipeline)
- end
-
- private
-
- def project_pipelines_path
- Gitlab::Routing.url_helpers.namespace_project_pipelines_path(
- project.namespace,
- project,
- format: :json)
- end
-
- def commit_pipelines_path
- Gitlab::Routing.url_helpers.pipelines_namespace_project_commit_path(
- project.namespace,
- project,
- pipeline.commit.id,
- format: :json)
- end
-
- def new_merge_request_pipelines_path
- Gitlab::Routing.url_helpers.new_namespace_project_merge_request_path(
- project.namespace,
- project,
- format: :json)
- end
-
- def merge_requests_pipelines_paths
- pipeline.merge_requests.collect do |merge_request|
- Gitlab::Routing.url_helpers.pipelines_namespace_project_merge_request_path(
- project.namespace,
- project,
- merge_request,
- format: :json)
- end
- end
- end
-end
diff --git a/app/services/users/migrate_to_ghost_user_service.rb b/app/services/users/migrate_to_ghost_user_service.rb
index 1e1ed1791ec..4628c4c6f6e 100644
--- a/app/services/users/migrate_to_ghost_user_service.rb
+++ b/app/services/users/migrate_to_ghost_user_service.rb
@@ -15,27 +15,39 @@ module Users
end
def execute
- # Block the user before moving records to prevent a data race.
- # For example, if the user creates an issue after `migrate_issues`
- # runs and before the user is destroyed, the destroy will fail with
- # an exception.
- user.block
+ transition = user.block_transition
user.transaction do
+ # Block the user before moving records to prevent a data race.
+ # For example, if the user creates an issue after `migrate_issues`
+ # runs and before the user is destroyed, the destroy will fail with
+ # an exception.
+ user.block
+
+ # Reverse the user block if record migration fails
+ if !migrate_records && transition
+ transition.rollback
+ user.save!
+ end
+ end
+
+ user.reload
+ end
+
+ private
+
+ def migrate_records
+ user.transaction(requires_new: true) do
@ghost_user = User.ghost
migrate_issues
migrate_merge_requests
migrate_notes
migrate_abuse_reports
- migrate_award_emoji
+ migrate_award_emojis
end
-
- user.reload
end
- private
-
def migrate_issues
user.issues.update_all(author_id: ghost_user.id)
end
@@ -52,7 +64,7 @@ module Users
user.reported_abuse_reports.update_all(reporter_id: ghost_user.id)
end
- def migrate_award_emoji
+ def migrate_award_emojis
user.award_emoji.update_all(user_id: ghost_user.id)
end
end
diff --git a/app/views/projects/_last_commit.html.haml b/app/views/projects/_last_commit.html.haml
index e1fea8ccf3d..df3b1c75508 100644
--- a/app/views/projects/_last_commit.html.haml
+++ b/app/views/projects/_last_commit.html.haml
@@ -1,10 +1,9 @@
-
- ref = local_assigns.fetch(:ref)
- status = commit.status(ref)
- if status
= link_to pipelines_namespace_project_commit_path(commit.project.namespace, commit.project, commit), class: "ci-status ci-#{status}" do
= ci_icon_for_status(status)
- = ci_label_for_status(status)
+ = ci_text_for_status(status)
= link_to commit.short_id, namespace_project_commit_path(project.namespace, project, commit), class: "commit_short_id"
= link_to_gfm commit.title, namespace_project_commit_path(project.namespace, project, commit), class: "commit-row-message"
diff --git a/app/views/projects/new.html.haml b/app/views/projects/new.html.haml
index 0c7b53e5a9a..9e292729425 100644
--- a/app/views/projects/new.html.haml
+++ b/app/views/projects/new.html.haml
@@ -145,7 +145,8 @@
}
});
+ $('#project_import_url').disable();
$('.import_git').click(function( event ) {
- $projectImportUrl = $('#project_import_url')
- $projectImportUrl.attr('disabled', !$projectImportUrl.attr('disabled'))
+ $projectImportUrl = $('#project_import_url');
+ $projectImportUrl.attr('disabled', !$projectImportUrl.attr('disabled'));
});
diff --git a/app/views/projects/triggers/_form.html.haml b/app/views/projects/triggers/_form.html.haml
index 8582bcbb8cc..70d654fa9a0 100644
--- a/app/views/projects/triggers/_form.html.haml
+++ b/app/views/projects/triggers/_form.html.haml
@@ -19,7 +19,7 @@
%strong Schedule trigger (experimental)
.help-block
If checked, this trigger will be executed periodically according to cron and timezone.
- = link_to icon('question-circle'), help_page_path('ci/triggers', anchor: 'schedule')
+ = link_to icon('question-circle'), help_page_path('ci/triggers/README', anchor: 'using-scheduled-triggers')
.form-group
= schedule_fields.label :cron, "Cron", class: "label-light"
= schedule_fields.text_field :cron, class: "form-control", title: 'Cron specification is required.', placeholder: "0 1 * * *"
diff --git a/app/views/shared/_personal_access_tokens_form.html.haml b/app/views/shared/_personal_access_tokens_form.html.haml
index e8062848fc3..b20055a564e 100644
--- a/app/views/shared/_personal_access_tokens_form.html.haml
+++ b/app/views/shared/_personal_access_tokens_form.html.haml
@@ -30,9 +30,10 @@
new Pikaday({
field: $dateField.get(0),
- theme: 'gitlab-theme',
+ theme: 'gitlab-theme animate-picker',
format: 'yyyy-mm-dd',
minDate: new Date(),
+ container: $dateField.parent().get(0),
onSelect: function(dateText) {
$dateField.val(dateFormat(new Date(dateText), 'yyyy-mm-dd'));
}
diff --git a/app/views/shared/milestones/_form_dates.html.haml b/app/views/shared/milestones/_form_dates.html.haml
index ed94773ef89..a74cdbe274b 100644
--- a/app/views/shared/milestones/_form_dates.html.haml
+++ b/app/views/shared/milestones/_form_dates.html.haml
@@ -3,10 +3,10 @@
= f.label :start_date, "Start Date", class: "control-label"
.col-sm-10
= f.text_field :start_date, class: "datepicker form-control", placeholder: "Select start date"
- %a.inline.prepend-top-5.js-clear-start-date{ href: "#" } Clear start date
+ %a.inline.pull-right.prepend-top-5.js-clear-start-date{ href: "#" } Clear start date
.col-md-6
.form-group
= f.label :due_date, "Due Date", class: "control-label"
.col-sm-10
= f.text_field :due_date, class: "datepicker form-control", placeholder: "Select due date"
- %a.inline.prepend-top-5.js-clear-due-date{ href: "#" } Clear due date
+ %a.inline.pull-right.prepend-top-5.js-clear-due-date{ href: "#" } Clear due date
diff --git a/app/views/shared/milestones/_issuable.html.haml b/app/views/shared/milestones/_issuable.html.haml
index 4c7d69d40d5..5247d6a51e6 100644
--- a/app/views/shared/milestones/_issuable.html.haml
+++ b/app/views/shared/milestones/_issuable.html.haml
@@ -1,11 +1,14 @@
-# @project is present when viewing Project's milestone
- project = @project || issuable.project
+- namespace = @project_namespace || project.namespace.becomes(Namespace)
- assignee = issuable.assignee
- issuable_type = issuable.class.table_name
-- base_url_args = [project.namespace.becomes(Namespace), project, issuable_type]
+- base_url_args = [namespace, project]
+- issuable_type_args = base_url_args + [issuable_type]
+- issuable_url_args = base_url_args + [issuable]
- can_update = can?(current_user, :"update_#{issuable.to_ability_name}", issuable)
-%li{ id: dom_id(issuable, 'sortable'), class: "issuable-row #{'is-disabled' unless can_update}", 'data-iid' => issuable.iid, 'data-id' => issuable.id, 'data-url' => polymorphic_path(issuable) }
+%li{ id: dom_id(issuable, 'sortable'), class: "issuable-row #{'is-disabled' unless can_update}", 'data-iid' => issuable.iid, 'data-id' => issuable.id, 'data-url' => polymorphic_path(issuable_url_args) }
%span
- if show_project_name
%strong #{project.name} &middot;
@@ -13,17 +16,17 @@
%strong #{project.name_with_namespace} &middot;
- if issuable.is_a?(Issue)
= confidential_icon(issuable)
- = link_to_gfm issuable.title, [project.namespace.becomes(Namespace), project, issuable], title: issuable.title
+ = link_to_gfm issuable.title, issuable_url_args, title: issuable.title
.issuable-detail
= link_to [project.namespace.becomes(Namespace), project, issuable] do
%span.issuable-number= issuable.to_reference
- issuable.labels.each do |label|
- = link_to polymorphic_path(base_url_args, { milestone_title: @milestone.title, label_name: label.title, state: 'all' }) do
+ = link_to polymorphic_path(issuable_type_args, { milestone_title: @milestone.title, label_name: label.title, state: 'all' }) do
- render_colored_label(label)
%span.assignee-icon
- if assignee
- = link_to polymorphic_path(base_url_args, { milestone_title: @milestone.title, assignee_id: issuable.assignee_id, state: 'all' }),
+ = link_to polymorphic_path(issuable_type_args, { milestone_title: @milestone.title, assignee_id: issuable.assignee_id, state: 'all' }),
class: 'has-tooltip', title: "Assigned to #{assignee.name}", data: { container: 'body' } do
- image_tag(avatar_icon(issuable.assignee, 16), class: "avatar s16", alt: '')
diff --git a/app/views/users/show.html.haml b/app/views/users/show.html.haml
index 969ea7ab9e6..03e5dd97405 100644
--- a/app/views/users/show.html.haml
+++ b/app/views/users/show.html.haml
@@ -84,19 +84,19 @@
.fade-right= icon('angle-right')
%ul.nav-links.center.user-profile-nav.scrolling-tabs
%li.js-activity-tab
- = link_to user_path, data: {target: 'div#activity', action: 'activity', toggle: 'tab'} do
+ = link_to user_path, data: { target: 'div#activity', action: 'activity', toggle: 'tab' } do
Activity
%li.js-groups-tab
- = link_to user_groups_path, data: {target: 'div#groups', action: 'groups', toggle: 'tab'} do
+ = link_to user_groups_path, data: { target: 'div#groups', action: 'groups', toggle: 'tab', endpoint: user_groups_path(format: :json) } do
Groups
%li.js-contributed-tab
- = link_to user_contributed_projects_path, data: {target: 'div#contributed', action: 'contributed', toggle: 'tab'} do
+ = link_to user_contributed_projects_path, data: { target: 'div#contributed', action: 'contributed', toggle: 'tab', endpoint: user_contributed_projects_path(format: :json) } do
Contributed projects
%li.js-projects-tab
- = link_to user_projects_path, data: {target: 'div#projects', action: 'projects', toggle: 'tab'} do
+ = link_to user_projects_path, data: { target: 'div#projects', action: 'projects', toggle: 'tab', endpoint: user_projects_path(format: :json) } do
Personal projects
%li.js-snippets-tab
- = link_to user_snippets_path, data: {target: 'div#snippets', action: 'snippets', toggle: 'tab'} do
+ = link_to user_snippets_path, data: { target: 'div#snippets', action: 'snippets', toggle: 'tab', endpoint: user_snippets_path(format: :json) } do
Snippets
%div{ class: container_class }
diff --git a/app/workers/clear_database_cache_worker.rb b/app/workers/clear_database_cache_worker.rb
deleted file mode 100644
index c4cb4733482..00000000000
--- a/app/workers/clear_database_cache_worker.rb
+++ /dev/null
@@ -1,24 +0,0 @@
-# This worker clears all cache fields in the database, working in batches.
-class ClearDatabaseCacheWorker
- include Sidekiq::Worker
- include DedicatedSidekiqQueue
-
- BATCH_SIZE = 1000
-
- def perform
- CacheMarkdownField.caching_classes.each do |kls|
- fields = kls.cached_markdown_fields.html_fields
- clear_cache_fields = fields.each_with_object({}) do |field, memo|
- memo[field] = nil
- end
-
- Rails.logger.debug("Clearing Markdown cache for #{kls}: #{fields.inspect}")
-
- kls.unscoped.in_batches(of: BATCH_SIZE) do |relation|
- relation.update_all(clear_cache_fields)
- end
- end
-
- nil
- end
-end
diff --git a/app/workers/expire_pipeline_cache_worker.rb b/app/workers/expire_pipeline_cache_worker.rb
new file mode 100644
index 00000000000..603e2f1aaea
--- /dev/null
+++ b/app/workers/expire_pipeline_cache_worker.rb
@@ -0,0 +1,57 @@
+class ExpirePipelineCacheWorker
+ include Sidekiq::Worker
+ include PipelineQueue
+
+ def perform(pipeline_id)
+ pipeline = Ci::Pipeline.find_by(id: pipeline_id)
+ return unless pipeline
+
+ project = pipeline.project
+ store = Gitlab::EtagCaching::Store.new
+
+ store.touch(project_pipelines_path(project))
+ store.touch(commit_pipelines_path(project, pipeline.commit)) if pipeline.commit
+ store.touch(new_merge_request_pipelines_path(project))
+ each_pipelines_merge_request_path(project, pipeline) do |path|
+ store.touch(path)
+ end
+
+ Gitlab::Cache::Ci::ProjectPipelineStatus.update_for_pipeline(pipeline)
+ end
+
+ private
+
+ def project_pipelines_path(project)
+ Gitlab::Routing.url_helpers.namespace_project_pipelines_path(
+ project.namespace,
+ project,
+ format: :json)
+ end
+
+ def commit_pipelines_path(project, commit)
+ Gitlab::Routing.url_helpers.pipelines_namespace_project_commit_path(
+ project.namespace,
+ project,
+ commit.id,
+ format: :json)
+ end
+
+ def new_merge_request_pipelines_path(project)
+ Gitlab::Routing.url_helpers.new_namespace_project_merge_request_path(
+ project.namespace,
+ project,
+ format: :json)
+ end
+
+ def each_pipelines_merge_request_path(project, pipeline)
+ pipeline.all_merge_requests.each do |merge_request|
+ path = Gitlab::Routing.url_helpers.pipelines_namespace_project_merge_request_path(
+ project.namespace,
+ project,
+ merge_request,
+ format: :json)
+
+ yield(path)
+ end
+ end
+end
diff --git a/changelogs/unreleased/12818-ci-status-as-favicon.yml b/changelogs/unreleased/12818-ci-status-as-favicon.yml
deleted file mode 100644
index 70194178d90..00000000000
--- a/changelogs/unreleased/12818-ci-status-as-favicon.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Show CI status as Favicon on Pipelines, Job and MR pages
-merge_request: 10144
-author:
diff --git a/changelogs/unreleased/12818-expose-simple-cicd-status-endpoints-with-status-serializer-gitlab-ci-status-for-pipeline-job-and-merge-request.yml b/changelogs/unreleased/12818-expose-simple-cicd-status-endpoints-with-status-serializer-gitlab-ci-status-for-pipeline-job-and-merge-request.yml
deleted file mode 100644
index 953009213df..00000000000
--- a/changelogs/unreleased/12818-expose-simple-cicd-status-endpoints-with-status-serializer-gitlab-ci-status-for-pipeline-job-and-merge-request.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Expose CI/CD status API endpoints with Gitlab::Ci::Status facility on pipeline,
- job and merge request for favicon
-merge_request: 9561
-author: dosuken123
diff --git a/changelogs/unreleased/1440-db-backup-ssl-support.yml b/changelogs/unreleased/1440-db-backup-ssl-support.yml
new file mode 100644
index 00000000000..c78bb4fd351
--- /dev/null
+++ b/changelogs/unreleased/1440-db-backup-ssl-support.yml
@@ -0,0 +1,4 @@
+---
+title: Database SSL support for backup script.
+merge_request: 9715
+author: Guillaume Simon
diff --git a/changelogs/unreleased/17325-rugged-gem-update.yml b/changelogs/unreleased/17325-rugged-gem-update.yml
deleted file mode 100644
index 7ca619439c4..00000000000
--- a/changelogs/unreleased/17325-rugged-gem-update.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Update rugged to 0.25.1.1
-merge_request: 10286
-author: Elan Ruusamäe
diff --git a/changelogs/unreleased/18471-restrict-tag-pushes-protected-tags.yml b/changelogs/unreleased/18471-restrict-tag-pushes-protected-tags.yml
deleted file mode 100644
index fabe24e485a..00000000000
--- a/changelogs/unreleased/18471-restrict-tag-pushes-protected-tags.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Tags can be protected, restricting creation of matching tags by user role
-merge_request: 10356
-author:
diff --git a/changelogs/unreleased/19742-permalink-blame-button-line-number-hash-links.yml b/changelogs/unreleased/19742-permalink-blame-button-line-number-hash-links.yml
deleted file mode 100644
index 199f1edec8b..00000000000
--- a/changelogs/unreleased/19742-permalink-blame-button-line-number-hash-links.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Update permalink/blame buttons with line number fragment hash
-merge_request:
-author:
diff --git a/changelogs/unreleased/20841-getting-started-better-empty-state-for-merge-requests-view.yml b/changelogs/unreleased/20841-getting-started-better-empty-state-for-merge-requests-view.yml
deleted file mode 100644
index 34909c06df3..00000000000
--- a/changelogs/unreleased/20841-getting-started-better-empty-state-for-merge-requests-view.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Added merge requests empty state
-merge_request: 7342
-author:
diff --git a/changelogs/unreleased/20914-project-home-width.yml b/changelogs/unreleased/20914-project-home-width.yml
deleted file mode 100644
index 323a614f3c8..00000000000
--- a/changelogs/unreleased/20914-project-home-width.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Limit line length for project home page
-merge_request:
-author:
diff --git a/changelogs/unreleased/2120-issues-search-bar-not-picking-up.yml b/changelogs/unreleased/2120-issues-search-bar-not-picking-up.yml
deleted file mode 100644
index 706609b7baf..00000000000
--- a/changelogs/unreleased/2120-issues-search-bar-not-picking-up.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Fix filtered search input width for IE
-merge_request:
-author:
diff --git a/changelogs/unreleased/21451-allow-disable-mr-link.yml b/changelogs/unreleased/21451-allow-disable-mr-link.yml
deleted file mode 100644
index ef99970a7a2..00000000000
--- a/changelogs/unreleased/21451-allow-disable-mr-link.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Add ability to disable Merge Request URL on push
-merge_request: 9663
-author: Alex Sanford
diff --git a/changelogs/unreleased/22303-symbolic-in-tree.yml b/changelogs/unreleased/22303-symbolic-in-tree.yml
deleted file mode 100644
index 02444f571d0..00000000000
--- a/changelogs/unreleased/22303-symbolic-in-tree.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Fix symlink icon in project tree
-merge_request: 9780
-author: mhasbini
diff --git a/changelogs/unreleased/23363-use-strong-params-in-wikis-controller.yml b/changelogs/unreleased/23363-use-strong-params-in-wikis-controller.yml
deleted file mode 100644
index dd342d38fef..00000000000
--- a/changelogs/unreleased/23363-use-strong-params-in-wikis-controller.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Update wikis_controller.rb to use strong params
-merge_request:
-author:
diff --git a/changelogs/unreleased/23655-api-group-issues.yml b/changelogs/unreleased/23655-api-group-issues.yml
deleted file mode 100644
index e19e588d09e..00000000000
--- a/changelogs/unreleased/23655-api-group-issues.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Fix API group/issues default state filter
-merge_request:
-author: Alexander Randa
diff --git a/changelogs/unreleased/23674-simplify-milestone-summary.yml b/changelogs/unreleased/23674-simplify-milestone-summary.yml
deleted file mode 100644
index 7a315c25151..00000000000
--- a/changelogs/unreleased/23674-simplify-milestone-summary.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Move milestone summary content into the sidebar
-merge_request: 10096
-author:
diff --git a/changelogs/unreleased/23862-fix-group-project-count.yml b/changelogs/unreleased/23862-fix-group-project-count.yml
deleted file mode 100644
index 7b2e9f9bfa6..00000000000
--- a/changelogs/unreleased/23862-fix-group-project-count.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Adding non_archived scope for counting projects
-merge_request: 8305
-author: Naveen Kumar
diff --git a/changelogs/unreleased/24137-issuable-permalink.yml b/changelogs/unreleased/24137-issuable-permalink.yml
deleted file mode 100644
index bcc6c6957a1..00000000000
--- a/changelogs/unreleased/24137-issuable-permalink.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Link issuable reference to itself in meta-header
-merge_request: 9641
-author: mhasbini
diff --git a/changelogs/unreleased/24166-close-builds-dropdown.yml b/changelogs/unreleased/24166-close-builds-dropdown.yml
deleted file mode 100644
index c57ffed6b45..00000000000
--- a/changelogs/unreleased/24166-close-builds-dropdown.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Prevent builds dropdown to close when the user clicks in a build
-merge_request:
-author:
diff --git a/changelogs/unreleased/24187-set-git-terminal-prompt-env-var-in-initializer.yml b/changelogs/unreleased/24187-set-git-terminal-prompt-env-var-in-initializer.yml
deleted file mode 100644
index 7fe5c8a84af..00000000000
--- a/changelogs/unreleased/24187-set-git-terminal-prompt-env-var-in-initializer.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Set GIT_TERMINAL_PROMPT env variable in initializer
-merge_request: 10372
-author:
diff --git a/changelogs/unreleased/24215-closed-issues-board.yml b/changelogs/unreleased/24215-closed-issues-board.yml
deleted file mode 100644
index 678ec34b274..00000000000
--- a/changelogs/unreleased/24215-closed-issues-board.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Display all closed issues in “done” board list
-merge_request:
-author:
diff --git a/changelogs/unreleased/24240-add-monitoring-endpoints.yml b/changelogs/unreleased/24240-add-monitoring-endpoints.yml
deleted file mode 100644
index a22458965fc..00000000000
--- a/changelogs/unreleased/24240-add-monitoring-endpoints.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Add /-/readiness /-/liveness and /-/metrics endpoints to track application health
-merge_request: 10416
-author:
diff --git a/changelogs/unreleased/24421-personal-milestone-count-badges.yml b/changelogs/unreleased/24421-personal-milestone-count-badges.yml
deleted file mode 100644
index 8bbc1ed2dde..00000000000
--- a/changelogs/unreleased/24421-personal-milestone-count-badges.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Add dashboard and group milestones count badges
-merge_request: 9836
-author: Alex Braha Stoll
diff --git a/changelogs/unreleased/24501-new-file-existing-branch.yml b/changelogs/unreleased/24501-new-file-existing-branch.yml
deleted file mode 100644
index 31c66b2a978..00000000000
--- a/changelogs/unreleased/24501-new-file-existing-branch.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: New file from interface on existing branch
-merge_request: 8427
-author: Jacopo Beschi @jacopo-beschi
diff --git a/changelogs/unreleased/24784-system-notes-meta-data.yml b/changelogs/unreleased/24784-system-notes-meta-data.yml
deleted file mode 100644
index 757ae9e0527..00000000000
--- a/changelogs/unreleased/24784-system-notes-meta-data.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Add metadata to system notes
-merge_request: 9964
-author:
diff --git a/changelogs/unreleased/24861-stringify-group-member-details.yml b/changelogs/unreleased/24861-stringify-group-member-details.yml
deleted file mode 100644
index f56a1060862..00000000000
--- a/changelogs/unreleased/24861-stringify-group-member-details.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Hide form inputs for group member without editing rights
-merge_request: 7816
-author:
diff --git a/changelogs/unreleased/25188-polyfill-es-symbol.yml b/changelogs/unreleased/25188-polyfill-es-symbol.yml
deleted file mode 100644
index d0cf36b9ec6..00000000000
--- a/changelogs/unreleased/25188-polyfill-es-symbol.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Add ECMAScript polyfills for Symbol and Array.find
-merge_request: 10120
-author:
diff --git a/changelogs/unreleased/25332-make-file-templates-easy-to-use-and-discover.yml b/changelogs/unreleased/25332-make-file-templates-easy-to-use-and-discover.yml
deleted file mode 100644
index fc95858f783..00000000000
--- a/changelogs/unreleased/25332-make-file-templates-easy-to-use-and-discover.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Remove no-new annotation from file_template_mediator.js.
-merge_request: !9782
-author:
diff --git a/changelogs/unreleased/25515-delegate-single-discussion-to-new-issue.yml b/changelogs/unreleased/25515-delegate-single-discussion-to-new-issue.yml
deleted file mode 100644
index 5b755a8bc32..00000000000
--- a/changelogs/unreleased/25515-delegate-single-discussion-to-new-issue.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Create a new issue for a single discussion in a Merge Request
-merge_request: 8266
-author: Bob Van Landuyt
diff --git a/changelogs/unreleased/25556-prevent-users-from-disconnecting-gitlab-account-from-cas.yml b/changelogs/unreleased/25556-prevent-users-from-disconnecting-gitlab-account-from-cas.yml
deleted file mode 100644
index 17e38ba6243..00000000000
--- a/changelogs/unreleased/25556-prevent-users-from-disconnecting-gitlab-account-from-cas.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Prevent users from disconnecting GitLab account from CAS
-merge_request: 10282
-author:
diff --git a/changelogs/unreleased/26188-tag-creation-404-for-guests.yml b/changelogs/unreleased/26188-tag-creation-404-for-guests.yml
deleted file mode 100644
index fb00d46ea1f..00000000000
--- a/changelogs/unreleased/26188-tag-creation-404-for-guests.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Don't show links to tag a commit for users that are not permitted
-merge_request: 8407
-author:
diff --git a/changelogs/unreleased/26202-change-dropdown-style-slightly.yml b/changelogs/unreleased/26202-change-dropdown-style-slightly.yml
deleted file mode 100644
index 827224abf5a..00000000000
--- a/changelogs/unreleased/26202-change-dropdown-style-slightly.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Changed dropdown style slightly
-merge_request:
-author:
diff --git a/changelogs/unreleased/26208-animate-drodowns.yml b/changelogs/unreleased/26208-animate-drodowns.yml
new file mode 100644
index 00000000000..580f6c12f67
--- /dev/null
+++ b/changelogs/unreleased/26208-animate-drodowns.yml
@@ -0,0 +1,4 @@
+---
+title: Add animations to all the dropdowns
+merge_request: 8419
+author:
diff --git a/changelogs/unreleased/26236-monospace-gfm.yml b/changelogs/unreleased/26236-monospace-gfm.yml
deleted file mode 100644
index c44f3d4d3dc..00000000000
--- a/changelogs/unreleased/26236-monospace-gfm.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Change gfm textarea to use monospace font
-merge_request:
-author:
diff --git a/changelogs/unreleased/26470-branch-names-with-reference-prefixes-results-in-buggy-branches.yml b/changelogs/unreleased/26470-branch-names-with-reference-prefixes-results-in-buggy-branches.yml
deleted file mode 100644
index e82cbf00cfb..00000000000
--- a/changelogs/unreleased/26470-branch-names-with-reference-prefixes-results-in-buggy-branches.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Strip reference prefixes on branch creation
-merge_request: 8498
-author: Matthieu Tardy
diff --git a/changelogs/unreleased/27114-add-undo-mark-all-as-done-to-todos.yml b/changelogs/unreleased/27114-add-undo-mark-all-as-done-to-todos.yml
deleted file mode 100644
index 44aae486574..00000000000
--- a/changelogs/unreleased/27114-add-undo-mark-all-as-done-to-todos.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Add Undo mark all as done to Todos
-merge_request: 9890
-author: Jacopo Beschi @jacopo-beschi
diff --git a/changelogs/unreleased/27114-add-undo-to-todos-in-the-done-tab.yml b/changelogs/unreleased/27114-add-undo-to-todos-in-the-done-tab.yml
deleted file mode 100644
index 2e6c10a6bfe..00000000000
--- a/changelogs/unreleased/27114-add-undo-to-todos-in-the-done-tab.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Add Undo to Todos in the Done tab
-merge_request: 8782
-author: Jacopo Beschi @jacopo-beschi
diff --git a/changelogs/unreleased/27174-filter-filters.yml b/changelogs/unreleased/27174-filter-filters.yml
deleted file mode 100644
index 0da1e4d5d3b..00000000000
--- a/changelogs/unreleased/27174-filter-filters.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Prevent filtering issues by multiple Milestones or Authors
-merge_request:
-author:
diff --git a/changelogs/unreleased/27262-issue-recent-searches.yml b/changelogs/unreleased/27262-issue-recent-searches.yml
deleted file mode 100644
index 4bdec5af31d..00000000000
--- a/changelogs/unreleased/27262-issue-recent-searches.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Recent search history for issues
-merge_request:
-author:
diff --git a/changelogs/unreleased/27271-missing-time-spent-in-issue-webhook.yml b/changelogs/unreleased/27271-missing-time-spent-in-issue-webhook.yml
deleted file mode 100644
index 4ea52a70e89..00000000000
--- a/changelogs/unreleased/27271-missing-time-spent-in-issue-webhook.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Include time tracking attributes in webhooks payload
-merge_request: 9942
-author:
diff --git a/changelogs/unreleased/27293-remove-repeated-labels.yml b/changelogs/unreleased/27293-remove-repeated-labels.yml
deleted file mode 100644
index 60caa6e971a..00000000000
--- a/changelogs/unreleased/27293-remove-repeated-labels.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Remove duplicated tokens in issuable search bar
-merge_request:
-author:
diff --git a/changelogs/unreleased/27503-feature-status-aria-labels.yml b/changelogs/unreleased/27503-feature-status-aria-labels.yml
deleted file mode 100644
index f514fd5b631..00000000000
--- a/changelogs/unreleased/27503-feature-status-aria-labels.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Add `aria-label` for feature status accessibility
-merge_request: 9830
-author:
diff --git a/changelogs/unreleased/27574-pipelines-empty-state.yml b/changelogs/unreleased/27574-pipelines-empty-state.yml
deleted file mode 100644
index c26ea97205f..00000000000
--- a/changelogs/unreleased/27574-pipelines-empty-state.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Adds empty and error state to pipelines
-merge_request:
-author:
diff --git a/changelogs/unreleased/27580-fix-show-go-back.yml b/changelogs/unreleased/27580-fix-show-go-back.yml
deleted file mode 100644
index c7dbbe7a236..00000000000
--- a/changelogs/unreleased/27580-fix-show-go-back.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Shows 'Go Back' link only when browser history is available
-merge_request: 9017
-author:
diff --git a/changelogs/unreleased/27878-new-service-for-creating-user.yml b/changelogs/unreleased/27878-new-service-for-creating-user.yml
deleted file mode 100644
index c07f0cef8db..00000000000
--- a/changelogs/unreleased/27878-new-service-for-creating-user.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Implement user create service
-merge_request: 9220
-author: George Andrinopoulos
diff --git a/changelogs/unreleased/27910-admin-can-create-project-in-all-groups.yml b/changelogs/unreleased/27910-admin-can-create-project-in-all-groups.yml
deleted file mode 100644
index 40fd8dacc82..00000000000
--- a/changelogs/unreleased/27910-admin-can-create-project-in-all-groups.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Allow admin to view all namespaces
-merge_request:
-author: George Andrinopoulos
diff --git a/changelogs/unreleased/27988-fix-transient-failure-in-commits-api.yml b/changelogs/unreleased/27988-fix-transient-failure-in-commits-api.yml
deleted file mode 100644
index c6ba9572f26..00000000000
--- a/changelogs/unreleased/27988-fix-transient-failure-in-commits-api.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: 'Add `requirements: { id: /.+/ }` for all projects and groups namespaced API
- routes'
-merge_request: 9944
-author:
diff --git a/changelogs/unreleased/28030-infinite-offset.yml b/changelogs/unreleased/28030-infinite-offset.yml
deleted file mode 100644
index 6f4082d7684..00000000000
--- a/changelogs/unreleased/28030-infinite-offset.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: allow offset query parameter for infinite list pages
-merge_request:
-author:
diff --git a/changelogs/unreleased/28187-project-name-cut-off-with-nested-groups.yml b/changelogs/unreleased/28187-project-name-cut-off-with-nested-groups.yml
deleted file mode 100644
index feca38ff083..00000000000
--- a/changelogs/unreleased/28187-project-name-cut-off-with-nested-groups.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Use toggle button to expand / collapse mulit-nested groups
-merge_request: 9501
-author:
diff --git a/changelogs/unreleased/28402-fix-starred-projects-filter-wrong-message-on-no-results.yml b/changelogs/unreleased/28402-fix-starred-projects-filter-wrong-message-on-no-results.yml
deleted file mode 100644
index dd94b3fe663..00000000000
--- a/changelogs/unreleased/28402-fix-starred-projects-filter-wrong-message-on-no-results.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Fix wrong message on starred projects filtering
-merge_request:
-author: George Andrinopoulos
diff --git a/changelogs/unreleased/28424-labels-support-color-names-in-backend.yml b/changelogs/unreleased/28424-labels-support-color-names-in-backend.yml
deleted file mode 100644
index 00da1e0fa60..00000000000
--- a/changelogs/unreleased/28424-labels-support-color-names-in-backend.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Labels support color names in backend
-merge_request: 9725
-author: Dongqing Hu
diff --git a/changelogs/unreleased/28494-mini-pipeline-graph-commit-view.yml b/changelogs/unreleased/28494-mini-pipeline-graph-commit-view.yml
deleted file mode 100644
index 67dbc30e760..00000000000
--- a/changelogs/unreleased/28494-mini-pipeline-graph-commit-view.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Adds pipeline mini-graph to system information box in Commit View
-merge_request:
-author:
diff --git a/changelogs/unreleased/28574-jira-trigers.yml b/changelogs/unreleased/28574-jira-trigers.yml
deleted file mode 100644
index 6ebd2c0c2c2..00000000000
--- a/changelogs/unreleased/28574-jira-trigers.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Remove confusing placeholder for JIRA transition_id
-merge_request:
-author:
diff --git a/changelogs/unreleased/28614-harmonious-color-palette.yml b/changelogs/unreleased/28614-harmonious-color-palette.yml
deleted file mode 100644
index b436e7129a4..00000000000
--- a/changelogs/unreleased/28614-harmonious-color-palette.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Update color palette to a more harmonious and consistent one.
-merge_request: 10154
-author:
diff --git a/changelogs/unreleased/28634-todos-margin.yml b/changelogs/unreleased/28634-todos-margin.yml
deleted file mode 100644
index f4221ce4350..00000000000
--- a/changelogs/unreleased/28634-todos-margin.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Remove extra margin at bottom of todos page
-merge_request:
-author:
diff --git a/changelogs/unreleased/28660-fix-dismissable-error-close-not-visible-enough.yml b/changelogs/unreleased/28660-fix-dismissable-error-close-not-visible-enough.yml
deleted file mode 100644
index 8b592766bf3..00000000000
--- a/changelogs/unreleased/28660-fix-dismissable-error-close-not-visible-enough.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Fixes dismissable error close is not visible enough
-merge_request: 9516
-author:
diff --git a/changelogs/unreleased/28695-move-all-associated-records-to-ghost-user.yml b/changelogs/unreleased/28695-move-all-associated-records-to-ghost-user.yml
deleted file mode 100644
index c5dcde48028..00000000000
--- a/changelogs/unreleased/28695-move-all-associated-records-to-ghost-user.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Deleting a user should not delete associated records
-merge_request: 10467
-author:
diff --git a/changelogs/unreleased/28713-fe-style-guide.yml b/changelogs/unreleased/28713-fe-style-guide.yml
deleted file mode 100644
index 57edb43e27f..00000000000
--- a/changelogs/unreleased/28713-fe-style-guide.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Adds Frontend Styleguide to documentation
-merge_request: 9961
-author:
diff --git a/changelogs/unreleased/28732-expandable-folders.yml b/changelogs/unreleased/28732-expandable-folders.yml
deleted file mode 100644
index 9ae30ba6253..00000000000
--- a/changelogs/unreleased/28732-expandable-folders.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Add back expandable folder behavior
-merge_request:
-author:
diff --git a/changelogs/unreleased/28799-todo-creation.yml b/changelogs/unreleased/28799-todo-creation.yml
deleted file mode 100644
index c6e05468568..00000000000
--- a/changelogs/unreleased/28799-todo-creation.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Create todos only for new mentions
-merge_request:
-author:
diff --git a/changelogs/unreleased/28810-projectfinder-should-handle-more-options.yml b/changelogs/unreleased/28810-projectfinder-should-handle-more-options.yml
deleted file mode 100644
index e4be16d4b37..00000000000
--- a/changelogs/unreleased/28810-projectfinder-should-handle-more-options.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: ProjectsFinder should handle more options
-merge_request: 9682
-author: Jacopo Beschi @jacopo-beschi
diff --git a/changelogs/unreleased/28874-fix-milestone-issues-position-order-in-api.yml b/changelogs/unreleased/28874-fix-milestone-issues-position-order-in-api.yml
deleted file mode 100644
index 0177394aa0f..00000000000
--- a/changelogs/unreleased/28874-fix-milestone-issues-position-order-in-api.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Order milestone issues by position ascending in api
-merge_request: 9635
-author: George Andrinopoulos
diff --git a/changelogs/unreleased/28899-linking-to-edit-file.yml b/changelogs/unreleased/28899-linking-to-edit-file.yml
deleted file mode 100644
index a9f5410693b..00000000000
--- a/changelogs/unreleased/28899-linking-to-edit-file.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Linking to blob edit page handles anonymous users and users without enough permissions
- to edit directly
-merge_request:
-author:
diff --git a/changelogs/unreleased/28991-viewing-old-wiki-page-version-edit-button-exists.yml b/changelogs/unreleased/28991-viewing-old-wiki-page-version-edit-button-exists.yml
deleted file mode 100644
index 26989c14958..00000000000
--- a/changelogs/unreleased/28991-viewing-old-wiki-page-version-edit-button-exists.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: When viewing old wiki page version, edit button should be disabled
-merge_request: 9966
-author: TM Lee
diff --git a/changelogs/unreleased/29014-create-issue-form-buttons-misaligned-on-mobile.yml b/changelogs/unreleased/29014-create-issue-form-buttons-misaligned-on-mobile.yml
deleted file mode 100644
index f869249c22b..00000000000
--- a/changelogs/unreleased/29014-create-issue-form-buttons-misaligned-on-mobile.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Fix create issue form buttons are misaligned on mobile
-merge_request: 9706
-author: TM Lee
diff --git a/changelogs/unreleased/29043-upgrade-vue-and-remove-warnings.yml b/changelogs/unreleased/29043-upgrade-vue-and-remove-warnings.yml
deleted file mode 100644
index 9055b23a13f..00000000000
--- a/changelogs/unreleased/29043-upgrade-vue-and-remove-warnings.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Upgrade VueJS to v2.2.4 and disable dev mode warnings
-merge_request: 9981
-author:
diff --git a/changelogs/unreleased/29046-fix-github-importer-open-prs.yml b/changelogs/unreleased/29046-fix-github-importer-open-prs.yml
deleted file mode 100644
index d279c269f94..00000000000
--- a/changelogs/unreleased/29046-fix-github-importer-open-prs.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Fix GitHub Import deleting branches for open PRs from a fork
-merge_request: 9758
-author:
diff --git a/changelogs/unreleased/29116-maxint-error.yml b/changelogs/unreleased/29116-maxint-error.yml
deleted file mode 100644
index 06e976617d5..00000000000
--- a/changelogs/unreleased/29116-maxint-error.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Fix projects_limit RangeError on user create
-merge_request:
-author: Alexander Randa
diff --git a/changelogs/unreleased/29128-profile-page-icons.yml b/changelogs/unreleased/29128-profile-page-icons.yml
deleted file mode 100644
index 0215f5c0e8f..00000000000
--- a/changelogs/unreleased/29128-profile-page-icons.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Add helpful icons to profile events
-merge_request:
-author:
diff --git a/changelogs/unreleased/29137-bulk-perform-async-should-specify-queue.yml b/changelogs/unreleased/29137-bulk-perform-async-should-specify-queue.yml
deleted file mode 100644
index 0de7754badc..00000000000
--- a/changelogs/unreleased/29137-bulk-perform-async-should-specify-queue.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Make authorized projects worker use a specific queue instead of the default one
-merge_request: 9813
-author:
diff --git a/changelogs/unreleased/29162-refactor-dropdown-milestone-spec.yml b/changelogs/unreleased/29162-refactor-dropdown-milestone-spec.yml
deleted file mode 100644
index ad0c513f525..00000000000
--- a/changelogs/unreleased/29162-refactor-dropdown-milestone-spec.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Refactor dropdown_milestone_spec.rb
-merge_request:
-author: George Andrinopoulos
diff --git a/changelogs/unreleased/29189-discussion-button.yml b/changelogs/unreleased/29189-discussion-button.yml
deleted file mode 100644
index eea96362117..00000000000
--- a/changelogs/unreleased/29189-discussion-button.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Fix alignment of resolve button
-merge_request:
-author:
diff --git a/changelogs/unreleased/29209-sign-up-form-name.yml b/changelogs/unreleased/29209-sign-up-form-name.yml
deleted file mode 100644
index e8e3a71f875..00000000000
--- a/changelogs/unreleased/29209-sign-up-form-name.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Change label for name on sign up form
-merge_request:
-author:
diff --git a/changelogs/unreleased/29328-fix-transient-failure-in-model-user-spec.yml b/changelogs/unreleased/29328-fix-transient-failure-in-model-user-spec.yml
deleted file mode 100644
index dabf9968c5b..00000000000
--- a/changelogs/unreleased/29328-fix-transient-failure-in-model-user-spec.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Add custom attributes in factories
-merge_request: 9892
-author: George Andrinopoulos
diff --git a/changelogs/unreleased/29341-add-metrics-button-env-overview.yml b/changelogs/unreleased/29341-add-metrics-button-env-overview.yml
deleted file mode 100644
index 16b69235dff..00000000000
--- a/changelogs/unreleased/29341-add-metrics-button-env-overview.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Add metrics button to environments overview page
-merge_request: 10234
-author:
diff --git a/changelogs/unreleased/29364-private-projects-mr-fix.yml b/changelogs/unreleased/29364-private-projects-mr-fix.yml
deleted file mode 100644
index ab93d6f337b..00000000000
--- a/changelogs/unreleased/29364-private-projects-mr-fix.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Don’t show source project name when user does not have access
-merge_request:
-author:
diff --git a/changelogs/unreleased/29405-fix-project-wiki-update.yml b/changelogs/unreleased/29405-fix-project-wiki-update.yml
deleted file mode 100644
index 85be36f7902..00000000000
--- a/changelogs/unreleased/29405-fix-project-wiki-update.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Fix Project Wiki update
-merge_request: 9990
-author: Dongqing Hu
diff --git a/changelogs/unreleased/29414-fix-toggle-discussion-link-jump.yml b/changelogs/unreleased/29414-fix-toggle-discussion-link-jump.yml
deleted file mode 100644
index 04342f5359d..00000000000
--- a/changelogs/unreleased/29414-fix-toggle-discussion-link-jump.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Update toggle buttons to be <button>
-merge_request:
-author:
diff --git a/changelogs/unreleased/29428-new-directory-from-existing-branch.yml b/changelogs/unreleased/29428-new-directory-from-existing-branch.yml
deleted file mode 100644
index b3f7cd1f8f8..00000000000
--- a/changelogs/unreleased/29428-new-directory-from-existing-branch.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: New directory from interface on existing branch
-merge_request: 9921
-author: Jacopo Beschi @jacopo-beschi
diff --git a/changelogs/unreleased/29432-prevent-click-disabled-btn.yml b/changelogs/unreleased/29432-prevent-click-disabled-btn.yml
deleted file mode 100644
index f30570cf68b..00000000000
--- a/changelogs/unreleased/29432-prevent-click-disabled-btn.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Fix project title validation, prevent clicking on disabled button
-merge_request: 9931
-author:
diff --git a/changelogs/unreleased/29438-fix-trigger-webhook-for-ref-with-dot.yml b/changelogs/unreleased/29438-fix-trigger-webhook-for-ref-with-dot.yml
deleted file mode 100644
index 61ffb64fa8f..00000000000
--- a/changelogs/unreleased/29438-fix-trigger-webhook-for-ref-with-dot.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Fix trigger webhook for ref with a dot
-merge_request: 10001
-author: George Andrinopoulos
diff --git a/changelogs/unreleased/29469-message-for-project-x-will-be-deleted-should-include-namespace.yml b/changelogs/unreleased/29469-message-for-project-x-will-be-deleted-should-include-namespace.yml
deleted file mode 100644
index 23a32d2c11a..00000000000
--- a/changelogs/unreleased/29469-message-for-project-x-will-be-deleted-should-include-namespace.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Display full project name with namespace upon deletion
-merge_request:
-author:
diff --git a/changelogs/unreleased/29483-spam-check-only-title-and-description.yml b/changelogs/unreleased/29483-spam-check-only-title-and-description.yml
deleted file mode 100644
index de8cacb250d..00000000000
--- a/changelogs/unreleased/29483-spam-check-only-title-and-description.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Spam check only when spammable attributes have changed
-merge_request:
-author:
diff --git a/changelogs/unreleased/29492-useless-queries.yml b/changelogs/unreleased/29492-useless-queries.yml
deleted file mode 100644
index 266a04be352..00000000000
--- a/changelogs/unreleased/29492-useless-queries.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Remove useless queries with false conditions (e.g 1=0)
-merge_request: 10141
-author: mhasbini
diff --git a/changelogs/unreleased/29550-fix-quick-submit-on-preview.yml b/changelogs/unreleased/29550-fix-quick-submit-on-preview.yml
deleted file mode 100644
index 71214971ffd..00000000000
--- a/changelogs/unreleased/29550-fix-quick-submit-on-preview.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Fix quick submit short-cut on preview tab for comments
-merge_request: 10002
-author:
diff --git a/changelogs/unreleased/29555-align-all-todo.yml b/changelogs/unreleased/29555-align-all-todo.yml
deleted file mode 100644
index c1555a96a92..00000000000
--- a/changelogs/unreleased/29555-align-all-todo.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: align Mark all as done with other Done buttons on Todos page
-merge_request:
-author:
diff --git a/changelogs/unreleased/29575-polling.yml b/changelogs/unreleased/29575-polling.yml
deleted file mode 100644
index 75016afd455..00000000000
--- a/changelogs/unreleased/29575-polling.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Adds polling utility function for vue resource
-merge_request:
-author:
diff --git a/changelogs/unreleased/29662-allow-unauthenticated-branches-api.yml b/changelogs/unreleased/29662-allow-unauthenticated-branches-api.yml
deleted file mode 100644
index 15d7b9dcafb..00000000000
--- a/changelogs/unreleased/29662-allow-unauthenticated-branches-api.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Allow unauthenticated access to some Branch API GET endpoints
-merge_request:
-author:
diff --git a/changelogs/unreleased/29669-redirect-referer-params.yml b/changelogs/unreleased/29669-redirect-referer-params.yml
deleted file mode 100644
index d8fc7f33049..00000000000
--- a/changelogs/unreleased/29669-redirect-referer-params.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Fix redirection after login when the referer have params
-merge_request:
-author: mhasbini
diff --git a/changelogs/unreleased/29670-jira-integration-documentation-improvment.yml b/changelogs/unreleased/29670-jira-integration-documentation-improvment.yml
deleted file mode 100644
index 8975f0b6ef3..00000000000
--- a/changelogs/unreleased/29670-jira-integration-documentation-improvment.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Added clarification to the Jira integration documentation.
-merge_request: 10066
-author: Matthew Bender
diff --git a/changelogs/unreleased/29712-unnecessary-wait-for-ajax.yml b/changelogs/unreleased/29712-unnecessary-wait-for-ajax.yml
new file mode 100644
index 00000000000..8dc657a4aba
--- /dev/null
+++ b/changelogs/unreleased/29712-unnecessary-wait-for-ajax.yml
@@ -0,0 +1,4 @@
+---
+title: Remove unnecessary test helpers includes
+merge_request: 10567
+author: Jacopo Beschi @jacopo-beschi
diff --git a/changelogs/unreleased/29801-add-slash-slack-commands-to-api-doc.yml b/changelogs/unreleased/29801-add-slash-slack-commands-to-api-doc.yml
new file mode 100644
index 00000000000..9c5df690085
--- /dev/null
+++ b/changelogs/unreleased/29801-add-slash-slack-commands-to-api-doc.yml
@@ -0,0 +1,5 @@
+---
+title: Add Slack slash command api to services documentation and rearrange order and
+ cases
+merge_request: 10757
+author: TM Lee
diff --git a/changelogs/unreleased/29828-change-search-hint-in-new-filters.yml b/changelogs/unreleased/29828-change-search-hint-in-new-filters.yml
deleted file mode 100644
index a9322693ca4..00000000000
--- a/changelogs/unreleased/29828-change-search-hint-in-new-filters.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Change hint on first row of filters dropdown to `Press Enter or click to search`
-merge_request: 10138
-author:
diff --git a/changelogs/unreleased/29830-build-scroll-indicator.yml b/changelogs/unreleased/29830-build-scroll-indicator.yml
deleted file mode 100644
index e899a828de7..00000000000
--- a/changelogs/unreleased/29830-build-scroll-indicator.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: fix sidebar padding for build and wiki pages
-merge_request:
-author:
diff --git a/changelogs/unreleased/29843-project-subgroup-transfer.yml b/changelogs/unreleased/29843-project-subgroup-transfer.yml
deleted file mode 100644
index 1cf83517591..00000000000
--- a/changelogs/unreleased/29843-project-subgroup-transfer.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Correctly update paths when changing a child group
-merge_request:
-author:
diff --git a/changelogs/unreleased/2989-run-cicd-pipelines-on-a-schedule-idea1-basic-backend-implementation.yml b/changelogs/unreleased/2989-run-cicd-pipelines-on-a-schedule-idea1-basic-backend-implementation.yml
deleted file mode 100644
index dd56409c35b..00000000000
--- a/changelogs/unreleased/2989-run-cicd-pipelines-on-a-schedule-idea1-basic-backend-implementation.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Resolve "Run CI/CD pipelines on a schedule" - "Basic backend implementation"
-merge_request: 10133
-author: dosuken123
diff --git a/changelogs/unreleased/29897-remove-force-scroll-for-mr-changes-diff.yml b/changelogs/unreleased/29897-remove-force-scroll-for-mr-changes-diff.yml
deleted file mode 100644
index d1da96096f8..00000000000
--- a/changelogs/unreleased/29897-remove-force-scroll-for-mr-changes-diff.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Remove forced scroll into view when switching to Changes MR tab
-merge_request:
-author:
diff --git a/changelogs/unreleased/29929-jira-doc.yml b/changelogs/unreleased/29929-jira-doc.yml
deleted file mode 100644
index f79dcd84634..00000000000
--- a/changelogs/unreleased/29929-jira-doc.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Fix link to Jira service documentation
-merge_request:
-author:
diff --git a/changelogs/unreleased/29930-fix-profile-cover-button-a11y.yml b/changelogs/unreleased/29930-fix-profile-cover-button-a11y.yml
deleted file mode 100644
index 754d471c7d7..00000000000
--- a/changelogs/unreleased/29930-fix-profile-cover-button-a11y.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Add tooltip and accessibility for profile cover buttons
-merge_request: 10182
-author:
diff --git a/changelogs/unreleased/29950-vue-pagination-icons.yml b/changelogs/unreleased/29950-vue-pagination-icons.yml
deleted file mode 100644
index e03092b8dba..00000000000
--- a/changelogs/unreleased/29950-vue-pagination-icons.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: consistent icons in vue and kaminari pagers
-merge_request:
-author:
diff --git a/changelogs/unreleased/30008-textarea-focus.yml b/changelogs/unreleased/30008-textarea-focus.yml
deleted file mode 100644
index 91837bbf96e..00000000000
--- a/changelogs/unreleased/30008-textarea-focus.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: refocus textarea after attaching a file
-merge_request:
-author:
diff --git a/changelogs/unreleased/30021-api-deploy_keys-can_push-is-not-honoured.yml b/changelogs/unreleased/30021-api-deploy_keys-can_push-is-not-honoured.yml
deleted file mode 100644
index 7584995a11f..00000000000
--- a/changelogs/unreleased/30021-api-deploy_keys-can_push-is-not-honoured.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Enable creation of deploy keys with write access via the API
-merge_request:
-author:
diff --git a/changelogs/unreleased/30056-rename-milestones-empty.yml b/changelogs/unreleased/30056-rename-milestones-empty.yml
deleted file mode 100644
index 85db342b6df..00000000000
--- a/changelogs/unreleased/30056-rename-milestones-empty.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Removed Milestone#is_empty?
-merge_request: 10523
-author: Jacopo Beschi @jacopo-beschi
diff --git a/changelogs/unreleased/30112-fix-pipelines-sub-nav-highlight.yml b/changelogs/unreleased/30112-fix-pipelines-sub-nav-highlight.yml
deleted file mode 100644
index deca629be83..00000000000
--- a/changelogs/unreleased/30112-fix-pipelines-sub-nav-highlight.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Fix sub-nav highlighting for `Environments` and `Jobs` pages
-merge_request: 10254
-author:
diff --git a/changelogs/unreleased/30125-markdown-security.yml b/changelogs/unreleased/30125-markdown-security.yml
deleted file mode 100644
index b766caf7d08..00000000000
--- a/changelogs/unreleased/30125-markdown-security.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Remove the class attribute from the whitelist for HTML generated from Markdown.
-merge_request:
-author:
diff --git a/changelogs/unreleased/30195-document-search-param-on-api.yml b/changelogs/unreleased/30195-document-search-param-on-api.yml
deleted file mode 100644
index f19f6ab699e..00000000000
--- a/changelogs/unreleased/30195-document-search-param-on-api.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Add search optional param and docs for V4
-merge_request:
-author:
diff --git a/changelogs/unreleased/30291-reopen-mr.yml b/changelogs/unreleased/30291-reopen-mr.yml
deleted file mode 100644
index 4ae3e90eeba..00000000000
--- a/changelogs/unreleased/30291-reopen-mr.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Include reopened MRs when searching for opened ones
-merge_request: 10407
-author:
diff --git a/changelogs/unreleased/30305-oauth-token-push-code.yml b/changelogs/unreleased/30305-oauth-token-push-code.yml
new file mode 100644
index 00000000000..aadfb5ca419
--- /dev/null
+++ b/changelogs/unreleased/30305-oauth-token-push-code.yml
@@ -0,0 +1,4 @@
+---
+title: Allow OAuth clients to push code
+merge_request: 10677
+author:
diff --git a/changelogs/unreleased/30306-transaction-while-moving-issues-to-ghost-user.yml b/changelogs/unreleased/30306-transaction-while-moving-issues-to-ghost-user.yml
new file mode 100644
index 00000000000..5fc57e44be6
--- /dev/null
+++ b/changelogs/unreleased/30306-transaction-while-moving-issues-to-ghost-user.yml
@@ -0,0 +1,4 @@
+---
+title: Add a transaction around move_issues_to_ghost_user
+merge_request: 10465
+author:
diff --git a/changelogs/unreleased/30400-fix-blob-highlighting-in-search.yml b/changelogs/unreleased/30400-fix-blob-highlighting-in-search.yml
deleted file mode 100644
index 942258450c0..00000000000
--- a/changelogs/unreleased/30400-fix-blob-highlighting-in-search.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Fix blob highlighting in search
-merge_request: 10420
-author:
diff --git a/changelogs/unreleased/30457-expire-note-destroy.yml b/changelogs/unreleased/30457-expire-note-destroy.yml
deleted file mode 100644
index f5c89da68a9..00000000000
--- a/changelogs/unreleased/30457-expire-note-destroy.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Fix issue's note cache expiration after delete
-merge_request:
-author: mhasbini
diff --git a/changelogs/unreleased/30493-env-deploy-tooltip.yml b/changelogs/unreleased/30493-env-deploy-tooltip.yml
deleted file mode 100644
index 8fadaaa7bd2..00000000000
--- a/changelogs/unreleased/30493-env-deploy-tooltip.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Fixes HTML structure that was preventing the tooltip to disappear when hovering
- out of the button.
-merge_request:
-author:
diff --git a/changelogs/unreleased/30587-pipeline-icon-z.yml b/changelogs/unreleased/30587-pipeline-icon-z.yml
deleted file mode 100644
index 548d16ce142..00000000000
--- a/changelogs/unreleased/30587-pipeline-icon-z.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: fix Status icons overlapping sidebar on mobile
-merge_request:
-author:
diff --git a/changelogs/unreleased/30588-fix-javascript-sourcemaps-w-chrome-breakpoints.yml b/changelogs/unreleased/30588-fix-javascript-sourcemaps-w-chrome-breakpoints.yml
deleted file mode 100644
index 9cff3c2776f..00000000000
--- a/changelogs/unreleased/30588-fix-javascript-sourcemaps-w-chrome-breakpoints.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Upgrade webpack to v2.3.3 and webpack-dev-server to v2.4.2
-merge_request: 10552
-author:
diff --git a/changelogs/unreleased/30672-versioned-markdown-cache.yml b/changelogs/unreleased/30672-versioned-markdown-cache.yml
new file mode 100644
index 00000000000..d8f977b01de
--- /dev/null
+++ b/changelogs/unreleased/30672-versioned-markdown-cache.yml
@@ -0,0 +1,4 @@
+---
+title: Replace rake cache:clear:db with an automatic mechanism
+merge_request: 10597
+author:
diff --git a/changelogs/unreleased/30779-show-mr-subnav-issue-tracker.yml b/changelogs/unreleased/30779-show-mr-subnav-issue-tracker.yml
deleted file mode 100644
index 59f8942911c..00000000000
--- a/changelogs/unreleased/30779-show-mr-subnav-issue-tracker.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Show sub-nav under Merge Requests when issue tracker is non-default.
-merge_request: 10658
-author:
diff --git a/changelogs/unreleased/31193-ff-copy.yml b/changelogs/unreleased/31193-ff-copy.yml
new file mode 100644
index 00000000000..4d44d83d458
--- /dev/null
+++ b/changelogs/unreleased/31193-ff-copy.yml
@@ -0,0 +1,4 @@
+---
+title: fix inline diff copy in firefox
+merge_request:
+author:
diff --git a/changelogs/unreleased/4195-add-sorting-to-project-milestones.yml b/changelogs/unreleased/4195-add-sorting-to-project-milestones.yml
deleted file mode 100644
index d4104dfa772..00000000000
--- a/changelogs/unreleased/4195-add-sorting-to-project-milestones.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Add dropdown sort to project milestones
-merge_request:
-author: George Andrinopoulos
diff --git a/changelogs/unreleased/8998_skip_pending_commits_if_not_head.yml b/changelogs/unreleased/8998_skip_pending_commits_if_not_head.yml
deleted file mode 100644
index 9852cd6e4ff..00000000000
--- a/changelogs/unreleased/8998_skip_pending_commits_if_not_head.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Cancel pending pipelines if commits not HEAD
-merge_request: 9362
-author: Rydkin Maxim
diff --git a/changelogs/unreleased/adam-finish-5993-closed-issuable.yml b/changelogs/unreleased/adam-finish-5993-closed-issuable.yml
deleted file mode 100644
index b324566313f..00000000000
--- a/changelogs/unreleased/adam-finish-5993-closed-issuable.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Add indication for closed or merged issuables in GFM
-merge_request: 9462
-author: Adam Buckland
diff --git a/changelogs/unreleased/adam-prevent-two-issue-trackers.yml b/changelogs/unreleased/adam-prevent-two-issue-trackers.yml
deleted file mode 100644
index 307b7ec7359..00000000000
--- a/changelogs/unreleased/adam-prevent-two-issue-trackers.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Prevent more than one issue tracker to be active for the same project
-merge_request:
-author: luisdgs19
diff --git a/changelogs/unreleased/add-aria-to-icon.yml b/changelogs/unreleased/add-aria-to-icon.yml
new file mode 100644
index 00000000000..fd6a25784c6
--- /dev/null
+++ b/changelogs/unreleased/add-aria-to-icon.yml
@@ -0,0 +1,4 @@
+---
+title: Fixes an issue preventing screen readers from reading some icons
+merge_request:
+author:
diff --git a/changelogs/unreleased/add-blob-copy-button.yml b/changelogs/unreleased/add-blob-copy-button.yml
deleted file mode 100644
index 946723e523b..00000000000
--- a/changelogs/unreleased/add-blob-copy-button.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Add copy button to blob header and use icon for Raw button
-merge_request:
-author:
diff --git a/changelogs/unreleased/add-dimension-etag-caching-metrics.yml b/changelogs/unreleased/add-dimension-etag-caching-metrics.yml
deleted file mode 100644
index f2a13eb7c61..00000000000
--- a/changelogs/unreleased/add-dimension-etag-caching-metrics.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Include endpoint in metrics for ETag caching middleware
-merge_request: 10495
-author:
diff --git a/changelogs/unreleased/add-email-receiver-metrics.yml b/changelogs/unreleased/add-email-receiver-metrics.yml
deleted file mode 100644
index 53155651080..00000000000
--- a/changelogs/unreleased/add-email-receiver-metrics.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Add metrics events for incoming emails
-merge_request:
-author:
diff --git a/changelogs/unreleased/add-error-empty-states.yml b/changelogs/unreleased/add-error-empty-states.yml
deleted file mode 100644
index ec6c7b6dce9..00000000000
--- a/changelogs/unreleased/add-error-empty-states.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Introduced error/empty states for the environments performance metrics
-merge_request: 10271
-author:
diff --git a/changelogs/unreleased/add-field-for-group-name.yml b/changelogs/unreleased/add-field-for-group-name.yml
deleted file mode 100644
index 0fe511a4fa1..00000000000
--- a/changelogs/unreleased/add-field-for-group-name.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Add a name field to the group form
-merge_request: 9891
-author: Douglas Lovell
diff --git a/changelogs/unreleased/add-issue-modal-loading-indicator.yml b/changelogs/unreleased/add-issue-modal-loading-indicator.yml
deleted file mode 100644
index 5398399c018..00000000000
--- a/changelogs/unreleased/add-issue-modal-loading-indicator.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Shows loading icon in issue boards modal when changing filters
-merge_request:
-author:
diff --git a/changelogs/unreleased/add-labels-to-issue-hook.yml b/changelogs/unreleased/add-labels-to-issue-hook.yml
deleted file mode 100644
index 967430ee09f..00000000000
--- a/changelogs/unreleased/add-labels-to-issue-hook.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Added labels array to the issue web hook returned object
-merge_request: 9972
-author:
diff --git a/changelogs/unreleased/add-test-backoff-util.yml b/changelogs/unreleased/add-test-backoff-util.yml
deleted file mode 100644
index f3f3b99caec..00000000000
--- a/changelogs/unreleased/add-test-backoff-util.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Added tests for the w.gl.utils.backOff promise
-merge_request:
-author:
diff --git a/changelogs/unreleased/add-todos-shortcut.yml b/changelogs/unreleased/add-todos-shortcut.yml
deleted file mode 100644
index 41d42775937..00000000000
--- a/changelogs/unreleased/add-todos-shortcut.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Add `g t` global shortcut to go to todos
-merge_request:
-author:
diff --git a/changelogs/unreleased/add-ui-for-trigger-schedule.yml b/changelogs/unreleased/add-ui-for-trigger-schedule.yml
deleted file mode 100644
index 9ca78983605..00000000000
--- a/changelogs/unreleased/add-ui-for-trigger-schedule.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Add UI for Trigger Schedule
-merge_request: 10533
-author: dosuken123
diff --git a/changelogs/unreleased/add_index_on_ci_builds_updated_at.yml b/changelogs/unreleased/add_index_on_ci_builds_updated_at.yml
new file mode 100644
index 00000000000..ede9b946a70
--- /dev/null
+++ b/changelogs/unreleased/add_index_on_ci_builds_updated_at.yml
@@ -0,0 +1,4 @@
+---
+title: Add index on ci_builds.updated_at
+merge_request: 10870
+author: blackst0ne
diff --git a/changelogs/unreleased/add_quick_submit_for_snippets_form.yml b/changelogs/unreleased/add_quick_submit_for_snippets_form.yml
deleted file mode 100644
index 088f1335796..00000000000
--- a/changelogs/unreleased/add_quick_submit_for_snippets_form.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Add quick submit for snippet forms
-merge_request: 9911
-author: blackst0ne
diff --git a/changelogs/unreleased/add_remove_concurrent_index_to_database_helper.yml b/changelogs/unreleased/add_remove_concurrent_index_to_database_helper.yml
deleted file mode 100644
index c7b06e45607..00000000000
--- a/changelogs/unreleased/add_remove_concurrent_index_to_database_helper.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Add remove_concurrent_index to database helper
-merge_request: 10441
-author: blackst0ne
diff --git a/changelogs/unreleased/allow-resolving-conflicts-in-utf-8.yml b/changelogs/unreleased/allow-resolving-conflicts-in-utf-8.yml
deleted file mode 100644
index c3c877423ff..00000000000
--- a/changelogs/unreleased/allow-resolving-conflicts-in-utf-8.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Fix conflict resolution when files contain valid UTF-8 characters
-merge_request:
-author:
diff --git a/changelogs/unreleased/award-emoji-button-smiley-animation.yml b/changelogs/unreleased/award-emoji-button-smiley-animation.yml
deleted file mode 100644
index 31903aeb040..00000000000
--- a/changelogs/unreleased/award-emoji-button-smiley-animation.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Added award emoji animation and improved active state
-merge_request:
-author:
diff --git a/changelogs/unreleased/bug-api_milestone_merge_requests_scope.yml b/changelogs/unreleased/bug-api_milestone_merge_requests_scope.yml
deleted file mode 100644
index a1e1c29165e..00000000000
--- a/changelogs/unreleased/bug-api_milestone_merge_requests_scope.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Fixes milestone/merge_requests endpoint to actually scope the result
-merge_request:
-author: Joren De Groof
diff --git a/changelogs/unreleased/bugfix-systemhook.yml b/changelogs/unreleased/bugfix-systemhook.yml
deleted file mode 100644
index 4c4d0dcc7a2..00000000000
--- a/changelogs/unreleased/bugfix-systemhook.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Fix bug when system hook for deploy key
-merge_request: 9796
-author: billy.lb
diff --git a/changelogs/unreleased/button-capitalization.yml b/changelogs/unreleased/button-capitalization.yml
deleted file mode 100644
index 13b3beea40c..00000000000
--- a/changelogs/unreleased/button-capitalization.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Changed capitalisation of buttons across GitLab
-merge_request: 10418
-author:
diff --git a/changelogs/unreleased/calendar-tooltips.yml b/changelogs/unreleased/calendar-tooltips.yml
deleted file mode 100644
index d1517bbab58..00000000000
--- a/changelogs/unreleased/calendar-tooltips.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Add tooltip to user's calendar activities
-merge_request: 10123
-author: Alex Argunov
diff --git a/changelogs/unreleased/chore-23493-remaining-time-tooltip.yml b/changelogs/unreleased/chore-23493-remaining-time-tooltip.yml
deleted file mode 100644
index dc315ca2367..00000000000
--- a/changelogs/unreleased/chore-23493-remaining-time-tooltip.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Added remaining_time method to milestoneish, specs and updated the milestone_helper
- milestone_remaining_days method to correctly return the correct remaining time.
-merge_request:
-author: Michael Robinson
diff --git a/changelogs/unreleased/clean_carrierwave_tempfiles.yml b/changelogs/unreleased/clean_carrierwave_tempfiles.yml
deleted file mode 100644
index 53fa69700ff..00000000000
--- a/changelogs/unreleased/clean_carrierwave_tempfiles.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Periodically clean up temporary upload files to recover storage space
-merge_request: 9466
-author: blackst0ne
diff --git a/changelogs/unreleased/cleaner-additional-award-emoji-button.yml b/changelogs/unreleased/cleaner-additional-award-emoji-button.yml
deleted file mode 100644
index 84685f4bd45..00000000000
--- a/changelogs/unreleased/cleaner-additional-award-emoji-button.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Removed unnecessary 'add' text in additional award emoji button
-merge_request:
-author:
diff --git a/changelogs/unreleased/create-collapsed-todo-button.yml b/changelogs/unreleased/create-collapsed-todo-button.yml
deleted file mode 100644
index 6da6c070bf7..00000000000
--- a/changelogs/unreleased/create-collapsed-todo-button.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: adds todo functionality to closed issuable sidebar and changes todo bell icon
- to check-square
-merge_request:
-author:
diff --git a/changelogs/unreleased/diff-discussion-buttons-spacing.yml b/changelogs/unreleased/diff-discussion-buttons-spacing.yml
new file mode 100644
index 00000000000..dc76973e55b
--- /dev/null
+++ b/changelogs/unreleased/diff-discussion-buttons-spacing.yml
@@ -0,0 +1,4 @@
+---
+title: Fixed spacing of discussion submit buttons
+merge_request:
+author:
diff --git a/changelogs/unreleased/dm-copy-code-as-gfm.yml b/changelogs/unreleased/dm-copy-code-as-gfm.yml
deleted file mode 100644
index 15ae2da44a3..00000000000
--- a/changelogs/unreleased/dm-copy-code-as-gfm.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Copy code as GFM from diffs, blobs and GFM code blocks
-merge_request:
-author:
diff --git a/changelogs/unreleased/dm-copy-diff-file-title-as-gfm.yml b/changelogs/unreleased/dm-copy-diff-file-title-as-gfm.yml
deleted file mode 100644
index 506883bc17d..00000000000
--- a/changelogs/unreleased/dm-copy-diff-file-title-as-gfm.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: After copying a diff file or blob path, pasting it into a comment field will format it as Markdown.
-merge_request: 9876
-author:
diff --git a/changelogs/unreleased/dm-fix-individual-notes-reply-attributes.yml b/changelogs/unreleased/dm-fix-individual-notes-reply-attributes.yml
new file mode 100644
index 00000000000..e8c05092ea8
--- /dev/null
+++ b/changelogs/unreleased/dm-fix-individual-notes-reply-attributes.yml
@@ -0,0 +1,5 @@
+---
+title: Ensure replying to an individual note by email creates a note with its own
+ discussion ID
+merge_request:
+author:
diff --git a/changelogs/unreleased/dm-fix-position-tracer-for-hidden-lines.yml b/changelogs/unreleased/dm-fix-position-tracer-for-hidden-lines.yml
new file mode 100644
index 00000000000..d9ba26a0657
--- /dev/null
+++ b/changelogs/unreleased/dm-fix-position-tracer-for-hidden-lines.yml
@@ -0,0 +1,5 @@
+---
+title: Fix commenting on an existing discussion on an unchanged line that is no longer
+ in the diff
+merge_request:
+author:
diff --git a/changelogs/unreleased/dz-cleanup-add-users.yml b/changelogs/unreleased/dz-cleanup-add-users.yml
new file mode 100644
index 00000000000..ba1e2d609f9
--- /dev/null
+++ b/changelogs/unreleased/dz-cleanup-add-users.yml
@@ -0,0 +1,4 @@
+---
+title: Refactor add_users method for project and group
+merge_request: 10850
+author:
diff --git a/changelogs/unreleased/dz-fix-group-move.yml b/changelogs/unreleased/dz-fix-group-move.yml
deleted file mode 100644
index 51fbe04fdc2..00000000000
--- a/changelogs/unreleased/dz-fix-group-move.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Fix subgroup repository disappearance if group was moved
-merge_request: 10414
-author:
diff --git a/changelogs/unreleased/dz-fix-project-view.yml b/changelogs/unreleased/dz-fix-project-view.yml
deleted file mode 100644
index 647a1c96bd9..00000000000
--- a/changelogs/unreleased/dz-fix-project-view.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Change project view default for existing users and anonymous visitors to files+readme
-merge_request: 10498
-author:
diff --git a/changelogs/unreleased/dz-hide-zero-counter.yml b/changelogs/unreleased/dz-hide-zero-counter.yml
deleted file mode 100644
index 45f35044c48..00000000000
--- a/changelogs/unreleased/dz-hide-zero-counter.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Hide header counters for issue/mr/todos if zero
-merge_request: 10506
-author:
diff --git a/changelogs/unreleased/dz-refactor-admin-group-members.yml b/changelogs/unreleased/dz-refactor-admin-group-members.yml
new file mode 100644
index 00000000000..993a6cac0df
--- /dev/null
+++ b/changelogs/unreleased/dz-refactor-admin-group-members.yml
@@ -0,0 +1,4 @@
+---
+title: Refactor Admin::GroupsController#members_update method and add some specs
+merge_request: 10735
+author:
diff --git a/changelogs/unreleased/emoji-menu-duplicated-search-icon.yml b/changelogs/unreleased/emoji-menu-duplicated-search-icon.yml
deleted file mode 100644
index 4ab6ba5399c..00000000000
--- a/changelogs/unreleased/emoji-menu-duplicated-search-icon.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Removed the duplicated search icon in the award emoji menu
-merge_request:
-author:
diff --git a/changelogs/unreleased/enable-snippets-by-default.yml b/changelogs/unreleased/enable-snippets-by-default.yml
deleted file mode 100644
index 04fa3f7bdae..00000000000
--- a/changelogs/unreleased/enable-snippets-by-default.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Enable snippets for new projects by default
-merge_request:
-author:
diff --git a/changelogs/unreleased/enforce-Ansi2html-output-encoding.yml b/changelogs/unreleased/enforce-Ansi2html-output-encoding.yml
deleted file mode 100644
index b1200548518..00000000000
--- a/changelogs/unreleased/enforce-Ansi2html-output-encoding.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Fix trace cannot be written due to encoding
-merge_request: 10758
-author:
diff --git a/changelogs/unreleased/environment-performance-improvements.yml b/changelogs/unreleased/environment-performance-improvements.yml
deleted file mode 100644
index 43e8f0afcee..00000000000
--- a/changelogs/unreleased/environment-performance-improvements.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Improved UX for the environments metrics view
-merge_request: 9946
-author:
diff --git a/changelogs/unreleased/es6-class-issue.yml b/changelogs/unreleased/es6-class-issue.yml
deleted file mode 100644
index 9d1c3ac7421..00000000000
--- a/changelogs/unreleased/es6-class-issue.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Convert Issue into ES6 class
-merge_request: 9636
-author: winniehell
diff --git a/changelogs/unreleased/feature-custom-lfs.yml b/changelogs/unreleased/feature-custom-lfs.yml
deleted file mode 100644
index ec968386a6f..00000000000
--- a/changelogs/unreleased/feature-custom-lfs.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Do not show LFS object when LFS is disabled
-merge_request: 9779
-author: Christopher Bartz
diff --git a/changelogs/unreleased/feature-enforce-2fa-per-group.yml b/changelogs/unreleased/feature-enforce-2fa-per-group.yml
deleted file mode 100644
index 6dd99e4245f..00000000000
--- a/changelogs/unreleased/feature-enforce-2fa-per-group.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Support 2FA requirement per-group
-merge_request: 8763
-author: Markus Koller
diff --git a/changelogs/unreleased/feature-gh-rake-task.yml b/changelogs/unreleased/feature-gh-rake-task.yml
deleted file mode 100644
index 5b1d380690c..00000000000
--- a/changelogs/unreleased/feature-gh-rake-task.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Add rake task to import GitHub projects from the command line
-merge_request:
-author:
diff --git a/changelogs/unreleased/feature-multi-level-container-registry-images.yml b/changelogs/unreleased/feature-multi-level-container-registry-images.yml
deleted file mode 100644
index 6d39a6c17c0..00000000000
--- a/changelogs/unreleased/feature-multi-level-container-registry-images.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Add support for multi-level container image repository names
-merge_request: 10109
-author: André Guede
diff --git a/changelogs/unreleased/feature-tokens-rake-task.yml b/changelogs/unreleased/feature-tokens-rake-task.yml
deleted file mode 100644
index 6c3845757db..00000000000
--- a/changelogs/unreleased/feature-tokens-rake-task.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: New rake task to reset all email and private tokens
-merge_request:
-author:
diff --git a/changelogs/unreleased/feature-use-gitaly-for-commit-is-ancestor.yml b/changelogs/unreleased/feature-use-gitaly-for-commit-is-ancestor.yml
deleted file mode 100644
index 733e3643ce5..00000000000
--- a/changelogs/unreleased/feature-use-gitaly-for-commit-is-ancestor.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Use Gitaly for Repository#is_ancestor
-merge_request: 9864
-author:
diff --git a/changelogs/unreleased/feature-use-gitaly-for-commit-show.yml b/changelogs/unreleased/feature-use-gitaly-for-commit-show.yml
deleted file mode 100644
index 4b668d994a1..00000000000
--- a/changelogs/unreleased/feature-use-gitaly-for-commit-show.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Use Gitaly for CommitController#show
-merge_request: 9629
-author:
diff --git a/changelogs/unreleased/file-import-export-path-disclosure.yml b/changelogs/unreleased/file-import-export-path-disclosure.yml
deleted file mode 100644
index 1a297d07187..00000000000
--- a/changelogs/unreleased/file-import-export-path-disclosure.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Fix path disclosure in project import/export
-merge_request:
-author:
-
diff --git a/changelogs/unreleased/fix-29093.yml b/changelogs/unreleased/fix-29093.yml
deleted file mode 100644
index 791129afe93..00000000000
--- a/changelogs/unreleased/fix-29093.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Fix 'Object not found - no match for id (sha)' when importing GitHub Pull Requests
-merge_request:
-author:
diff --git a/changelogs/unreleased/fix-29125.yml b/changelogs/unreleased/fix-29125.yml
deleted file mode 100644
index 00b5e8c0a2a..00000000000
--- a/changelogs/unreleased/fix-29125.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Display custom hook error messages when automatic merge is enabled
-merge_request:
-author:
diff --git a/changelogs/unreleased/fix-admin-projects.yml b/changelogs/unreleased/fix-admin-projects.yml
deleted file mode 100644
index d192f07004c..00000000000
--- a/changelogs/unreleased/fix-admin-projects.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Fix layout of projects page on admin area
-merge_request:
-author:
diff --git a/changelogs/unreleased/fix-gb-dashboard-commit-status-caching.yml b/changelogs/unreleased/fix-gb-dashboard-commit-status-caching.yml
deleted file mode 100644
index 4db684c40b2..00000000000
--- a/changelogs/unreleased/fix-gb-dashboard-commit-status-caching.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Resolve project pipeline status caching problem on dashboard
-merge_request: 9895
-author:
diff --git a/changelogs/unreleased/fix-gb-fix-blocked-pipeline-duration.yml b/changelogs/unreleased/fix-gb-fix-blocked-pipeline-duration.yml
new file mode 100644
index 00000000000..5c87b1fdbd5
--- /dev/null
+++ b/changelogs/unreleased/fix-gb-fix-blocked-pipeline-duration.yml
@@ -0,0 +1,4 @@
+---
+title: Fix missing duration for blocked pipelines
+merge_request: 10856
+author:
diff --git a/changelogs/unreleased/fix-gb-fix-incorrect-commit-status-badge-text.yml b/changelogs/unreleased/fix-gb-fix-incorrect-commit-status-badge-text.yml
new file mode 100644
index 00000000000..abe047af06f
--- /dev/null
+++ b/changelogs/unreleased/fix-gb-fix-incorrect-commit-status-badge-text.yml
@@ -0,0 +1,4 @@
+---
+title: Fix lastest commit status text on main project page
+merge_request: 10863
+author:
diff --git a/changelogs/unreleased/fix-gb-remove-deprecated-pipeline-processing-code.yml b/changelogs/unreleased/fix-gb-remove-deprecated-pipeline-processing-code.yml
deleted file mode 100644
index 32862b527fd..00000000000
--- a/changelogs/unreleased/fix-gb-remove-deprecated-pipeline-processing-code.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Drop support for correctly processing legacy pipelines
-merge_request: 10266
-author:
diff --git a/changelogs/unreleased/fix-gh-import-status-check.yml b/changelogs/unreleased/fix-gh-import-status-check.yml
deleted file mode 100644
index d04bc2954a0..00000000000
--- a/changelogs/unreleased/fix-gh-import-status-check.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Periodically mark projects that are stuck in importing as failed
-merge_request:
-author:
diff --git a/changelogs/unreleased/fix-github-importer-slowness.yml b/changelogs/unreleased/fix-github-importer-slowness.yml
deleted file mode 100644
index c1f8d0e02d5..00000000000
--- a/changelogs/unreleased/fix-github-importer-slowness.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Improve performance of GitHub importer for large repositories.
-merge_request: 10273
-author:
diff --git a/changelogs/unreleased/fix-groups-long-url.yml b/changelogs/unreleased/fix-groups-long-url.yml
deleted file mode 100644
index f0f1296ad40..00000000000
--- a/changelogs/unreleased/fix-groups-long-url.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Skip groups validation on the client
-merge_request:
-author:
diff --git a/changelogs/unreleased/fix-import-fork.yml b/changelogs/unreleased/fix-import-fork.yml
deleted file mode 100644
index ff8dd131995..00000000000
--- a/changelogs/unreleased/fix-import-fork.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Fix Import/Export MR diffs not showing and missing forked MRs
-merge_request:
-author:
diff --git a/changelogs/unreleased/fix-import-namespace.yml b/changelogs/unreleased/fix-import-namespace.yml
deleted file mode 100644
index 9a2fa5e425f..00000000000
--- a/changelogs/unreleased/fix-import-namespace.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Create subgroups if they don't exist while importing projects
-merge_request:
-author:
diff --git a/changelogs/unreleased/fix-issue-23237.yml b/changelogs/unreleased/fix-issue-23237.yml
deleted file mode 100644
index ed0ffc0684d..00000000000
--- a/changelogs/unreleased/fix-issue-23237.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: "Fixes an issue in the new merge request form, where a tag would be selected instead of a branch when they have the same names"
-merge_request: 9535
-author: Weiqing Chu
diff --git a/changelogs/unreleased/fix-milestone-name-on-show.yml b/changelogs/unreleased/fix-milestone-name-on-show.yml
deleted file mode 100644
index bf17a758c80..00000000000
--- a/changelogs/unreleased/fix-milestone-name-on-show.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Fix Milestone name on show page
-merge_request:
-author: Raveesh
diff --git a/changelogs/unreleased/fix-missing-capitalisation-buttons.yml b/changelogs/unreleased/fix-missing-capitalisation-buttons.yml
deleted file mode 100644
index b2c40483475..00000000000
--- a/changelogs/unreleased/fix-missing-capitalisation-buttons.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Fix missing capitalisation on views
-merge_request:
-author:
diff --git a/changelogs/unreleased/fix-orphan-notification-settings.yml b/changelogs/unreleased/fix-orphan-notification-settings.yml
deleted file mode 100644
index 7595b033336..00000000000
--- a/changelogs/unreleased/fix-orphan-notification-settings.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Removed orphaned notification settings without a namespace
-merge_request:
-author:
diff --git a/changelogs/unreleased/fix-preloading-merge_request_diff.yml b/changelogs/unreleased/fix-preloading-merge_request_diff.yml
deleted file mode 100644
index d38b6b0a707..00000000000
--- a/changelogs/unreleased/fix-preloading-merge_request_diff.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Fix bad query for PostgreSQL showing merge requests list
-merge_request: 10666
-author:
diff --git a/changelogs/unreleased/fix-project-visibility-setting.yml b/changelogs/unreleased/fix-project-visibility-setting.yml
deleted file mode 100644
index 0fc219ccf52..00000000000
--- a/changelogs/unreleased/fix-project-visibility-setting.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Fix restricted project visibility setting available to users
-merge_request:
-author:
diff --git a/changelogs/unreleased/fix-trace-encoding.yml b/changelogs/unreleased/fix-trace-encoding.yml
deleted file mode 100644
index 152610c43f5..00000000000
--- a/changelogs/unreleased/fix-trace-encoding.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Fix another case where trace does not have proper encoding set
-merge_request: 10728
-author:
diff --git a/changelogs/unreleased/fix-trace-seeking.yml b/changelogs/unreleased/fix-trace-seeking.yml
deleted file mode 100644
index b753df4bb43..00000000000
--- a/changelogs/unreleased/fix-trace-seeking.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Fix invalid encoding when showing some traces
-merge_request: 10681
-author:
diff --git a/changelogs/unreleased/fix-user-profile-tabs-showing-raw-json-instead.yml b/changelogs/unreleased/fix-user-profile-tabs-showing-raw-json-instead.yml
new file mode 100644
index 00000000000..410172864e3
--- /dev/null
+++ b/changelogs/unreleased/fix-user-profile-tabs-showing-raw-json-instead.yml
@@ -0,0 +1,5 @@
+---
+title: Prevent user profile tabs to display raw json when going back and forward in
+ browser history
+merge_request:
+author:
diff --git a/changelogs/unreleased/fix_admin_monitoring_background.yml b/changelogs/unreleased/fix_admin_monitoring_background.yml
deleted file mode 100644
index 3a9a1c88672..00000000000
--- a/changelogs/unreleased/fix_admin_monitoring_background.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Handle parsing OpenBSD ps output properly to display sidekiq infos on admin->monitoring->background
-merge_request: 10303
-author: Sebastian Reitenbach
diff --git a/changelogs/unreleased/fix_link_in_readme.yml b/changelogs/unreleased/fix_link_in_readme.yml
new file mode 100644
index 00000000000..be5ceac8656
--- /dev/null
+++ b/changelogs/unreleased/fix_link_in_readme.yml
@@ -0,0 +1,4 @@
+---
+title: Fix dead link to GDK on the README page
+merge_request:
+author: Dino Maric
diff --git a/changelogs/unreleased/fix_rake_gitlab_check_sidekiq.yml b/changelogs/unreleased/fix_rake_gitlab_check_sidekiq.yml
deleted file mode 100644
index 4752ed34ae6..00000000000
--- a/changelogs/unreleased/fix_rake_gitlab_check_sidekiq.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Force unlimited terminal size when checking processes via call to ps
-merge_request: 10246
-author: Sebastian Reitenbach
diff --git a/changelogs/unreleased/fix_updated_field_in_issues-atom.yml b/changelogs/unreleased/fix_updated_field_in_issues-atom.yml
deleted file mode 100644
index 414facdf779..00000000000
--- a/changelogs/unreleased/fix_updated_field_in_issues-atom.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Fix xml.updated field in rss/atom feeds
-merge_request: 9889
-author: blackst0ne
diff --git a/changelogs/unreleased/fix_visibility_level.yml b/changelogs/unreleased/fix_visibility_level.yml
deleted file mode 100644
index 4cf649124ca..00000000000
--- a/changelogs/unreleased/fix_visibility_level.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Fix visibility level on new project page
-merge_request: 9885
-author: blackst0ne
diff --git a/changelogs/unreleased/fix_wiki_commit_message.yml b/changelogs/unreleased/fix_wiki_commit_message.yml
deleted file mode 100644
index e5cd398b4b5..00000000000
--- a/changelogs/unreleased/fix_wiki_commit_message.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Fix wiki commit message
-merge_request: 10464
-author: blackst0ne
diff --git a/changelogs/unreleased/fl-remove-ujs-pipelines.yml b/changelogs/unreleased/fl-remove-ujs-pipelines.yml
deleted file mode 100644
index f353400753a..00000000000
--- a/changelogs/unreleased/fl-remove-ujs-pipelines.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: 'Removes UJS from pipelines tables'
-merge_request: 9929
-author:
diff --git a/changelogs/unreleased/form-focus-previous-incorrect-form.yml b/changelogs/unreleased/form-focus-previous-incorrect-form.yml
new file mode 100644
index 00000000000..efabb78de6b
--- /dev/null
+++ b/changelogs/unreleased/form-focus-previous-incorrect-form.yml
@@ -0,0 +1,4 @@
+---
+title: Fixued preview shortcut focusing wrong preview tab
+merge_request:
+author:
diff --git a/changelogs/unreleased/gitaly-refs.yml b/changelogs/unreleased/gitaly-refs.yml
deleted file mode 100644
index 3d462cdf90f..00000000000
--- a/changelogs/unreleased/gitaly-refs.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Incorporate Gitaly client for refs service
-merge_request: 9291
-author:
diff --git a/changelogs/unreleased/group-gear-setting-dropdown-to-tab.yml b/changelogs/unreleased/group-gear-setting-dropdown-to-tab.yml
deleted file mode 100644
index aff1bdd957c..00000000000
--- a/changelogs/unreleased/group-gear-setting-dropdown-to-tab.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Moved the gear settings dropdown to a tab in the groups view
-merge_request:
-author:
diff --git a/changelogs/unreleased/group-milestone-date-fields-fix.yml b/changelogs/unreleased/group-milestone-date-fields-fix.yml
deleted file mode 100644
index 3cf3d3fa5ed..00000000000
--- a/changelogs/unreleased/group-milestone-date-fields-fix.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Fixed group milestone date dropdowns not opening
-merge_request:
-author:
diff --git a/changelogs/unreleased/handle-failure-when-deleting-tags.yml b/changelogs/unreleased/handle-failure-when-deleting-tags.yml
deleted file mode 100644
index 99b07c5fb5f..00000000000
--- a/changelogs/unreleased/handle-failure-when-deleting-tags.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Display error message when deleting tag in web UI fails
-merge_request: 9906
-author:
diff --git a/changelogs/unreleased/hook_retries.yml b/changelogs/unreleased/hook_retries.yml
deleted file mode 100644
index ee30399edbb..00000000000
--- a/changelogs/unreleased/hook_retries.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Add retry to system hook worker
-merge_request: 10801
-author:
diff --git a/changelogs/unreleased/introduce-polling-interval-multiplier.yml b/changelogs/unreleased/introduce-polling-interval-multiplier.yml
deleted file mode 100644
index 3ccae8e327f..00000000000
--- a/changelogs/unreleased/introduce-polling-interval-multiplier.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Introduce "polling_interval_multiplier" as application setting
-merge_request: 10280
-author:
diff --git a/changelogs/unreleased/issue-boards-cant-drag-fix.yml b/changelogs/unreleased/issue-boards-cant-drag-fix.yml
deleted file mode 100644
index ac92573abe8..00000000000
--- a/changelogs/unreleased/issue-boards-cant-drag-fix.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Fixed bug in issue boards which stopped cards being able to be dragged
-merge_request:
-author:
diff --git a/changelogs/unreleased/issue-boards-new-search-bar.yml b/changelogs/unreleased/issue-boards-new-search-bar.yml
deleted file mode 100644
index b02be70c470..00000000000
--- a/changelogs/unreleased/issue-boards-new-search-bar.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Added new filtered search bar to issue boards
-merge_request:
-author:
diff --git a/changelogs/unreleased/issue_27212.yml b/changelogs/unreleased/issue_27212.yml
deleted file mode 100644
index 7a7e04f7ca7..00000000000
--- a/changelogs/unreleased/issue_27212.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Add closed_at field to issues
-merge_request:
-author:
diff --git a/changelogs/unreleased/issue_29449.yml b/changelogs/unreleased/issue_29449.yml
deleted file mode 100644
index 3556f22b080..00000000000
--- a/changelogs/unreleased/issue_29449.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Remove whitespace in group links
-merge_request: 9947
-author: Xurxo Méndez Pérez
diff --git a/changelogs/unreleased/issue_91_ee_backport.yml b/changelogs/unreleased/issue_91_ee_backport.yml
deleted file mode 100644
index 17bc0e435f3..00000000000
--- a/changelogs/unreleased/issue_91_ee_backport.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Do not set closed_at to nil when issue is reopened
-merge_request:
-author:
diff --git a/changelogs/unreleased/issues-empty-state-not-centered.yml b/changelogs/unreleased/issues-empty-state-not-centered.yml
deleted file mode 100644
index 883125e28b1..00000000000
--- a/changelogs/unreleased/issues-empty-state-not-centered.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Centered issues empty state
-merge_request:
-author:
diff --git a/changelogs/unreleased/jej-group-name-disclosure.yml b/changelogs/unreleased/jej-group-name-disclosure.yml
deleted file mode 100644
index 9b8ab7082ef..00000000000
--- a/changelogs/unreleased/jej-group-name-disclosure.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Fixed private group name disclosure via new/update forms
-merge_request:
-author:
diff --git a/changelogs/unreleased/make-karma-fast-again.yml b/changelogs/unreleased/make-karma-fast-again.yml
deleted file mode 100644
index 9b95e06954a..00000000000
--- a/changelogs/unreleased/make-karma-fast-again.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Only add code coverage instrumentation when generating coverage report
-merge_request: 9987
-author:
diff --git a/changelogs/unreleased/make_user_mentions_case_insensitive.yml b/changelogs/unreleased/make_user_mentions_case_insensitive.yml
deleted file mode 100644
index ab114494802..00000000000
--- a/changelogs/unreleased/make_user_mentions_case_insensitive.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Make user mentions case-insensitive
-merge_request: 10285
-author: blackst0ne
diff --git a/changelogs/unreleased/menu-shortcut.yml b/changelogs/unreleased/menu-shortcut.yml
deleted file mode 100644
index 74803498f58..00000000000
--- a/changelogs/unreleased/menu-shortcut.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Add keyboard shortcuts to main menu
-merge_request:
-author:
diff --git a/changelogs/unreleased/metrics-button-misplaced.yml b/changelogs/unreleased/metrics-button-misplaced.yml
deleted file mode 100644
index 6c685ff32a5..00000000000
--- a/changelogs/unreleased/metrics-button-misplaced.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Moved the monitoring button inside the show view for the environments page
-merge_request:
-author:
diff --git a/changelogs/unreleased/microsoft-teams-integration.yml b/changelogs/unreleased/microsoft-teams-integration.yml
deleted file mode 100644
index c01902d3401..00000000000
--- a/changelogs/unreleased/microsoft-teams-integration.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Integrates Microsoft Teams webhooks with GitLab
-merge_request: 10412
-author:
diff --git a/changelogs/unreleased/mr-diffs-speed-up.yml b/changelogs/unreleased/mr-diffs-speed-up.yml
deleted file mode 100644
index ccc7a99d05e..00000000000
--- a/changelogs/unreleased/mr-diffs-speed-up.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Speed up initial rendering of MR diffs page
-merge_request:
-author:
diff --git a/changelogs/unreleased/mr-new-page-changing-url.yml b/changelogs/unreleased/mr-new-page-changing-url.yml
deleted file mode 100644
index 39de1eaa523..00000000000
--- a/changelogs/unreleased/mr-new-page-changing-url.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Fixed tabs on new merge request page causing incorrect URLs
-merge_request:
-author:
diff --git a/changelogs/unreleased/mr-widget-bug-fix.yml b/changelogs/unreleased/mr-widget-bug-fix.yml
deleted file mode 100644
index 9af29d3927e..00000000000
--- a/changelogs/unreleased/mr-widget-bug-fix.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Fix MR widget bug that merged a MR when Merge when pipeline succeeds was clicked
- via the dropdown
-merge_request: 10611
-author:
diff --git a/changelogs/unreleased/mrchrisw-22740-merge-api.yml b/changelogs/unreleased/mrchrisw-22740-merge-api.yml
new file mode 100644
index 00000000000..e75160aec70
--- /dev/null
+++ b/changelogs/unreleased/mrchrisw-22740-merge-api.yml
@@ -0,0 +1,4 @@
+---
+title: Fix updating merge_when_build_succeeds via merge API endpoint
+merge_request: 10873
+author:
diff --git a/changelogs/unreleased/namespace-race-condition.yml b/changelogs/unreleased/namespace-race-condition.yml
deleted file mode 100644
index 2a76b6c74e8..00000000000
--- a/changelogs/unreleased/namespace-race-condition.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Fix project creation failure due to race condition in namespace directory creation
-merge_request: 10268
-author: Robin Bobbitt
diff --git a/changelogs/unreleased/new-resolvable-discussion.yml b/changelogs/unreleased/new-resolvable-discussion.yml
deleted file mode 100644
index f4dc4ea3ede..00000000000
--- a/changelogs/unreleased/new-resolvable-discussion.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Add option to start a new resolvable discussion in an MR
-merge_request: 7527
-author:
diff --git a/changelogs/unreleased/open-redirect-continue-params.yml b/changelogs/unreleased/open-redirect-continue-params.yml
deleted file mode 100644
index def3bc7d929..00000000000
--- a/changelogs/unreleased/open-redirect-continue-params.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Fix for open redirect vulnerability using continue[to] in URL when requesting project import status.
-merge_request:
-author:
diff --git a/changelogs/unreleased/open-redirect-host-field.yml b/changelogs/unreleased/open-redirect-host-field.yml
deleted file mode 100644
index bed4b47cf04..00000000000
--- a/changelogs/unreleased/open-redirect-host-field.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Fix for open redirect vulnerabilities in todos, issues, and MR controllers.
-merge_request:
-author:
diff --git a/changelogs/unreleased/optimise-builds-view.yml b/changelogs/unreleased/optimise-builds-view.yml
deleted file mode 100644
index 1d715ab4f47..00000000000
--- a/changelogs/unreleased/optimise-builds-view.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Optimise builds endpoint
-merge_request:
-author:
diff --git a/changelogs/unreleased/option-to-be-notified-of-own-activity.yml b/changelogs/unreleased/option-to-be-notified-of-own-activity.yml
deleted file mode 100644
index 542287a09be..00000000000
--- a/changelogs/unreleased/option-to-be-notified-of-own-activity.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Add option to receive email notifications about your own activity
-merge_request: 10032
-author: Richard Macklin
diff --git a/changelogs/unreleased/pages-debug-log.yml b/changelogs/unreleased/pages-debug-log.yml
deleted file mode 100644
index 328c8e4615b..00000000000
--- a/changelogs/unreleased/pages-debug-log.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Log errors during generating of Gitlab Pages to debug log
-merge_request: 10335
-author: Danilo Bargen
diff --git a/changelogs/unreleased/pipeline-tooltips-overflow.yml b/changelogs/unreleased/pipeline-tooltips-overflow.yml
deleted file mode 100644
index 184da8049f3..00000000000
--- a/changelogs/unreleased/pipeline-tooltips-overflow.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Fixed pipeline actions tooltips overflowing
-merge_request:
-author:
diff --git a/changelogs/unreleased/pipelines-build-tooltip.yml b/changelogs/unreleased/pipelines-build-tooltip.yml
deleted file mode 100644
index 000276e1de3..00000000000
--- a/changelogs/unreleased/pipelines-build-tooltip.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Fixed job tooltip being cut-off
-merge_request:
-author:
diff --git a/changelogs/unreleased/plantuml-filter-after-highlight.yml b/changelogs/unreleased/plantuml-filter-after-highlight.yml
deleted file mode 100644
index f438bfd2bf7..00000000000
--- a/changelogs/unreleased/plantuml-filter-after-highlight.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Fix PlantUML integration in GFM
-merge_request: 10651
-author:
diff --git a/changelogs/unreleased/pms-lighter-colors.yml b/changelogs/unreleased/pms-lighter-colors.yml
deleted file mode 100644
index 958d4bc0ac0..00000000000
--- a/changelogs/unreleased/pms-lighter-colors.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Add lighter colors and fix existing light colors
-merge_request: 10690
-author:
diff --git a/changelogs/unreleased/projects-list-line-breaks.yml b/changelogs/unreleased/projects-list-line-breaks.yml
deleted file mode 100644
index 179d7081293..00000000000
--- a/changelogs/unreleased/projects-list-line-breaks.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Fixed projects list lines breaking
-merge_request:
-author:
diff --git a/changelogs/unreleased/quiet-pipelines.yml b/changelogs/unreleased/quiet-pipelines.yml
deleted file mode 100644
index c02eb59b824..00000000000
--- a/changelogs/unreleased/quiet-pipelines.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Only email pipeline creators; only email for successful pipelines with custom
- settings
-merge_request:
-author:
diff --git a/changelogs/unreleased/refresh-permissions-recent-users.yml b/changelogs/unreleased/refresh-permissions-recent-users.yml
deleted file mode 100644
index 4d08be6ed5c..00000000000
--- a/changelogs/unreleased/refresh-permissions-recent-users.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Reset users.authorized_projects_populated to automatically refresh user permissions
-merge_request:
-author:
diff --git a/changelogs/unreleased/remember-me-missasligned-mobile.yml b/changelogs/unreleased/remember-me-missasligned-mobile.yml
deleted file mode 100644
index 7071d32727f..00000000000
--- a/changelogs/unreleased/remember-me-missasligned-mobile.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Corrected alignment for the remember-me checkbox in the login view
-merge_request:
-author:
diff --git a/changelogs/unreleased/remove_index_for_users-current_sign_in_at.yml b/changelogs/unreleased/remove_index_for_users-current_sign_in_at.yml
deleted file mode 100644
index ec3a2c8e2bf..00000000000
--- a/changelogs/unreleased/remove_index_for_users-current_sign_in_at.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Remove index for users.current sign in at
-merge_request: 10401
-author: blackst0ne
diff --git a/changelogs/unreleased/remove_is_admin.yml b/changelogs/unreleased/remove_is_admin.yml
deleted file mode 100644
index f6baf1942de..00000000000
--- a/changelogs/unreleased/remove_is_admin.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Remove the User#is_admin? method
-merge_request: 10520
-author: blackst0ne
diff --git a/changelogs/unreleased/rename_all_issues.yml b/changelogs/unreleased/rename_all_issues.yml
deleted file mode 100644
index d3109bdb17e..00000000000
--- a/changelogs/unreleased/rename_all_issues.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Rename 'All issues' to 'Open issues' in Add issues modal
-merge_request: 10042
-author: blackst0ne
diff --git a/changelogs/unreleased/rename_done_to_closed.yml b/changelogs/unreleased/rename_done_to_closed.yml
deleted file mode 100644
index 6de112c4b0d..00000000000
--- a/changelogs/unreleased/rename_done_to_closed.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Change Done column to Closed in issue boards
-merge_request: 10198
-author: blackst0ne
diff --git a/changelogs/unreleased/replace_closing_mr_icon.yml b/changelogs/unreleased/replace_closing_mr_icon.yml
deleted file mode 100644
index 4d7b5fa67a7..00000000000
--- a/changelogs/unreleased/replace_closing_mr_icon.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Replace closing MR icon
-merge_request: 10103
-author: blackst0ne
diff --git a/changelogs/unreleased/scrollable-secondary-tabs.yml b/changelogs/unreleased/scrollable-secondary-tabs.yml
deleted file mode 100644
index 963d5d325dc..00000000000
--- a/changelogs/unreleased/scrollable-secondary-tabs.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Fixed tabs not scrolling on mobile
-merge_request:
-author:
diff --git a/changelogs/unreleased/sh-add-index-to-system-note-metadata.yml b/changelogs/unreleased/sh-add-index-to-system-note-metadata.yml
deleted file mode 100644
index 6b226c53f30..00000000000
--- a/changelogs/unreleased/sh-add-index-to-system-note-metadata.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Add unique index for notes_id to system note metadata table
-merge_request:
-author:
diff --git a/changelogs/unreleased/sh-issue-29247-fix.yml b/changelogs/unreleased/sh-issue-29247-fix.yml
deleted file mode 100644
index b530e5da55b..00000000000
--- a/changelogs/unreleased/sh-issue-29247-fix.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Don't delete a branch involved in an open merge request in "Delete all merged
- branches" service
-merge_request:
-author:
diff --git a/changelogs/unreleased/sh-optimize-duplicate-routable-full-path.yml b/changelogs/unreleased/sh-optimize-duplicate-routable-full-path.yml
new file mode 100644
index 00000000000..b1ef00f09b2
--- /dev/null
+++ b/changelogs/unreleased/sh-optimize-duplicate-routable-full-path.yml
@@ -0,0 +1,4 @@
+---
+title: Cache Routable#full_path in RequestStore to reduce duplicate route loads
+merge_request:
+author:
diff --git a/changelogs/unreleased/sh-optimize-milestone-polymorphic-url.yml b/changelogs/unreleased/sh-optimize-milestone-polymorphic-url.yml
new file mode 100644
index 00000000000..ad62c896b04
--- /dev/null
+++ b/changelogs/unreleased/sh-optimize-milestone-polymorphic-url.yml
@@ -0,0 +1,4 @@
+---
+title: Eliminate N+1 queries in loading namespaces for every issuable in milestones
+merge_request:
+author:
diff --git a/changelogs/unreleased/sh-relax-wiki-slug-constraint.yml b/changelogs/unreleased/sh-relax-wiki-slug-constraint.yml
deleted file mode 100644
index 08395b0d28c..00000000000
--- a/changelogs/unreleased/sh-relax-wiki-slug-constraint.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Relax constraint on Wiki IDs, since subdirectories can contain spaces
-merge_request:
-author:
diff --git a/changelogs/unreleased/sh-remove-tags-from-explore.yml b/changelogs/unreleased/sh-remove-tags-from-explore.yml
deleted file mode 100644
index b76ec89a006..00000000000
--- a/changelogs/unreleased/sh-remove-tags-from-explore.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Remove Tags filter from Projects Explore dropdown
-merge_request:
-author:
diff --git a/changelogs/unreleased/siemens-gitlab-ce-fix-subgroup-hide-button.yml b/changelogs/unreleased/siemens-gitlab-ce-fix-subgroup-hide-button.yml
deleted file mode 100644
index 716311c7582..00000000000
--- a/changelogs/unreleased/siemens-gitlab-ce-fix-subgroup-hide-button.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Hide new subgroup button if user has no permission to create one
-merge_request: 10627
-author:
diff --git a/changelogs/unreleased/simplify-docs-trigger.yml b/changelogs/unreleased/simplify-docs-trigger.yml
deleted file mode 100644
index 062626359ef..00000000000
--- a/changelogs/unreleased/simplify-docs-trigger.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Simplify trigger_docs build job for CE and EE
-merge_request: 9820
-author: winniehell
diff --git a/changelogs/unreleased/style-proc-cop.yml b/changelogs/unreleased/style-proc-cop.yml
deleted file mode 100644
index 25acab740bd..00000000000
--- a/changelogs/unreleased/style-proc-cop.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Enable Style/Proc cop for rubocop
-merge_request:
-author: mhasbini
diff --git a/changelogs/unreleased/submodules-no-dotgit.yml b/changelogs/unreleased/submodules-no-dotgit.yml
new file mode 100644
index 00000000000..2ff0ee997fa
--- /dev/null
+++ b/changelogs/unreleased/submodules-no-dotgit.yml
@@ -0,0 +1,4 @@
+---
+title: 'repository browser: handle submodule urls that don''t end with .git'
+merge_request:
+author: David Turner
diff --git a/changelogs/unreleased/tc-fix-pipeline-recipient.yml b/changelogs/unreleased/tc-fix-pipeline-recipient.yml
deleted file mode 100644
index 0337533fdb2..00000000000
--- a/changelogs/unreleased/tc-fix-pipeline-recipient.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Clearly show who triggered the pipeline in email
-merge_request: 10283
-author:
diff --git a/changelogs/unreleased/tc-fix-unplayable-build-action-404.yml b/changelogs/unreleased/tc-fix-unplayable-build-action-404.yml
deleted file mode 100644
index e5e22c1daf7..00000000000
--- a/changelogs/unreleased/tc-fix-unplayable-build-action-404.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Disable pipeline and environment actions that are not playable
-merge_request: 10052
-author:
diff --git a/changelogs/unreleased/tc-pipeline-show-trigger-date.yml b/changelogs/unreleased/tc-pipeline-show-trigger-date.yml
deleted file mode 100644
index 4de784d98f3..00000000000
--- a/changelogs/unreleased/tc-pipeline-show-trigger-date.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Show correct user & creation time in heading of the pipeline page
-merge_request: 9936
-author:
diff --git a/changelogs/unreleased/tc-realtime-every-pipeline-on-mr.yml b/changelogs/unreleased/tc-realtime-every-pipeline-on-mr.yml
new file mode 100644
index 00000000000..944baae257c
--- /dev/null
+++ b/changelogs/unreleased/tc-realtime-every-pipeline-on-mr.yml
@@ -0,0 +1,4 @@
+---
+title: Properly expire cache for all MRs of a pipeline
+merge_request: 10770
+author:
diff --git a/changelogs/unreleased/tc-show-pipeline-coverage-if-avail.yml b/changelogs/unreleased/tc-show-pipeline-coverage-if-avail.yml
deleted file mode 100644
index c0cc4fb18c8..00000000000
--- a/changelogs/unreleased/tc-show-pipeline-coverage-if-avail.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Show the build/pipeline coverage if it is available
-merge_request:
-author:
diff --git a/changelogs/unreleased/time-tracking-color-not-consistent.yml b/changelogs/unreleased/time-tracking-color-not-consistent.yml
deleted file mode 100644
index 50ec9efb1ff..00000000000
--- a/changelogs/unreleased/time-tracking-color-not-consistent.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Corrected time tracking icon color in the issuable side bar
-merge_request:
-author:
diff --git a/changelogs/unreleased/update-issue-board-cards-design.yml b/changelogs/unreleased/update-issue-board-cards-design.yml
deleted file mode 100644
index 5ef94a74e8a..00000000000
--- a/changelogs/unreleased/update-issue-board-cards-design.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Update issue board cards design
-merge_request: 10353
-author:
diff --git a/changelogs/unreleased/update-test-bundle-ignored-files.yml b/changelogs/unreleased/update-test-bundle-ignored-files.yml
deleted file mode 100644
index 1235d4ced6c..00000000000
--- a/changelogs/unreleased/update-test-bundle-ignored-files.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: update test_bundle.js ignored files
-merge_request:
-author:
diff --git a/changelogs/unreleased/usage-ping-port.yml b/changelogs/unreleased/usage-ping-port.yml
deleted file mode 100644
index 4f135100fce..00000000000
--- a/changelogs/unreleased/usage-ping-port.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Add usage ping to CE
-merge_request:
-author:
diff --git a/changelogs/unreleased/use-corejs-polyfills.yml b/changelogs/unreleased/use-corejs-polyfills.yml
deleted file mode 100644
index 381f80c5c0d..00000000000
--- a/changelogs/unreleased/use-corejs-polyfills.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Standardize on core-js for es2015 polyfills
-merge_request: 9749
-author:
diff --git a/changelogs/unreleased/user-callout-showing-on-all-profiles.yml b/changelogs/unreleased/user-callout-showing-on-all-profiles.yml
deleted file mode 100644
index b8eb5a149b7..00000000000
--- a/changelogs/unreleased/user-callout-showing-on-all-profiles.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: User callout only shows on current users profile
-merge_request:
-author:
diff --git a/changelogs/unreleased/user-profile-join-date.yml b/changelogs/unreleased/user-profile-join-date.yml
deleted file mode 100644
index f9d78b0dc3e..00000000000
--- a/changelogs/unreleased/user-profile-join-date.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Removed the hours & minutes from the users start date on their profile
-merge_request:
-author:
diff --git a/changelogs/unreleased/zj-api-fix-build-events.yml b/changelogs/unreleased/zj-api-fix-build-events.yml
deleted file mode 100644
index 7700d8dcd22..00000000000
--- a/changelogs/unreleased/zj-api-fix-build-events.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: "Bugfix: POST /projects/:id/hooks and PUT /projects/:id/hook/:hook_id no longer ignore the the job_events param in the V4 API"
-merge_request: 10586
-author:
diff --git a/changelogs/unreleased/zj-chat-notification-default-branch.yml b/changelogs/unreleased/zj-chat-notification-default-branch.yml
deleted file mode 100644
index fa0052d5034..00000000000
--- a/changelogs/unreleased/zj-chat-notification-default-branch.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Only send chat notifications for the default branch
-merge_request:
-author:
diff --git a/changelogs/unreleased/zj-fk-ci-triggers.yml b/changelogs/unreleased/zj-fk-ci-triggers.yml
deleted file mode 100644
index 9fe708b25c0..00000000000
--- a/changelogs/unreleased/zj-fk-ci-triggers.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Add foreign key for ci_trigger_requests on ci_triggers
-merge_request: 10537
-author:
diff --git a/changelogs/unreleased/zj-kube-service-auto-fill.yml b/changelogs/unreleased/zj-kube-service-auto-fill.yml
deleted file mode 100644
index 7a2c7a5085b..00000000000
--- a/changelogs/unreleased/zj-kube-service-auto-fill.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Don't fill in the default kubernetes namespace
-merge_request:
-author:
diff --git a/config/database.yml.mysql b/config/database.yml.mysql
index a33e40e8eb3..db1b712d3bc 100644
--- a/config/database.yml.mysql
+++ b/config/database.yml.mysql
@@ -25,6 +25,7 @@ development:
pool: 5
username: root
password: "secure password"
+ # host: localhost
# socket: /tmp/mysql.sock
# Warning: The database defined as "test" will be erased and
@@ -39,4 +40,5 @@ test: &test
pool: 5
username: root
password:
+ # host: localhost
# socket: /tmp/mysql.sock
diff --git a/config/database.yml.postgresql b/config/database.yml.postgresql
index 7067e0fe402..c517a4c0cb8 100644
--- a/config/database.yml.postgresql
+++ b/config/database.yml.postgresql
@@ -9,7 +9,7 @@ production:
# username: git
# password:
# host: localhost
- # port: 5432
+ # port: 5432
#
# Development specific
@@ -21,6 +21,7 @@ development:
pool: 5
username: postgres
password:
+ # host: localhost
#
# Staging specific
@@ -32,6 +33,7 @@ staging:
pool: 5
username: postgres
password:
+ # host: localhost
# Warning: The database defined as "test" will be erased and
# re-generated from your development database when you run "rake".
@@ -43,3 +45,4 @@ test: &test
pool: 5
username: postgres
password:
+ # host: localhost
diff --git a/config/gitlab.yml.example b/config/gitlab.yml.example
index 06c9f734c2a..c2eaf263937 100644
--- a/config/gitlab.yml.example
+++ b/config/gitlab.yml.example
@@ -505,6 +505,11 @@ production: &base
# If you use non-standard ssh port you need to specify it
# ssh_port: 22
+ workhorse:
+ # File that contains the secret key for verifying access for gitlab-workhorse.
+ # Default is '.gitlab_workhorse_secret' relative to Rails.root (i.e. root of the GitLab app).
+ # secret_file: /home/git/gitlab/.gitlab_workhorse_secret
+
## Git settings
# CAUTION!
# Use the default values unless you really know what you are doing
diff --git a/config/initializers/1_settings.rb b/config/initializers/1_settings.rb
index 87bf48a3dcd..7a8f00f11b2 100644
--- a/config/initializers/1_settings.rb
+++ b/config/initializers/1_settings.rb
@@ -388,6 +388,12 @@ Settings.gitlab_shell['owner_group'] ||= Settings.gitlab.user
Settings.gitlab_shell['ssh_path_prefix'] ||= Settings.__send__(:build_gitlab_shell_ssh_path_prefix)
#
+# Workhorse
+#
+Settings['workhorse'] ||= Settingslogic.new({})
+Settings.workhorse['secret_file'] ||= Rails.root.join('.gitlab_workhorse_secret')
+
+#
# Repositories
#
Settings['repositories'] ||= Settingslogic.new({})
diff --git a/config/initializers/rspec_profiling.rb b/config/initializers/rspec_profiling.rb
index 764c067c6f0..b909cc5b9a4 100644
--- a/config/initializers/rspec_profiling.rb
+++ b/config/initializers/rspec_profiling.rb
@@ -38,7 +38,7 @@ if Rails.env.test?
end
end
- if ENV.has_key?('CI')
+ if ENV.has_key?('CI') && ENV['GITLAB_DATABASE'] == 'postgresql'
RspecProfiling::VCS::Git.prepend(RspecProfilingExt::Git)
RspecProfiling::Run.prepend(RspecProfilingExt::Run)
end
diff --git a/config/sidekiq_queues.yml b/config/sidekiq_queues.yml
index bf8964d7f68..c3bd73533d0 100644
--- a/config/sidekiq_queues.yml
+++ b/config/sidekiq_queues.yml
@@ -34,7 +34,6 @@
- [repository_fork, 1]
- [repository_import, 1]
- [project_service, 1]
- - [clear_database_cache, 1]
- [delete_user, 1]
- [delete_merged_branches, 1]
- [authorized_projects, 1]
diff --git a/db/migrate/20170410133135_add_version_field_to_markdown_cache.rb b/db/migrate/20170410133135_add_version_field_to_markdown_cache.rb
new file mode 100644
index 00000000000..d9209fe5770
--- /dev/null
+++ b/db/migrate/20170410133135_add_version_field_to_markdown_cache.rb
@@ -0,0 +1,25 @@
+class AddVersionFieldToMarkdownCache < ActiveRecord::Migration
+ include Gitlab::Database::MigrationHelpers
+
+ DOWNTIME = false
+
+ def change
+ %i[
+ abuse_reports
+ appearances
+ application_settings
+ broadcast_messages
+ issues
+ labels
+ merge_requests
+ milestones
+ namespaces
+ notes
+ projects
+ releases
+ snippets
+ ].each do |table|
+ add_column table, :cached_markdown_version, :integer, limit: 4
+ end
+ end
+end
diff --git a/db/migrate/20170423064036_add_index_on_ci_builds_updated_at.rb b/db/migrate/20170423064036_add_index_on_ci_builds_updated_at.rb
new file mode 100644
index 00000000000..0bbb74ee05e
--- /dev/null
+++ b/db/migrate/20170423064036_add_index_on_ci_builds_updated_at.rb
@@ -0,0 +1,19 @@
+# See http://doc.gitlab.com/ce/development/migration_style_guide.html
+# for more information on how to write migrations for GitLab.
+
+class AddIndexOnCiBuildsUpdatedAt < ActiveRecord::Migration
+ include Gitlab::Database::MigrationHelpers
+
+ # Set this constant to true if this migration requires downtime.
+ DOWNTIME = false
+
+ disable_ddl_transaction!
+
+ def up
+ add_concurrent_index :ci_builds, :updated_at
+ end
+
+ def down
+ remove_concurrent_index :ci_builds, :updated_at if index_exists?(:ci_builds, :updated_at)
+ end
+end
diff --git a/db/schema.rb b/db/schema.rb
index f89e9adb7d6..7b13f2a98a1 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: 20170419001229) do
+ActiveRecord::Schema.define(version: 20170423064036) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
@@ -24,6 +24,7 @@ ActiveRecord::Schema.define(version: 20170419001229) do
t.datetime "created_at"
t.datetime "updated_at"
t.text "message_html"
+ t.integer "cached_markdown_version"
end
create_table "appearances", force: :cascade do |t|
@@ -34,6 +35,7 @@ ActiveRecord::Schema.define(version: 20170419001229) do
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.text "description_html"
+ t.integer "cached_markdown_version"
end
create_table "application_settings", force: :cascade do |t|
@@ -116,6 +118,7 @@ ActiveRecord::Schema.define(version: 20170419001229) do
t.integer "unique_ips_limit_time_window"
t.boolean "unique_ips_limit_enabled", default: false, null: false
t.decimal "polling_interval_multiplier", default: 1.0, null: false
+ t.integer "cached_markdown_version"
t.boolean "usage_ping_enabled", default: true, null: false
t.string "uuid"
end
@@ -161,6 +164,7 @@ ActiveRecord::Schema.define(version: 20170419001229) do
t.string "color"
t.string "font"
t.text "message_html"
+ t.integer "cached_markdown_version"
end
create_table "chat_names", force: :cascade do |t|
@@ -237,6 +241,7 @@ ActiveRecord::Schema.define(version: 20170419001229) do
add_index "ci_builds", ["status", "type", "runner_id"], name: "index_ci_builds_on_status_and_type_and_runner_id", using: :btree
add_index "ci_builds", ["status"], name: "index_ci_builds_on_status", using: :btree
add_index "ci_builds", ["token"], name: "index_ci_builds_on_token", unique: true, using: :btree
+ add_index "ci_builds", ["updated_at"], name: "index_ci_builds_on_updated_at", using: :btree
create_table "ci_pipelines", force: :cascade do |t|
t.string "ref"
@@ -479,6 +484,7 @@ ActiveRecord::Schema.define(version: 20170419001229) do
t.integer "time_estimate"
t.integer "relative_position"
t.datetime "closed_at"
+ t.integer "cached_markdown_version"
end
add_index "issues", ["assignee_id"], name: "index_issues_on_assignee_id", using: :btree
@@ -543,6 +549,7 @@ ActiveRecord::Schema.define(version: 20170419001229) do
t.text "description_html"
t.string "type"
t.integer "group_id"
+ t.integer "cached_markdown_version"
end
add_index "labels", ["group_id", "project_id", "title"], name: "index_labels_on_group_id_and_project_id_and_title", unique: true, using: :btree
@@ -663,6 +670,7 @@ ActiveRecord::Schema.define(version: 20170419001229) do
t.text "title_html"
t.text "description_html"
t.integer "time_estimate"
+ t.integer "cached_markdown_version"
end
add_index "merge_requests", ["assignee_id"], name: "index_merge_requests_on_assignee_id", using: :btree
@@ -700,6 +708,7 @@ ActiveRecord::Schema.define(version: 20170419001229) do
t.text "title_html"
t.text "description_html"
t.date "start_date"
+ t.integer "cached_markdown_version"
end
add_index "milestones", ["description"], name: "index_milestones_on_description_trigram", using: :gin, opclasses: {"description"=>"gin_trgm_ops"}
@@ -726,6 +735,7 @@ ActiveRecord::Schema.define(version: 20170419001229) do
t.integer "parent_id"
t.boolean "require_two_factor_authentication", default: false, null: false
t.integer "two_factor_grace_period", default: 48, null: false
+ t.integer "cached_markdown_version"
end
add_index "namespaces", ["created_at"], name: "index_namespaces_on_created_at", using: :btree
@@ -760,6 +770,7 @@ ActiveRecord::Schema.define(version: 20170419001229) do
t.integer "resolved_by_id"
t.string "discussion_id"
t.text "note_html"
+ t.integer "cached_markdown_version"
end
add_index "notes", ["author_id"], name: "index_notes_on_author_id", using: :btree
@@ -956,6 +967,7 @@ ActiveRecord::Schema.define(version: 20170419001229) do
t.integer "auto_cancel_pending_pipelines", default: 0, null: false
t.boolean "printing_merge_request_link_enabled", default: true, null: false
t.string "import_jid"
+ t.integer "cached_markdown_version"
end
add_index "projects", ["ci_id"], name: "index_projects_on_ci_id", using: :btree
@@ -1028,6 +1040,7 @@ ActiveRecord::Schema.define(version: 20170419001229) do
t.datetime "created_at"
t.datetime "updated_at"
t.text "description_html"
+ t.integer "cached_markdown_version"
end
add_index "releases", ["project_id", "tag"], name: "index_releases_on_project_id_and_tag", using: :btree
@@ -1099,6 +1112,7 @@ ActiveRecord::Schema.define(version: 20170419001229) do
t.integer "visibility_level", default: 0, null: false
t.text "title_html"
t.text "content_html"
+ t.integer "cached_markdown_version"
end
add_index "snippets", ["author_id"], name: "index_snippets_on_author_id", using: :btree
diff --git a/doc/README.md b/doc/README.md
index 9e6a5b4ed44..fb393aa09a1 100644
--- a/doc/README.md
+++ b/doc/README.md
@@ -15,6 +15,7 @@ All technical content published by GitLab lives in the documentation, including:
- [API](api/README.md) Automate GitLab via a simple and powerful API.
- [CI/CD](ci/README.md) GitLab Continuous Integration (CI) and Continuous Delivery (CD) getting started, `.gitlab-ci.yml` options, and examples.
- [Container Registry](user/project/container_registry.md) Learn how to use GitLab Container Registry.
+- [Discussions](user/discussions/index.md) Threads, comments, and resolvable discussions in issues, commits, and merge requests.
- [Git Attributes](user/project/git_attributes.md) Managing Git attributes using a `.gitattributes` file.
- [Git cheatsheet](https://gitlab.com/gitlab-com/marketing/raw/master/design/print/git-cheatsheet/print-pdf/git-cheatsheet.pdf) Download a PDF describing the most used Git operations.
- [GitLab as OAuth2 authentication service provider](integration/oauth_provider.md). It allows you to login to other applications from GitLab.
diff --git a/doc/administration/gitaly/index.md b/doc/administration/gitaly/index.md
index 2e22212ddde..6c6942a7bfe 100644
--- a/doc/administration/gitaly/index.md
+++ b/doc/administration/gitaly/index.md
@@ -1,6 +1,6 @@
# Gitaly
-[Gitaly](https://gitlab.com/gitlab-org/gitlay) (introduced in GitLab
+[Gitaly](https://gitlab.com/gitlab-org/gitaly) (introduced in GitLab
9.0) is a service that provides high-level RPC access to Git
repositories. As of GitLab 9.1 it is still an optional component with
limited scope.
diff --git a/doc/administration/high_availability/redis.md b/doc/administration/high_availability/redis.md
index b4e7bf21e35..4638a9c9782 100644
--- a/doc/administration/high_availability/redis.md
+++ b/doc/administration/high_availability/redis.md
@@ -492,7 +492,7 @@ which ideally should not have Redis or Sentinels on it for a HA setup.
redis['master_name'] = 'gitlab-redis'
## The same password for Redis authentication you set up for the master node.
- redis['password'] = 'redis-password-goes-here'
+ redis['master_password'] = 'redis-password-goes-here'
## A list of sentinels with `host` and `port`
gitlab_rails['redis_sentinels'] = [
diff --git a/doc/administration/integration/plantuml.md b/doc/administration/integration/plantuml.md
index 5c856835039..b21817c1fd3 100644
--- a/doc/administration/integration/plantuml.md
+++ b/doc/administration/integration/plantuml.md
@@ -28,7 +28,7 @@ using Tomcat:
sudo apt-get install tomcat7
sudo cp target/plantuml.war /var/lib/tomcat7/webapps/plantuml.war
sudo chown tomcat7:tomcat7 /var/lib/tomcat7/webapps/plantuml.war
-sudo service restart tomcat7
+sudo service tomcat7 restart
```
Once the Tomcat service restarts the PlantUML service will be ready and
diff --git a/doc/api/jobs.md b/doc/api/jobs.md
index 7ce67ca607d..404da3dc603 100644
--- a/doc/api/jobs.md
+++ b/doc/api/jobs.md
@@ -118,7 +118,7 @@ Example of response
Get a list of jobs for a pipeline.
```
-GET /projects/:id/pipeline/:pipeline_id/jobs
+GET /projects/:id/pipelines/:pipeline_id/jobs
```
| Attribute | Type | Required | Description |
diff --git a/doc/api/projects.md b/doc/api/projects.md
index 63f88a464f5..51de4fef7ff 100644
--- a/doc/api/projects.md
+++ b/doc/api/projects.md
@@ -859,6 +859,17 @@ Parameters:
| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) |
| `file` | string | yes | The file to be uploaded |
+To upload a file from your filesystem, use the `--form` argument. This causes
+cURL to post data using the header `Content-Type: multipart/form-data`.
+The `file=` parameter must point to a file on your filesystem and be preceded
+by `@`. For example:
+
+```bash
+curl --request POST --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" --form "file=@dk.png" https://gitlab.example.com/api/v3/projects/5/uploads
+```
+
+Returned object:
+
```json
{
"alt": "dk",
@@ -868,8 +879,8 @@ Parameters:
```
**Note**: The returned `url` is relative to the project path.
-In Markdown contexts, the link is automatically expanded when the format in `markdown` is used.
-
+In Markdown contexts, the link is automatically expanded when the format in
+`markdown` is used.
## Project members
diff --git a/doc/api/services.md b/doc/api/services.md
index 7d4779f1137..0f42c256099 100644
--- a/doc/api/services.md
+++ b/doc/api/services.md
@@ -490,41 +490,98 @@ Remove all previously JIRA settings from a project.
DELETE /projects/:id/services/jira
```
-## Mattermost Slash Commands
+## Slack slash commands
-Ability to receive slash commands from a Mattermost chat instance.
+Ability to receive slash commands from a Slack chat instance.
-### Create/Edit Mattermost Slash Command service
+### Get Slack slash command service settings
-Set Mattermost Slash Command for a project.
+Get Slack slash command service settings for a project.
```
-PUT /projects/:id/services/mattermost-slash-commands
+GET /projects/:id/services/slack-slash-commands
+```
+
+Example response:
+
+```json
+{
+ "id": 4,
+ "title": "Slack slash commands",
+ "created_at": "2017-06-27T05:51:39-07:00",
+ "updated_at": "2017-06-27T05:51:39-07:00",
+ "active": true,
+ "push_events": true,
+ "issues_events": true,
+ "merge_requests_events": true,
+ "tag_push_events": true,
+ "note_events": true,
+ "build_events": true,
+ "pipeline_events": true,
+ "properties": {
+ "token": "9koXpg98eAheJpvBs5tK"
+ }
+}
+```
+
+### Create/Edit Slack slash command service
+
+Set Slack slash command for a project.
+
+```
+PUT /projects/:id/services/slack-slash-commands
```
Parameters:
| Attribute | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
-| `token` | string | yes | The Mattermost token |
+| `token` | string | yes | The Slack token |
-### Delete Mattermost Slash Command service
+### Delete Slack slash command service
-Delete Mattermost Slash Command service for a project.
+Delete Slack slash command service for a project.
```
-DELETE /projects/:id/services/mattermost-slash-commands
+DELETE /projects/:id/services/slack-slash-commands
```
-### Get Mattermost Slash Command service settings
+## Mattermost slash commands
+
+Ability to receive slash commands from a Mattermost chat instance.
+
+### Get Mattermost slash command service settings
-Get Mattermost Slash Command service settings for a project.
+Get Mattermost slash command service settings for a project.
```
GET /projects/:id/services/mattermost-slash-commands
```
+### Create/Edit Mattermost slash command service
+
+Set Mattermost slash command for a project.
+
+```
+PUT /projects/:id/services/mattermost-slash-commands
+```
+
+Parameters:
+
+| Attribute | Type | Required | Description |
+| --------- | ---- | -------- | ----------- |
+| `token` | string | yes | The Mattermost token |
+
+
+### Delete Mattermost slash command service
+
+Delete Mattermost slash command service for a project.
+
+```
+DELETE /projects/:id/services/mattermost-slash-commands
+```
+
## Pipeline-Emails
Get emails for GitLab CI pipelines.
diff --git a/doc/api/users.md b/doc/api/users.md
index e940ba5bbe1..86027bcc05c 100644
--- a/doc/api/users.md
+++ b/doc/api/users.md
@@ -1024,7 +1024,7 @@ Parameters:
| `from` | string | no | Date string in the format YEAR-MONTH-DAY, e.g. `2016-03-11`. Defaults to 6 months ago. |
```bash
-curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v3/user/activities
+curl --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v4/user/activities
```
Example response:
diff --git a/doc/ci/autodeploy/img/auto_deploy_dropdown.png b/doc/ci/autodeploy/img/auto_deploy_dropdown.png
index 957870ec8c7..b93b0a08fea 100644
--- a/doc/ci/autodeploy/img/auto_deploy_dropdown.png
+++ b/doc/ci/autodeploy/img/auto_deploy_dropdown.png
Binary files differ
diff --git a/doc/ci/autodeploy/index.md b/doc/ci/autodeploy/index.md
index 4028a5efa9e..9fa2b2c4969 100644
--- a/doc/ci/autodeploy/index.md
+++ b/doc/ci/autodeploy/index.md
@@ -1,6 +1,8 @@
# Auto deploy
-> [Introduced][mr-8135] in GitLab 8.15. Currently requires a [Public project][project-settings].
+> [Introduced][mr-8135] in GitLab 8.15.
+> Auto deploy is an experimental feature and is not recommended for Production use at this time.
+> As of GitLab 9.1, access to the container registry is only available while the Pipeline is running. Restarting a pod, scaling a service, or other actions which require on-going access will fail. On-going secure access is planned for a subsequent release.
Auto deploy is an easy way to configure GitLab CI for the deployment of your
application. GitLab Community maintains a list of `.gitlab-ci.yml`
@@ -15,7 +17,8 @@ deployment.
## Supported templates
-The list of supported auto deploy templates is available [here][auto-deploy-templates].
+The list of supported auto deploy templates is available in the
+[gitlab-ci-yml project][auto-deploy-templates].
## Configuration
@@ -32,10 +35,37 @@ enable [Kubernetes service][kubernetes-service].
1. Test your deployment configuration using a [Review App][review-app] that was
created automatically for you.
+## Private Project Support
+
+> Experimental support [introduced][mr-2] in GitLab 9.1.
+
+When a project has been marked as private, GitLab's [Container Registry][container-registry] requires authentication when downloading containers. Auto deploy will automatically provide the required authentication information to Kubernetes, allowing temporary access to the registry. Authentication credentials will be valid while the pipeline is running, allowing for a successful initial deployment.
+
+After the pipeline completes, Kubernetes will no longer be able to access the container registry. Restarting a pod, scaling a service, or other actions which require on-going access to the registry will fail. On-going secure access is planned for a subsequent release.
+
+## PostgreSQL Database Support
+
+> Experimental support [introduced][mr-8] in GitLab 9.1.
+
+In order to support applications that require a database, [PostgreSQL][postgresql] is provisioned by default. Credentials to access the database are preconfigured, but can be customized by setting the associated [variables](#postgresql-variables). These credentials can be used for defining a `DATABASE_URL` of the format: `postgres://user:password@postgres-host:postgres-port/postgres-database`. It is important to note that the database itself is temporary, and contents will be not be saved.
+
+PostgreSQL provisioning can be disabled by setting the variable `DISABLE_POSTGRES` to `"yes"`.
+
+### PostgreSQL Variables
+
+1. `DISABLE_POSTGRES: "yes"`: disable automatic deployment of PostgreSQL
+1. `POSTGRES_USER: "my-user"`: use custom username for PostgreSQL
+1. `POSTGRES_PASSWORD: "password"`: use custom password for PostgreSQL
+1. `POSTGRES_DB: "my database"`: use custom database name for PostgreSQL
+
[mr-8135]: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/8135
+[mr-2]: https://gitlab.com/gitlab-examples/kubernetes-deploy/merge_requests/2
+[mr-8]: https://gitlab.com/gitlab-examples/kubernetes-deploy/merge_requests/8
[project-settings]: https://docs.gitlab.com/ce/public_access/public_access.html
[project-services]: ../../user/project/integrations/project_services.md
[auto-deploy-templates]: https://gitlab.com/gitlab-org/gitlab-ci-yml/tree/master/autodeploy
[kubernetes-service]: ../../user/project/integrations/kubernetes.md
[docker-in-docker]: ../docker/using_docker_build.md#use-docker-in-docker-executor
[review-app]: ../review_apps/index.md
+[container-registry]: https://docs.gitlab.com/ce/user/project/container_registry.html
+[postgresql]: https://www.postgresql.org/
diff --git a/doc/ci/triggers/README.md b/doc/ci/triggers/README.md
index e380282f910..5f611314d09 100644
--- a/doc/ci/triggers/README.md
+++ b/doc/ci/triggers/README.md
@@ -227,3 +227,31 @@ branch of project with ID `9` every night at `00:30`:
```
[ci-229]: https://gitlab.com/gitlab-org/gitlab-ci/merge_requests/229
+
+## Using scheduled triggers
+
+> [Introduced][ci-10533] in GitLab CE 9.1 as experimental.
+
+In order to schedule a trigger, navigate to your project's **Settings ➔ CI/CD Pipelines ➔ Triggers** and edit an existing trigger token.
+
+![Triggers Schedule edit](img/trigger_schedule_edit.png)
+
+To set up a scheduled trigger:
+
+1. Check the **Schedule trigger (experimental)** checkbox
+1. Enter a cron value for the frequency of the trigger ([learn more about cron notation](http://www.nncron.ru/help/EN/working/cron-format.htm))
+1. Enter the timezone of the cron trigger ([see a list of timezones](https://en.wikipedia.org/wiki/List_of_tz_database_time_zones))
+1. Enter the branch or tag that the trigger will target
+1. Hit **Save trigger** for the changes to take effect
+
+![Triggers Schedule create](img/trigger_schedule_create.png)
+
+You can check a next execution date of the scheduled trigger, which is automatically calculated by a server.
+
+![Triggers Schedule create](img/trigger_schedule_updated_next_run_at.png)
+
+> **Notes**:
+- Those triggers won't be executed precicely. Because scheduled triggers are handled by Sidekiq, which runs according to its interval. For exmaple, if you set a trigger to be executed every minute (`* * * * *`) and the Sidekiq worker performs 00:00 and 12:00 o'clock every day (`0 */12 * * *`), then your trigger will be executed only 00:00 and 12:00 o'clock every day. To change the Sidekiq worker's frequency, you have to edit the `trigger_schedule_worker` value in `config/gitlab.yml` and restart GitLab. The Sidekiq worker's configuration on GiLab.com is able to be looked up at [here](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/config/gitlab.yml.example#L185).
+- Cron notation is parsed by [Rufus-Scheduler](https://github.com/jmettraux/rufus-scheduler).
+
+[ci-10533]: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/10533
diff --git a/doc/ci/triggers/img/trigger_schedule_create.png b/doc/ci/triggers/img/trigger_schedule_create.png
new file mode 100644
index 00000000000..3cfdc00b7a7
--- /dev/null
+++ b/doc/ci/triggers/img/trigger_schedule_create.png
Binary files differ
diff --git a/doc/ci/triggers/img/trigger_schedule_edit.png b/doc/ci/triggers/img/trigger_schedule_edit.png
new file mode 100644
index 00000000000..647eac0a5d0
--- /dev/null
+++ b/doc/ci/triggers/img/trigger_schedule_edit.png
Binary files differ
diff --git a/doc/ci/triggers/img/trigger_schedule_updated_next_run_at.png b/doc/ci/triggers/img/trigger_schedule_updated_next_run_at.png
new file mode 100644
index 00000000000..71d08d04c37
--- /dev/null
+++ b/doc/ci/triggers/img/trigger_schedule_updated_next_run_at.png
Binary files differ
diff --git a/doc/development/fe_guide/index.md b/doc/development/fe_guide/index.md
index e2a198f637f..a08694fb66a 100644
--- a/doc/development/fe_guide/index.md
+++ b/doc/development/fe_guide/index.md
@@ -75,7 +75,7 @@ sharing a Merge Request with a reviewer or a maintainer.
1. Follow the steps in [Vue.js Best Practices](vue.md)
1. Follow the style guide.
1. Only a handful of people are allowed to merge Vue related features.
-Reach out to @jschatz, @iamphill, @fatihacet or @filipa early in this process.
+Reach out to one of Vue experts early in this process.
---
diff --git a/doc/development/fe_guide/testing.md b/doc/development/fe_guide/testing.md
index 66afbf4db4d..157c13352ca 100644
--- a/doc/development/fe_guide/testing.md
+++ b/doc/development/fe_guide/testing.md
@@ -14,8 +14,10 @@ for more information on general testing practices at GitLab.
GitLab uses the [Karma][karma] test runner with [Jasmine][jasmine] as its test
framework for our JavaScript unit tests. For tests that rely on DOM
-manipulation we use fixtures which are pre-compiled from HAML source files and
-served during testing by the [jasmine-jquery][jasmine-jquery] plugin.
+manipulation, we generate HTML files using RSpec suites (see `spec/javascripts/fixtures/*.rb` for examples).
+Some fixtures are still HAML templates that are translated to HTML files using the same mechanism (see `static_fixtures.rb`).
+Those will be migrated over time.
+Fixtures are served during testing by the [jasmine-jquery][jasmine-jquery] plugin.
JavaScript tests live in `spec/javascripts/`, matching the folder structure
of `app/assets/javascripts/`: `app/assets/javascripts/behaviors/autosize.js`
diff --git a/doc/development/fe_guide/vue.md b/doc/development/fe_guide/vue.md
index 45c8300d9de..73d2ffc1bdc 100644
--- a/doc/development/fe_guide/vue.md
+++ b/doc/development/fe_guide/vue.md
@@ -103,6 +103,21 @@ The Service is a class used only to communicate with the server.
It does not store or manipulate any data. It is not aware of the store or the components.
We use [vue-resource][vue-resource-repo] to communicate with the server.
+Vue Resource should only be imported in the service file.
+
+ ```javascript
+ import Vue from 'vue';
+ import VueResource from 'vue-resource';
+
+ Vue.use(VueResource);
+ ```
+
+### CSRF token
+We use a Vue Resource interceptor to manage the CSRF token.
+`app/assets/javascripts/vue_shared/vue_resource_interceptor.js` holds all our common interceptors.
+Note: You don't need to load `app/assets/javascripts/vue_shared/vue_resource_interceptor.js`
+since it's already being loaded by `common_vue.js`.
+
### End Result
The following example shows an application:
@@ -288,7 +303,8 @@ new Vue({
```
-The [issue boards service][issue-boards-service] is a good example of this pattern.
+The [issue boards service][issue-boards-service]
+is a good example of this pattern.
## Style guide
diff --git a/doc/install/installation.md b/doc/install/installation.md
index 1f61a4f67bb..b6bbc2a0af6 100644
--- a/doc/install/installation.md
+++ b/doc/install/installation.md
@@ -470,10 +470,8 @@ with setting up Gitaly until you upgrade to GitLab 9.2 or later.
sudo chmod 0700 /home/git/gitlab/tmp/sockets/private
sudo chown git /home/git/gitlab/tmp/sockets/private
- # Configure Gitaly
- cd /home/git/gitaly
- sudo -u git cp config.toml.example config.toml
# If you are using non-default settings you need to update config.toml
+ cd /home/git/gitaly
sudo -u git -H editor config.toml
# Enable Gitaly in the init script
diff --git a/doc/raketasks/backup_restore.md b/doc/raketasks/backup_restore.md
index 65fcfc77ab1..e680a560888 100644
--- a/doc/raketasks/backup_restore.md
+++ b/doc/raketasks/backup_restore.md
@@ -18,10 +18,12 @@ another is through backup restore.
To restore a backup, you will also need to restore `/etc/gitlab/gitlab-secrets.json`
(for omnibus packages) or `/home/git/gitlab/.secret` (for installations
-from source). This file contains the database encryption key and CI secret
-variables used for two-factor authentication. If you fail to restore this
-encryption key file along with the application data backup, users with two-factor
-authentication enabled will lose access to your GitLab server.
+from source). This file contains the database encryption key,
+[CI secret variables](../ci/variables/README.md#secret-variables), and
+secret variables used for [two-factor authentication](../security/two_factor_authentication.md).
+If you fail to restore this encryption key file along with the application data
+backup, users with two-factor authentication enabled and GitLab Runners will
+lose access to your GitLab server.
## Create a backup of the GitLab system
diff --git a/doc/update/9.0-to-9.1.md b/doc/update/9.0-to-9.1.md
index 1191662ee14..2d597894517 100644
--- a/doc/update/9.0-to-9.1.md
+++ b/doc/update/9.0-to-9.1.md
@@ -317,6 +317,17 @@ the socket path, but with `unix:` in front.
Each entry under `storages:` should use the same `gitaly_address`.
+#### Compile Gitaly
+
+This step will also create `config.toml.example` which you need below.
+
+```shell
+cd /home/git/gitaly
+sudo -u git -H git fetch --all --tags
+sudo -u git -H git checkout v$(</home/git/gitlab/GITALY_SERVER_VERSION)
+sudo -u git -H make
+```
+
#### Gitaly config.toml
In GitLab 9.1 we are replacing environment variables in Gitaly with a
diff --git a/doc/user/admin_area/monitoring/health_check.md b/doc/user/admin_area/monitoring/health_check.md
index eac57bc3de4..a4935f66cbd 100644
--- a/doc/user/admin_area/monitoring/health_check.md
+++ b/doc/user/admin_area/monitoring/health_check.md
@@ -1,36 +1,78 @@
# Health Check
-> [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].
+>**Notes:**
+ - Liveness and readiness probes were [introduced][ce-10416] in GitLab 9.1.
+ - The `health_check` endpoint was [introduced][ce-3888] in GitLab 8.8 and will
+ be deprecated in GitLab 9.1. Read more in the [old behavior](#old-behavior)
+ section.
+
+GitLab provides liveness and readiness probes to indicate service health and
+reachability to required services. These probes report on the status of the
+database connection, Redis connection, and access to the filesystem. These
+endpoints [can be provided to schedulers like Kubernetes][kubernetes] to hold
+traffic until the system is ready or restart the container as needed.
## 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/health_check` page of your GitLab instance.
+An access token needs to be provided while accessing the probe endpoints. The current
+accepted token can be found under the **Admin area ➔ Monitoring ➔ Health check**
+(`admin/health_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
+https://gitlab.example.com/-/readiness?token=ACCESS_TOKEN
```
-or as an HTTP header:
+which will then provide a report of system health in JSON format:
-```bash
-curl --header "TOKEN: ACCESS_TOKEN" https://gitlab.example.com/health_check.json
+```
+{
+ "db_check": {
+ "status": "ok"
+ },
+ "redis_check": {
+ "status": "ok"
+ },
+ "fs_shards_check": {
+ "status": "ok",
+ "labels": {
+ "shard": "default"
+ }
+ }
+}
```
## 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:
+Once you have the access token, the probes can be accessed:
+
+- `https://gitlab.example.com/-/readiness?token=ACCESS_TOKEN`
+- `https://gitlab.example.com/-/liveness?token=ACCESS_TOKEN`
+
+## 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.
+
+## Old behavior
+
+>**Notes:**
+ - Liveness and readiness probes were [introduced][ce-10416] in GitLab 9.1.
+ - The `health_check` endpoint was [introduced][ce-3888] in GitLab 8.8 and will
+ be deprecated in GitLab 9.1. Read more in the [old behavior](#old-behavior)
+ section.
+
+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].
+
+Once you have the [access token](#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`
@@ -54,13 +96,13 @@ 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-10416]: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/3888
[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
+[kubernetes]: https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-probes/
diff --git a/doc/user/project/merge_requests/img/btn_new_issue_for_all_discussions.png b/doc/user/discussions/img/btn_new_issue_for_all_discussions.png
index b15447ec290..b15447ec290 100644
--- a/doc/user/project/merge_requests/img/btn_new_issue_for_all_discussions.png
+++ b/doc/user/discussions/img/btn_new_issue_for_all_discussions.png
Binary files differ
diff --git a/doc/user/discussions/img/comment_type_toggle.gif b/doc/user/discussions/img/comment_type_toggle.gif
new file mode 100644
index 00000000000..b73c197b97f
--- /dev/null
+++ b/doc/user/discussions/img/comment_type_toggle.gif
Binary files differ
diff --git a/doc/user/discussions/img/discussion_comment.png b/doc/user/discussions/img/discussion_comment.png
new file mode 100644
index 00000000000..8f66d138922
--- /dev/null
+++ b/doc/user/discussions/img/discussion_comment.png
Binary files differ
diff --git a/doc/user/project/merge_requests/img/discussion_view.png b/doc/user/discussions/img/discussion_view.png
index 2ee1db2eab3..2ee1db2eab3 100644
--- a/doc/user/project/merge_requests/img/discussion_view.png
+++ b/doc/user/discussions/img/discussion_view.png
Binary files differ
diff --git a/doc/user/project/merge_requests/img/discussions_resolved.png b/doc/user/discussions/img/discussions_resolved.png
index 3fd496f6da5..3fd496f6da5 100644
--- a/doc/user/project/merge_requests/img/discussions_resolved.png
+++ b/doc/user/discussions/img/discussions_resolved.png
Binary files differ
diff --git a/doc/user/project/merge_requests/img/new_issue_for_discussion.png b/doc/user/discussions/img/new_issue_for_discussion.png
index 93c9dad8921..93c9dad8921 100644
--- a/doc/user/project/merge_requests/img/new_issue_for_discussion.png
+++ b/doc/user/discussions/img/new_issue_for_discussion.png
Binary files differ
diff --git a/doc/user/project/merge_requests/img/only_allow_merge_if_all_discussions_are_resolved.png b/doc/user/discussions/img/only_allow_merge_if_all_discussions_are_resolved.png
index 928c7d33898..928c7d33898 100644
--- a/doc/user/project/merge_requests/img/only_allow_merge_if_all_discussions_are_resolved.png
+++ b/doc/user/discussions/img/only_allow_merge_if_all_discussions_are_resolved.png
Binary files differ
diff --git a/doc/user/project/merge_requests/img/only_allow_merge_if_all_discussions_are_resolved_msg.png b/doc/user/discussions/img/only_allow_merge_if_all_discussions_are_resolved_msg.png
index bcdc0250d7c..bcdc0250d7c 100644
--- a/doc/user/project/merge_requests/img/only_allow_merge_if_all_discussions_are_resolved_msg.png
+++ b/doc/user/discussions/img/only_allow_merge_if_all_discussions_are_resolved_msg.png
Binary files differ
diff --git a/doc/user/project/merge_requests/img/preview_issue_for_discussion.png b/doc/user/discussions/img/preview_issue_for_discussion.png
index 2ee0653b2ba..2ee0653b2ba 100644
--- a/doc/user/project/merge_requests/img/preview_issue_for_discussion.png
+++ b/doc/user/discussions/img/preview_issue_for_discussion.png
Binary files differ
diff --git a/doc/user/project/merge_requests/img/preview_issue_for_discussions.png b/doc/user/discussions/img/preview_issue_for_discussions.png
index 3fe0a666678..3fe0a666678 100644
--- a/doc/user/project/merge_requests/img/preview_issue_for_discussions.png
+++ b/doc/user/discussions/img/preview_issue_for_discussions.png
Binary files differ
diff --git a/doc/user/project/merge_requests/img/resolve_comment_button.png b/doc/user/discussions/img/resolve_comment_button.png
index 70340108874..70340108874 100644
--- a/doc/user/project/merge_requests/img/resolve_comment_button.png
+++ b/doc/user/discussions/img/resolve_comment_button.png
Binary files differ
diff --git a/doc/user/project/merge_requests/img/resolve_discussion_button.png b/doc/user/discussions/img/resolve_discussion_button.png
index ab454f661e0..ab454f661e0 100644
--- a/doc/user/project/merge_requests/img/resolve_discussion_button.png
+++ b/doc/user/discussions/img/resolve_discussion_button.png
Binary files differ
diff --git a/doc/user/project/merge_requests/img/resolve_discussion_issue_notice.png b/doc/user/discussions/img/resolve_discussion_issue_notice.png
index e0ee6a39ffd..e0ee6a39ffd 100644
--- a/doc/user/project/merge_requests/img/resolve_discussion_issue_notice.png
+++ b/doc/user/discussions/img/resolve_discussion_issue_notice.png
Binary files differ
diff --git a/doc/user/project/merge_requests/img/resolve_discussion_open_issue.png b/doc/user/discussions/img/resolve_discussion_open_issue.png
index 98d63278326..98d63278326 100644
--- a/doc/user/project/merge_requests/img/resolve_discussion_open_issue.png
+++ b/doc/user/discussions/img/resolve_discussion_open_issue.png
Binary files differ
diff --git a/doc/user/discussions/index.md b/doc/user/discussions/index.md
new file mode 100644
index 00000000000..59e343ebe51
--- /dev/null
+++ b/doc/user/discussions/index.md
@@ -0,0 +1,150 @@
+# Discussions
+
+The ability to contribute conversationally is offered throughout GitLab.
+
+You can leave a comment in the following places:
+
+- issues
+- merge requests
+- snippets
+- commits
+- commit diffs
+
+The comment area supports [Markdown] and [slash commands]. One can edit their
+own comment at any time, and anyone with [Master access level][permissions] or
+higher can also edit a comment made by someone else.
+
+Apart from the standard comments, you also have the option to create a comment
+in the form of a resolvable or threaded discussion.
+
+## Resolvable discussions
+
+>**Notes:**
+- The main feature was [introduced][ce-5022] in GitLab 8.11.
+- Resolvable discussions can be added only to merge request diffs.
+
+Discussion resolution helps keep track of progress during planning or code review.
+Resolving comments prevents you from forgetting to address feedback and lets you
+hide discussions that are no longer relevant.
+
+!["A discussion between two people on a piece of code"][discussion-view]
+
+Comments and discussions can be resolved by anyone with at least Developer
+access to the project or the author of the merge request.
+
+### Jumping between unresolved discussions
+
+When a merge request has a large number of comments it can be difficult to track
+what remains unresolved. You can jump between unresolved discussions with the
+Jump button next to the Reply field on a discussion.
+
+You can also jump to the first unresolved discussion from the button next to the
+resolved discussions tracker.
+
+!["3/4 discussions resolved"][discussions-resolved]
+
+### Marking a comment or discussion as resolved
+
+You can mark a discussion as resolved by clicking the **Resolve discussion**
+button at the bottom of the discussion.
+
+!["Resolve discussion" button][resolve-discussion-button]
+
+Alternatively, you can mark each comment as resolved individually.
+
+!["Resolve comment" button][resolve-comment-button]
+
+### Move all unresolved discussions in a merge request to an issue
+
+> [Introduced][ce-8266] in GitLab 9.1
+
+To continue all open discussions from a merge request in a new issue, click the
+**Resolve all discussions in new issue** button.
+
+![Open new issue for all unresolved discussions](img/btn_new_issue_for_all_discussions.png)
+
+Alternatively, when your project only accepts merge requests [when all discussions
+are resolved](#only-allow-merge-requests-to-be-merged-if-all-discussions-are-resolved),
+there will be an **open an issue to resolve them later** link in the merge
+request widget.
+
+![Link in merge request widget](img/resolve_discussion_open_issue.png)
+
+This will prepare an issue with its content referring to the merge request and
+the unresolved discussions.
+
+![Issue mentioning discussions in a merge request](img/preview_issue_for_discussions.png)
+
+Hitting **Submit issue** will cause all discussions to be marked as resolved and
+add a note referring to the newly created issue.
+
+![Mark discussions as resolved notice](img/resolve_discussion_issue_notice.png)
+
+You can now proceed to merge the merge request from the UI.
+
+### Moving a single discussion to a new issue
+
+> [Introduced][ce-8266] in GitLab 9.1
+
+To create a new issue for a single discussion, you can use the **Resolve this
+discussion in a new issue** button.
+
+![Create issue for discussion](img/new_issue_for_discussion.png)
+
+This will direct you to a new issue prefilled with the content of the
+discussion, similar to the issues created for delegating multiple
+discussions at once. Saving the issue will mark the discussion as resolved and
+add a note to the merge request discussion referencing the new issue.
+
+![New issue for a single discussion](img/preview_issue_for_discussion.png)
+
+### Only allow merge requests to be merged if all discussions are resolved
+
+> [Introduced][ce-7125] in GitLab 8.14.
+
+You can prevent merge requests from being merged until all discussions are
+resolved.
+
+Navigate to your project's settings page, select the
+**Only allow merge requests to be merged if all discussions are resolved** check
+box and hit **Save** for the changes to take effect.
+
+![Only allow merge if all the discussions are resolved settings](img/only_allow_merge_if_all_discussions_are_resolved.png)
+
+From now on, you will not be able to merge from the UI until all discussions
+are resolved.
+
+![Only allow merge if all the discussions are resolved message](img/only_allow_merge_if_all_discussions_are_resolved_msg.png)
+
+## Threaded discussions
+
+> [Introduced][ce-7527] in GitLab 9.1.
+
+While resolvable discussions are only available to merge request diffs,
+discussions can also be added without a diff. You can start a specific
+discussion which will look like a thread, on issues, commits, snippets, and
+merge requests.
+
+To start a threaded discussion, click on the **Comment** button toggle dropdown,
+select **Start discussion** and click **Start discussion** when you're ready to
+post the comment.
+
+![Comment type toggle](img/comment_type_toggle.gif)
+
+This will post a comment with a single thread to allow you to discuss specific
+comments in greater detail.
+
+![Discussion comment](img/discussion_comment.png)
+
+[ce-5022]: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/5022
+[ce-7125]: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/7125
+[ce-7527]: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/7527
+[ce-7180]: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/7180
+[ce-8266]: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/8266
+[resolve-discussion-button]: img/resolve_discussion_button.png
+[resolve-comment-button]: img/resolve_comment_button.png
+[discussion-view]: img/discussion_view.png
+[discussions-resolved]: img/discussions_resolved.png
+[markdown]: ../markdown.md
+[slash commands]: ../project/slash_commands.md
+[permissions]: ../permissions.md
diff --git a/doc/user/project/integrations/microsoft_teams.md b/doc/user/project/integrations/microsoft_teams.md
index fbf9c1de443..eaad2d5138a 100644
--- a/doc/user/project/integrations/microsoft_teams.md
+++ b/doc/user/project/integrations/microsoft_teams.md
@@ -1,8 +1,8 @@
-# Microsoft Teams Service
+# Microsoft Teams service
## On Microsoft Teams
-To enable Microsoft Teams integration you must create an incoming webhook integration on Microsoft Teams by following the steps described in this [document](https://msdn.microsoft.com/en-us/microsoft-teams/connectors)
+To enable Microsoft Teams integration you must create an incoming webhook integration on Microsoft Teams by following the steps described in this [document](https://msdn.microsoft.com/en-us/microsoft-teams/connectors).
## On GitLab
@@ -30,4 +30,4 @@ At the end fill in your Microsoft Teams details:
After you are all done, click **Save changes** for the changes to take effect.
-![Microsoft Teams configuration](img/microsoft_teams_configuration.png) \ No newline at end of file
+![Microsoft Teams configuration](img/microsoft_teams_configuration.png)
diff --git a/doc/user/project/integrations/project_services.md b/doc/user/project/integrations/project_services.md
index 25400633de5..96c91093d7d 100644
--- a/doc/user/project/integrations/project_services.md
+++ b/doc/user/project/integrations/project_services.md
@@ -47,6 +47,7 @@ Click on the service links to see further configuration instructions and details
| [Kubernetes](kubernetes.md) | A containerized deployment service |
| [Mattermost slash commands](mattermost_slash_commands.md) | Mattermost chat and ChatOps slash commands |
| [Mattermost Notifications](mattermost.md) | Receive event notifications in Mattermost |
+| [Microsoft teams](microsoft_teams.md) | Receive notifications for actions that happen on GitLab into a room on Microsoft Teams using Office 365 Connectors |
| Pipelines emails | Email the pipeline status to a list of recipients |
| [Slack Notifications](slack.md) | Receive event notifications in Slack |
| [Slack slash commands](slack_slash_commands.md) | Slack chat and ChatOps slash commands |
diff --git a/doc/user/project/merge_requests/index.md b/doc/user/project/merge_requests/index.md
index c759b7aaa4a..954454f7e7a 100644
--- a/doc/user/project/merge_requests/index.md
+++ b/doc/user/project/merge_requests/index.md
@@ -34,7 +34,7 @@ Keep track of the progress during a code review with resolving comments.
Resolving comments prevents you from forgetting to address feedback and lets
you hide discussions that are no longer relevant.
-[Read more about resolving discussion comments in merge requests reviews.](merge_request_discussion_resolution.md)
+[Read more about resolving discussion comments in merge requests reviews.](../../discussions/index.md)
## Resolve conflicts
diff --git a/doc/user/project/merge_requests/merge_request_discussion_resolution.md b/doc/user/project/merge_requests/merge_request_discussion_resolution.md
index 230e957f045..200965875a1 100644
--- a/doc/user/project/merge_requests/merge_request_discussion_resolution.md
+++ b/doc/user/project/merge_requests/merge_request_discussion_resolution.md
@@ -1,106 +1 @@
-# Merge Request discussion resolution
-
-> [Introduced][ce-5022] in GitLab 8.11.
-
-Discussion resolution helps keep track of progress during code review.
-Resolving comments prevents you from forgetting to address feedback and lets you
-hide discussions that are no longer relevant.
-
-!["A discussion between two people on a piece of code"][discussion-view]
-
-Comments and discussions can be resolved by anyone with at least Developer
-access to the project, as well as by the author of the merge request.
-
-## Marking a comment or discussion as resolved
-
-You can mark a discussion as resolved by clicking the "Resolve discussion"
-button at the bottom of the discussion.
-
-!["Resolve discussion" button][resolve-discussion-button]
-
-Alternatively, you can mark each comment as resolved individually.
-
-!["Resolve comment" button][resolve-comment-button]
-
-## Jumping between unresolved discussions
-
-When a merge request has a large number of comments it can be difficult to track
-what remains unresolved. You can jump between unresolved discussions with the
-Jump button next to the Reply field on a discussion.
-
-You can also jump to the first unresolved discussion from the button next to the
-resolved discussions tracker.
-
-!["3/4 discussions resolved"][discussions-resolved]
-
-## Only allow merge requests to be merged if all discussions are resolved
-
-> [Introduced][ce-7125] in GitLab 8.14.
-
-You can prevent merge requests from being merged until all discussions are
-resolved.
-
-Navigate to your project's settings page, select the
-**Only allow merge requests to be merged if all discussions are resolved** check
-box and hit **Save** for the changes to take effect.
-
-![Only allow merge if all the discussions are resolved settings](img/only_allow_merge_if_all_discussions_are_resolved.png)
-
-From now on, you will not be able to merge from the UI until all discussions
-are resolved.
-
-![Only allow merge if all the discussions are resolved message](img/only_allow_merge_if_all_discussions_are_resolved_msg.png)
-
-## Move all unresolved discussions in a merge request to an issue
-
-> [Introduced][ce-8266]
-
-To continue all open discussions in a merge request, click the button **Resolve
-all discussions in new issue**
-
-![Open new issue for all unresolved discussions](img/btn_new_issue_for_all_discussions.png)
-
-Alternatively, when your project only accepts merge requests when all discussions
-are resolved, there will be an **open an issue to resolve them later** link in
-the merge request-widget.
-
-![Link in merge request widget](img/resolve_discussion_open_issue.png)
-
-This will prepare an issue with content referring to the merge request and
-discussions.
-
-![Issue mentioning discussions in a merge request](img/preview_issue_for_discussions.png)
-
-Hitting **Submit issue** will cause all discussions to be marked as resolved and
-add a note referring to the newly created issue.
-
-![Mark discussions as resolved notice](img/resolve_discussion_issue_notice.png)
-
-You can now proceed to merge the merge request from the UI.
-
-## Moving a single discussion to a new issue
-
-> [Introduced][ce-8266]
-
-To create a new issue for a single discussion, you can use the **Resolve this
-discussion in a new issue** button.
-
-![Create issue for discussion](img/new_issue_for_discussion.png)
-
-This will direct you to a new issue prefilled with the content of the
-discussion, similar to the issues created for delegating multiple
-discussions at once.
-
-![New issue for a single discussion](img/preview_issue_for_discussion.png)
-
-Saving the issue will mark the discussion as resolved and add a note
-to the discussion referencing the new issue.
-
-[ce-5022]: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/5022
-[ce-7125]: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/7125
-[ce-7180]: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/7180
-[ce-8266]: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/8266
-[resolve-discussion-button]: img/resolve_discussion_button.png
-[resolve-comment-button]: img/resolve_comment_button.png
-[discussion-view]: img/discussion_view.png
-[discussions-resolved]: img/discussions_resolved.png
+This document was moved to [another location](../../discussions/index.md).
diff --git a/doc/user/project/milestones/index.md b/doc/user/project/milestones/index.md
index 9502b9885c1..a43a42a8fe8 100644
--- a/doc/user/project/milestones/index.md
+++ b/doc/user/project/milestones/index.md
@@ -14,9 +14,6 @@ To create a new milestone, simply click the **New milestone** button when in the
milestones page. A milestone can have a title, a description and start/due dates.
Once you fill in all the details, hit the **Create milestone** button.
->**Note:**
-The start/due dates are required if you intend to use [Burndown charts](#burndown-charts).
-
![Creating a milestone](img/milestone_create.png)
## Creating a group milestone
diff --git a/doc/workflow/README.md b/doc/workflow/README.md
index 375b334c3b6..604c7d5cefb 100644
--- a/doc/workflow/README.md
+++ b/doc/workflow/README.md
@@ -32,7 +32,7 @@
- [Authorization for merge requests](../user/project/merge_requests/authorization_for_merge_requests.md)
- [Cherry-pick changes](../user/project/merge_requests/cherry_pick_changes.md)
- [Merge when pipeline succeeds](../user/project/merge_requests/merge_when_pipeline_succeeds.md)
- - [Resolve discussion comments in merge requests reviews](../user/project/merge_requests/merge_request_discussion_resolution.md)
+ - [Resolve discussion comments in merge requests reviews](../user/discussions/index.md)
- [Resolve merge conflicts in the UI](../user/project/merge_requests/resolve_conflicts.md)
- [Revert changes in the UI](../user/project/merge_requests/revert_changes.md)
- [Merge requests versions](../user/project/merge_requests/versions.md)
diff --git a/features/profile/profile.feature b/features/profile/profile.feature
index dc1339deb4c..70f47c97173 100644
--- a/features/profile/profile.feature
+++ b/features/profile/profile.feature
@@ -60,7 +60,9 @@ Feature: Profile
Then I should see a password error message
Scenario: I visit history tab
- Given I have activity
+ Given I logout
+ And I sign in via the UI
+ And I have activity
When I visit Audit Log page
Then I should see my activity
diff --git a/features/project/forked_merge_requests.feature b/features/project/forked_merge_requests.feature
index 67f1e117f7f..9809b0ea0fe 100644
--- a/features/project/forked_merge_requests.feature
+++ b/features/project/forked_merge_requests.feature
@@ -41,8 +41,7 @@ Feature: Project Forked Merge Requests
@javascript
Scenario: I see the users in the target project for a new merge request
- Given I logout
- And I sign in as an admin
+ Given I sign in as an admin
And I have a project forked off of "Shop" called "Forked Shop"
Then I visit project "Forked Shop" merge requests page
And I click link "New Merge Request"
diff --git a/features/steps/project/commits/commits.rb b/features/steps/project/commits/commits.rb
index 97ffd4b4ea2..de737cdc823 100644
--- a/features/steps/project/commits/commits.rb
+++ b/features/steps/project/commits/commits.rb
@@ -178,11 +178,13 @@ class Spinach::Features::ProjectCommits < Spinach::FeatureSteps
def select_using_dropdown(dropdown_type, selection, is_commit = false)
dropdown = find(".js-compare-#{dropdown_type}-dropdown")
dropdown.find(".compare-dropdown-toggle").click
+ dropdown.find('.dropdown-menu', visible: true)
dropdown.fill_in("Filter by Git revision", with: selection)
if is_commit
dropdown.find('input[type="search"]').send_keys(:return)
else
find_link(selection, visible: true).click
end
+ dropdown.find('.dropdown-menu', visible: false)
end
end
diff --git a/features/steps/project/forked_merge_requests.rb b/features/steps/project/forked_merge_requests.rb
index ef1bb453615..8081b764be6 100644
--- a/features/steps/project/forked_merge_requests.rb
+++ b/features/steps/project/forked_merge_requests.rb
@@ -6,7 +6,7 @@ class Spinach::Features::ProjectForkedMergeRequests < Spinach::FeatureSteps
include Select2Helper
step 'I am a member of project "Shop"' do
- @project = Project.find_by(name: "Shop")
+ @project = ::Project.find_by(name: "Shop")
@project ||= create(:project, :repository, name: "Shop")
@project.team << [@user, :reporter]
end
diff --git a/features/steps/project/merge_requests/acceptance.rb b/features/steps/project/merge_requests/acceptance.rb
index d7167352e02..7521a9439e3 100644
--- a/features/steps/project/merge_requests/acceptance.rb
+++ b/features/steps/project/merge_requests/acceptance.rb
@@ -43,7 +43,7 @@ class Spinach::Features::ProjectMergeRequestsAcceptance < Spinach::FeatureSteps
end
step 'I am signed in as a developer of the project' do
- login_as(@user)
+ sign_in(@user)
end
step 'I should see merge request merged' do
diff --git a/features/steps/project/merge_requests/revert.rb b/features/steps/project/merge_requests/revert.rb
index a8f4e4ef027..1149c1c2426 100644
--- a/features/steps/project/merge_requests/revert.rb
+++ b/features/steps/project/merge_requests/revert.rb
@@ -31,7 +31,7 @@ class Spinach::Features::RevertMergeRequests < Spinach::FeatureSteps
step 'I am signed in as a developer of the project' do
@user = create(:user) { |u| @project.add_developer(u) }
- login_as(@user)
+ sign_in(@user)
end
step 'There is an open Merge Request' do
diff --git a/features/steps/project/source/browse_files.rb b/features/steps/project/source/browse_files.rb
index f5e8f7a7c32..b4741f06d1b 100644
--- a/features/steps/project/source/browse_files.rb
+++ b/features/steps/project/source/browse_files.rb
@@ -87,9 +87,9 @@ class Spinach::Features::ProjectSourceBrowseFiles < Spinach::FeatureSteps
step 'I fill the new branch name' do
first('button.js-target-branch', visible: true).click
- first('.create-new-branch', visible: true).click
- first('#new_branch_name', visible: true).set('new_branch_name')
- first('.js-new-branch-btn', visible: true).click
+ find('.create-new-branch', visible: true).click
+ find('#new_branch_name', visible: true).set('new_branch_name')
+ find('.js-new-branch-btn', visible: true).click
end
step 'I fill the new file name with an illegal name' do
diff --git a/features/steps/project/source/markdown_render.rb b/features/steps/project/source/markdown_render.rb
index 115b67d98fb..0f0827f0477 100644
--- a/features/steps/project/source/markdown_render.rb
+++ b/features/steps/project/source/markdown_render.rb
@@ -7,7 +7,7 @@ class Spinach::Features::ProjectSourceMarkdownRender < Spinach::FeatureSteps
include SharedMarkdown
step 'I own project "Delta"' do
- @project = Project.find_by(name: "Delta")
+ @project = ::Project.find_by(name: "Delta")
@project ||= create(:project, :repository, name: "Delta", namespace: @user.namespace)
@project.team << [@user, :master]
end
diff --git a/features/steps/shared/authentication.rb b/features/steps/shared/authentication.rb
index 5c3e724746b..97fac595d8e 100644
--- a/features/steps/shared/authentication.rb
+++ b/features/steps/shared/authentication.rb
@@ -1,23 +1,33 @@
-require Rails.root.join('spec', 'support', 'login_helpers')
+require Rails.root.join('features', 'support', 'login_helpers')
module SharedAuthentication
include Spinach::DSL
include LoginHelpers
step 'I sign in as a user' do
- login_as :user
+ sign_out(@user) if @user
+
+ @user = create(:user)
+ sign_in(@user)
+ end
+
+ step 'I sign in via the UI' do
+ gitlab_sign_in(create(:user))
end
step 'I sign in as an admin' do
- login_as :admin
+ sign_out(@user) if @user
+
+ @user = create(:admin)
+ sign_in(@user)
end
step 'I sign in as "John Doe"' do
- login_with(user_exists("John Doe"))
+ gitlab_sign_in(user_exists("John Doe"))
end
step 'I sign in as "Mary Jane"' do
- login_with(user_exists("Mary Jane"))
+ gitlab_sign_in(user_exists("Mary Jane"))
end
step 'I should be redirected to sign in page' do
@@ -25,14 +35,41 @@ module SharedAuthentication
end
step "I logout" do
- logout
+ gitlab_sign_out
end
step "I logout directly" do
- logout_direct
+ gitlab_sign_out
end
def current_user
@user || User.reorder(nil).first
end
+
+ private
+
+ def gitlab_sign_in(user)
+ visit new_user_session_path
+
+ fill_in "user_login", with: user.email
+ fill_in "user_password", with: "12345678"
+ check 'user_remember_me'
+ click_button "Sign in"
+
+ @user = user
+ end
+
+ def gitlab_sign_out
+ return unless @user
+
+ if Capybara.current_driver == Capybara.javascript_driver
+ find('.header-user-dropdown-toggle').click
+ click_link 'Sign out'
+ expect(page).to have_button('Sign in')
+ else
+ sign_out(@user)
+ end
+
+ @user = nil
+ end
end
diff --git a/features/support/login_helpers.rb b/features/support/login_helpers.rb
new file mode 100644
index 00000000000..540ff25a4f2
--- /dev/null
+++ b/features/support/login_helpers.rb
@@ -0,0 +1,19 @@
+module LoginHelpers
+ # After inclusion, IntegrationHelpers calls these two methods that aren't
+ # supported by Spinach, so we perform the end results ourselves
+ class << self
+ def setup(*args)
+ Spinach.hooks.before_scenario do
+ Warden.test_mode!
+ end
+ end
+
+ def teardown(*args)
+ Spinach.hooks.after_scenario do
+ Warden.test_reset!
+ end
+ end
+ end
+
+ include Devise::Test::IntegrationHelpers
+end
diff --git a/lib/api/merge_requests.rb b/lib/api/merge_requests.rb
index cb7aec47cf0..c7dc2ea336f 100644
--- a/lib/api/merge_requests.rb
+++ b/lib/api/merge_requests.rb
@@ -197,14 +197,15 @@ module API
end
put ':id/merge_requests/:merge_request_iid/merge' do
merge_request = find_project_merge_request(params[:merge_request_iid])
+ merge_when_pipeline_succeeds = to_boolean(params[:merge_when_pipeline_succeeds])
# Merge request can not be merged
# because user dont have permissions to push into target branch
unauthorized! unless merge_request.can_be_merged_by?(current_user)
- not_allowed! unless merge_request.mergeable_state?
+ not_allowed! unless merge_request.mergeable_state?(skip_ci_check: merge_when_pipeline_succeeds)
- render_api_error!('Branch cannot be merged', 406) unless merge_request.mergeable?
+ render_api_error!('Branch cannot be merged', 406) unless merge_request.mergeable?(skip_ci_check: merge_when_pipeline_succeeds)
if params[:sha] && merge_request.diff_head_sha != params[:sha]
render_api_error!("SHA does not match HEAD of source branch: #{merge_request.diff_head_sha}", 409)
@@ -215,7 +216,7 @@ module API
should_remove_source_branch: params[:should_remove_source_branch]
}
- if params[:merge_when_pipeline_succeeds] && merge_request.head_pipeline && merge_request.head_pipeline.active?
+ if merge_when_pipeline_succeeds && merge_request.head_pipeline && merge_request.head_pipeline.active?
::MergeRequests::MergeWhenPipelineSucceedsService
.new(merge_request.target_project, current_user, merge_params)
.execute(merge_request)
diff --git a/lib/api/projects.rb b/lib/api/projects.rb
index 50842370947..db4b31b55bc 100644
--- a/lib/api/projects.rb
+++ b/lib/api/projects.rb
@@ -11,7 +11,7 @@ module API
optional :issues_enabled, type: Boolean, desc: 'Flag indication if the issue tracker is enabled'
optional :merge_requests_enabled, type: Boolean, desc: 'Flag indication if merge requests are enabled'
optional :wiki_enabled, type: Boolean, desc: 'Flag indication if the wiki is enabled'
- optional :builds_enabled, type: Boolean, desc: 'Flag indication if builds are enabled'
+ optional :jobs_enabled, type: Boolean, desc: 'Flag indication if jobs are enabled'
optional :snippets_enabled, type: Boolean, desc: 'Flag indication if snippets are enabled'
optional :shared_runners_enabled, type: Boolean, desc: 'Flag indication if shared runners are enabled for that project'
optional :container_registry_enabled, type: Boolean, desc: 'Flag indication if the container registry is enabled for that project'
@@ -103,6 +103,7 @@ module API
end
post do
attrs = declared_params(include_missing: false)
+ attrs[:builds_enabled] = attrs.delete(:jobs_enabled) if attrs.has_key?(:jobs_enabled)
project = ::Projects::CreateService.new(current_user, attrs).execute
if project.saved?
@@ -205,7 +206,7 @@ module API
# CE
at_least_one_of_ce =
[
- :builds_enabled,
+ :jobs_enabled,
:container_registry_enabled,
:default_branch,
:description,
@@ -236,6 +237,8 @@ module API
authorize! :rename_project, user_project if attrs[:name].present?
authorize! :change_visibility_level, user_project if attrs[:visibility].present?
+ attrs[:builds_enabled] = attrs.delete(:jobs_enabled) if attrs.has_key?(:jobs_enabled)
+
result = ::Projects::UpdateService.new(user_project, current_user, attrs).execute
if result[:status] == :success
diff --git a/lib/backup/database.rb b/lib/backup/database.rb
index 4016ac76348..d97e5d98229 100644
--- a/lib/backup/database.rb
+++ b/lib/backup/database.rb
@@ -80,16 +80,32 @@ module Backup
'port' => '--port',
'socket' => '--socket',
'username' => '--user',
- 'encoding' => '--default-character-set'
+ 'encoding' => '--default-character-set',
+ # SSL
+ 'sslkey' => '--ssl-key',
+ 'sslcert' => '--ssl-cert',
+ 'sslca' => '--ssl-ca',
+ 'sslcapath' => '--ssl-capath',
+ 'sslcipher' => '--ssl-cipher'
}
args.map { |opt, arg| "#{arg}=#{config[opt]}" if config[opt] }.compact
end
def pg_env
- ENV['PGUSER'] = config["username"] if config["username"]
- ENV['PGHOST'] = config["host"] if config["host"]
- ENV['PGPORT'] = config["port"].to_s if config["port"]
- ENV['PGPASSWORD'] = config["password"].to_s if config["password"]
+ args = {
+ 'username' => 'PGUSER',
+ 'host' => 'PGHOST',
+ 'port' => 'PGPORT',
+ 'password' => 'PGPASSWORD',
+ # SSL
+ 'sslmode' => 'PGSSLMODE',
+ 'sslkey' => 'PGSSLKEY',
+ 'sslcert' => 'PGSSLCERT',
+ 'sslrootcert' => 'PGSSLROOTCERT',
+ 'sslcrl' => 'PGSSLCRL',
+ 'sslcompression' => 'PGSSLCOMPRESSION'
+ }
+ args.each { |opt, arg| ENV[arg] = config[opt].to_s if config[opt] }
end
def report_success(success)
diff --git a/lib/banzai/renderer.rb b/lib/banzai/renderer.rb
index 74663556cbb..c7801cb5baf 100644
--- a/lib/banzai/renderer.rb
+++ b/lib/banzai/renderer.rb
@@ -1,7 +1,5 @@
module Banzai
module Renderer
- module_function
-
# Convert a Markdown String into an HTML-safe String of HTML
#
# Note that while the returned HTML will have been sanitized of dangerous
@@ -16,7 +14,7 @@ module Banzai
# context - Hash of context options passed to our HTML Pipeline
#
# Returns an HTML-safe String
- def render(text, context = {})
+ def self.render(text, context = {})
cache_key = context.delete(:cache_key)
cache_key = full_cache_key(cache_key, context[:pipeline])
@@ -35,24 +33,16 @@ module Banzai
# of HTML. This method is analogous to calling render(object.field), but it
# can cache the rendered HTML in the object, rather than Redis.
#
- # The context to use is learned from the passed-in object by calling
- # #banzai_render_context(field), and cannot be changed. Use #render, passing
- # it the field text, if a custom rendering is needed. The generated context
- # is returned along with the HTML.
- def render_field(object, field)
- html_field = object.markdown_cache_field_for(field)
-
- html = object.__send__(html_field)
- return html if html.present?
-
- html = cacheless_render_field(object, field)
- update_object(object, html_field, html) unless object.new_record? || object.destroyed?
+ # The context to use is managed by the object and cannot be changed.
+ # Use #render, passing it the field text, if a custom rendering is needed.
+ def self.render_field(object, field)
+ object.refresh_markdown_cache!(do_update: update_object?(object)) unless object.cached_html_up_to_date?(field)
- html
+ object.cached_html_for(field)
end
# Same as +render_field+, but without consulting or updating the cache field
- def cacheless_render_field(object, field, options = {})
+ def self.cacheless_render_field(object, field, options = {})
text = object.__send__(field)
context = object.banzai_render_context(field).merge(options)
@@ -82,7 +72,7 @@ module Banzai
# texts_and_contexts
# => [{ text: '### Hello',
# context: { cache_key: [note, :note] } }]
- def cache_collection_render(texts_and_contexts)
+ def self.cache_collection_render(texts_and_contexts)
items_collection = texts_and_contexts.each_with_index do |item, index|
context = item[:context]
cache_key = full_cache_multi_key(context.delete(:cache_key), context[:pipeline])
@@ -111,7 +101,7 @@ module Banzai
items_collection.map { |item| item[:rendered] }
end
- def render_result(text, context = {})
+ def self.render_result(text, context = {})
text = Pipeline[:pre_process].to_html(text, context) if text
Pipeline[context[:pipeline]].call(text, context)
@@ -130,7 +120,7 @@ module Banzai
# :user - User object
#
# Returns an HTML-safe String
- def post_process(html, context)
+ def self.post_process(html, context)
context = Pipeline[context[:pipeline]].transform_context(context)
pipeline = Pipeline[:post_process]
@@ -141,7 +131,7 @@ module Banzai
end.html_safe
end
- def cacheless_render(text, context = {})
+ def self.cacheless_render(text, context = {})
Gitlab::Metrics.measure(:banzai_cacheless_render) do
result = render_result(text, context)
@@ -154,7 +144,7 @@ module Banzai
end
end
- def full_cache_key(cache_key, pipeline_name)
+ def self.full_cache_key(cache_key, pipeline_name)
return unless cache_key
["banzai", *cache_key, pipeline_name || :full]
end
@@ -162,13 +152,14 @@ module Banzai
# To map Rails.cache.read_multi results we need to know the Rails.cache.expanded_key.
# Other option will be to generate stringified keys on our side and don't delegate to Rails.cache.expanded_key
# method.
- def full_cache_multi_key(cache_key, pipeline_name)
+ def self.full_cache_multi_key(cache_key, pipeline_name)
return unless cache_key
Rails.cache.send(:expanded_key, full_cache_key(cache_key, pipeline_name))
end
- def update_object(object, html_field, html)
- object.update_column(html_field, html)
+ # GitLab EE needs to disable updates on GET requests in Geo
+ def self.update_object?(object)
+ true
end
end
end
diff --git a/lib/gitlab/auth.rb b/lib/gitlab/auth.rb
index eee5601b0ed..ea918b23a63 100644
--- a/lib/gitlab/auth.rb
+++ b/lib/gitlab/auth.rb
@@ -108,7 +108,7 @@ module Gitlab
token = Doorkeeper::AccessToken.by_token(password)
if valid_oauth_token?(token)
user = User.find_by(id: token.resource_owner_id)
- Gitlab::Auth::Result.new(user, nil, :oauth, read_authentication_abilities)
+ Gitlab::Auth::Result.new(user, nil, :oauth, full_authentication_abilities)
end
end
end
diff --git a/lib/gitlab/diff/position_tracer.rb b/lib/gitlab/diff/position_tracer.rb
index 4d04f867268..c7542a8fabc 100644
--- a/lib/gitlab/diff/position_tracer.rb
+++ b/lib/gitlab/diff/position_tracer.rb
@@ -82,7 +82,7 @@ module Gitlab
file_diff, old_line, new_line = results
- Position.new(
+ new_position = Position.new(
old_path: file_diff.old_path,
new_path: file_diff.new_path,
head_sha: new_diff_refs.head_sha,
@@ -91,6 +91,13 @@ module Gitlab
old_line: old_line,
new_line: new_line
)
+
+ # If a position is found, but is not actually contained in the diff, for example
+ # because it was an unchanged line in the context of a change that was undone,
+ # we cannot return this as a successful trace.
+ return unless new_position.diff_line(repository)
+
+ new_position
end
private
diff --git a/lib/gitlab/email/handler/base_handler.rb b/lib/gitlab/email/handler/base_handler.rb
index 3f6ace0311a..0bba433d04b 100644
--- a/lib/gitlab/email/handler/base_handler.rb
+++ b/lib/gitlab/email/handler/base_handler.rb
@@ -16,6 +16,10 @@ module Gitlab
def execute
raise NotImplementedError
end
+
+ def metrics_params
+ { handler: self.class.name }
+ end
end
end
end
diff --git a/lib/gitlab/email/handler/create_issue_handler.rb b/lib/gitlab/email/handler/create_issue_handler.rb
index b8ec9138c10..e7f91607e7e 100644
--- a/lib/gitlab/email/handler/create_issue_handler.rb
+++ b/lib/gitlab/email/handler/create_issue_handler.rb
@@ -1,4 +1,3 @@
-
require 'gitlab/email/handler/base_handler'
module Gitlab
@@ -37,6 +36,10 @@ module Gitlab
@project ||= Project.find_by_full_path(project_path)
end
+ def metrics_params
+ super.merge(project: project)
+ end
+
private
def create_issue
diff --git a/lib/gitlab/email/handler/create_note_handler.rb b/lib/gitlab/email/handler/create_note_handler.rb
index c66b0435f3a..31bb775c357 100644
--- a/lib/gitlab/email/handler/create_note_handler.rb
+++ b/lib/gitlab/email/handler/create_note_handler.rb
@@ -28,6 +28,10 @@ module Gitlab
record_name: 'comment')
end
+ def metrics_params
+ super.merge(project: project)
+ end
+
private
def author
diff --git a/lib/gitlab/email/handler/unsubscribe_handler.rb b/lib/gitlab/email/handler/unsubscribe_handler.rb
index df491f060bf..df70a063330 100644
--- a/lib/gitlab/email/handler/unsubscribe_handler.rb
+++ b/lib/gitlab/email/handler/unsubscribe_handler.rb
@@ -19,6 +19,10 @@ module Gitlab
noteable.unsubscribe(sent_notification.recipient)
end
+ def metrics_params
+ super.merge(project: project)
+ end
+
private
def sent_notification
diff --git a/lib/gitlab/email/receiver.rb b/lib/gitlab/email/receiver.rb
index bb4fdd1f1f4..419d56a51e0 100644
--- a/lib/gitlab/email/receiver.rb
+++ b/lib/gitlab/email/receiver.rb
@@ -1,4 +1,3 @@
-
require_dependency 'gitlab/email/handler'
# Inspired in great part by Discourse's Email::Receiver
@@ -32,9 +31,7 @@ module Gitlab
raise UnknownIncomingEmail unless handler
- Gitlab::Metrics.add_event(:receive_email,
- project: handler.try(:project),
- handler: handler.class.name)
+ Gitlab::Metrics.add_event(:receive_email, handler.metrics_params)
handler.execute
end
diff --git a/lib/gitlab/git/encoding_helper.rb b/lib/gitlab/git/encoding_helper.rb
index e57d228e688..f918074cb14 100644
--- a/lib/gitlab/git/encoding_helper.rb
+++ b/lib/gitlab/git/encoding_helper.rb
@@ -40,7 +40,13 @@ module Gitlab
def encode_utf8(message)
detect = CharlockHolmes::EncodingDetector.detect(message)
if detect
- CharlockHolmes::Converter.convert(message, detect[:encoding], 'UTF-8')
+ begin
+ CharlockHolmes::Converter.convert(message, detect[:encoding], 'UTF-8')
+ rescue ArgumentError => e
+ Rails.logger.warn("Ignoring error converting #{detect[:encoding]} into UTF8: #{e.message}")
+
+ ''
+ end
else
clean(message)
end
diff --git a/lib/gitlab/metrics.rb b/lib/gitlab/metrics.rb
index 857e0abf710..c6dfa4ad9bd 100644
--- a/lib/gitlab/metrics.rb
+++ b/lib/gitlab/metrics.rb
@@ -138,6 +138,11 @@ module Gitlab
@series_prefix ||= Sidekiq.server? ? 'sidekiq_' : 'rails_'
end
+ # Allow access from other metrics related middlewares
+ def self.current_transaction
+ Transaction.current
+ end
+
# When enabled this should be set before being used as the usual pattern
# "@foo ||= bar" is _not_ thread-safe.
if enabled?
@@ -149,10 +154,5 @@ module Gitlab
new(udp: { host: host, port: port })
end
end
-
- # Allow access from other metrics related middlewares
- def self.current_transaction
- Transaction.current
- end
end
end
diff --git a/lib/gitlab/workhorse.rb b/lib/gitlab/workhorse.rb
index e6e40f6945d..c551f939df1 100644
--- a/lib/gitlab/workhorse.rb
+++ b/lib/gitlab/workhorse.rb
@@ -168,7 +168,7 @@ module Gitlab
end
def secret_path
- Rails.root.join('.gitlab_workhorse_secret')
+ Gitlab.config.workhorse.secret_file
end
def set_key_and_notify(key, value, expire: nil, overwrite: true)
diff --git a/lib/tasks/cache.rake b/lib/tasks/cache.rake
index d55923673b1..125a3d560d6 100644
--- a/lib/tasks/cache.rake
+++ b/lib/tasks/cache.rake
@@ -21,12 +21,7 @@ namespace :cache do
end
end
- desc "GitLab | Clear database cache (in the background)"
- task db: :environment do
- ClearDatabaseCacheWorker.perform_async
- end
-
- task all: [:db, :redis]
+ task all: [:redis]
end
task clear: 'cache:clear:redis'
diff --git a/lib/tasks/gitlab/gitaly.rake b/lib/tasks/gitlab/gitaly.rake
index 8079c6e416c..046780481ba 100644
--- a/lib/tasks/gitlab/gitaly.rake
+++ b/lib/tasks/gitlab/gitaly.rake
@@ -2,6 +2,8 @@ namespace :gitlab do
namespace :gitaly do
desc "GitLab | Install or upgrade gitaly"
task :install, [:dir] => :environment do |t, args|
+ require 'toml'
+
warn_user_is_not_gitlab
unless args.dir.present?
abort %(Please specify the directory where you want to install gitaly:\n rake "gitlab:gitaly:install[/home/git/gitaly]")
@@ -16,6 +18,7 @@ namespace :gitlab do
command = status.zero? ? 'gmake' : 'make'
Dir.chdir(args.dir) do
+ create_gitaly_configuration
run_command!([command])
end
end
@@ -33,5 +36,39 @@ namespace :gitlab do
puts TOML.dump(storage: config)
end
+
+ private
+
+ # We cannot create config.toml files for all possible Gitaly configuations.
+ # For instance, if Gitaly is running on another machine then it makes no
+ # sense to write a config.toml file on the current machine. This method will
+ # only write a config.toml file in the most common and simplest case: the
+ # case where we have exactly one Gitaly process and we are sure it is
+ # running locally because it uses a Unix socket.
+ def create_gitaly_configuration
+ storages = []
+ address = nil
+
+ Gitlab.config.repositories.storages.each do |key, val|
+ if address
+ if address != val['gitaly_address']
+ raise ArgumentError, "Your gitlab.yml contains more than one gitaly_address."
+ end
+ elsif URI(val['gitaly_address']).scheme != 'unix'
+ raise ArgumentError, "Automatic config.toml generation only supports 'unix:' addresses."
+ else
+ address = val['gitaly_address']
+ end
+
+ storages << { name: key, path: val['path'] }
+ end
+
+ File.open("config.toml", "w") do |f|
+ f.puts TOML.dump(socket_path: address.sub(%r{\Aunix:}, ''), storages: storages)
+ end
+ rescue ArgumentError => e
+ puts "Skipping config.toml generation:"
+ puts e.message
+ end
end
end
diff --git a/package.json b/package.json
index e65f30eea77..f8c151ebd81 100644
--- a/package.json
+++ b/package.json
@@ -32,8 +32,10 @@
"js-cookie": "^2.1.3",
"jszip": "^3.1.3",
"jszip-utils": "^0.0.2",
+ "marked": "^0.3.6",
"mousetrap": "^1.4.6",
"pikaday": "^1.5.1",
+ "prismjs": "^1.6.0",
"raphael": "^2.2.7",
"raw-loader": "^0.5.1",
"react-dev-utils": "^0.5.2",
diff --git a/scripts/prepare_build.sh b/scripts/prepare_build.sh
index 6cacb81b8bc..de7379425cf 100755
--- a/scripts/prepare_build.sh
+++ b/scripts/prepare_build.sh
@@ -1,26 +1,48 @@
#!/bin/sh
-retry() {
- if eval "$@"; then
- return 0
- fi
+. scripts/utils.sh
+
+export SETUP_DB=${SETUP_DB:-true}
+export USE_BUNDLE_INSTALL=${USE_BUNDLE_INSTALL:-true}
+export BUNDLE_INSTALL_FLAGS="--without production --jobs $(nproc) --path vendor --retry 3 --quiet"
+
+# Determine the database by looking at the job name.
+# For example, we'll get pg if the job is `rspec pg 19 20`
+export GITLAB_DATABASE=$(echo $CI_JOB_NAME | cut -f2 -d' ')
+
+# This would make the default database postgresql, and we could also use
+# pg to mean postgresql.
+if [ "$GITLAB_DATABASE" != 'mysql' ]; then
+ export GITLAB_DATABASE='postgresql'
+fi
+
+cp config/database.yml.$GITLAB_DATABASE config/database.yml
- for i in 2 1; do
- sleep 3s
- echo "Retrying $i..."
- if eval "$@"; then
- return 0
- fi
- done
- return 1
-}
-
-cp config/database.yml.mysql config/database.yml
-sed -i 's/username:.*/username: root/g' config/database.yml
-sed -i 's/password:.*/password:/g' config/database.yml
-sed -i 's/# socket:.*/host: mysql/g' config/database.yml
+if [ "$GITLAB_DATABASE" = 'postgresql' ]; then
+ sed -i 's/# host:.*/host: postgres/g' config/database.yml
+else # Assume it's mysql
+ sed -i 's/username:.*/username: root/g' config/database.yml
+ sed -i 's/password:.*/password:/g' config/database.yml
+ sed -i 's/# host:.*/host: mysql/g' config/database.yml
+fi
cp config/resque.yml.example config/resque.yml
sed -i 's/localhost/redis/g' config/resque.yml
-export FLAGS="--path vendor --retry 3 --quiet"
+cp config/gitlab.yml.example config/gitlab.yml
+
+if [ "$USE_BUNDLE_INSTALL" != "false" ]; then
+ retry bundle install --clean $BUNDLE_INSTALL_FLAGS
+fi
+
+# Only install knapsack after bundle install! Otherwise oddly some native
+# gems could not be found under some circumstance. No idea why, hours wasted.
+retry gem install knapsack fog-aws mime-types
+
+if [ "$SETUP_DB" != "false" ]; then
+ bundle exec rake db:drop db:create db:schema:load db:migrate
+
+ if [ "$GITLAB_DATABASE" = "mysql" ]; then
+ bundle exec rake add_limits_mysql
+ fi
+fi
diff --git a/scripts/utils.sh b/scripts/utils.sh
new file mode 100644
index 00000000000..6faa701f0ce
--- /dev/null
+++ b/scripts/utils.sh
@@ -0,0 +1,14 @@
+retry() {
+ if eval "$@"; then
+ return 0
+ fi
+
+ for i in 2 1; do
+ sleep 3s
+ echo "Retrying $i..."
+ if eval "$@"; then
+ return 0
+ fi
+ done
+ return 1
+}
diff --git a/spec/controllers/admin/groups_controller_spec.rb b/spec/controllers/admin/groups_controller_spec.rb
index 84db26a958a..c29b2fe8946 100644
--- a/spec/controllers/admin/groups_controller_spec.rb
+++ b/spec/controllers/admin/groups_controller_spec.rb
@@ -22,4 +22,28 @@ describe Admin::GroupsController do
expect(response).to redirect_to(admin_groups_path)
end
end
+
+ describe 'PUT #members_update' do
+ let(:group_user) { create(:user) }
+
+ it 'adds user to members' do
+ put :members_update, id: group,
+ user_ids: group_user.id,
+ access_level: Gitlab::Access::GUEST
+
+ expect(response).to set_flash.to 'Users were successfully added.'
+ expect(response).to redirect_to(admin_group_path(group))
+ expect(group.users).to include group_user
+ end
+
+ it 'adds no user to members' do
+ put :members_update, id: group,
+ user_ids: '',
+ access_level: Gitlab::Access::GUEST
+
+ expect(response).to set_flash.to 'No users specified.'
+ expect(response).to redirect_to(admin_group_path(group))
+ expect(group.users).not_to include group_user
+ end
+ end
end
diff --git a/spec/controllers/dashboard/todos_controller_spec.rb b/spec/controllers/dashboard/todos_controller_spec.rb
index 6075259ea99..762e90f4a16 100644
--- a/spec/controllers/dashboard/todos_controller_spec.rb
+++ b/spec/controllers/dashboard/todos_controller_spec.rb
@@ -1,8 +1,6 @@
require 'spec_helper'
describe Dashboard::TodosController do
- include ApiHelpers
-
let(:user) { create(:user) }
let(:author) { create(:user) }
let(:project) { create(:empty_project) }
diff --git a/spec/controllers/projects/builds_controller_spec.rb b/spec/controllers/projects/builds_controller_spec.rb
index faf3770f5e9..fb4ccfa58c2 100644
--- a/spec/controllers/projects/builds_controller_spec.rb
+++ b/spec/controllers/projects/builds_controller_spec.rb
@@ -1,8 +1,6 @@
require 'spec_helper'
describe Projects::BuildsController do
- include ApiHelpers
-
let(:user) { create(:user) }
let(:project) { create(:empty_project, :public) }
@@ -63,4 +61,44 @@ describe Projects::BuildsController do
expect(json_response['favicon']).to eq "/assets/ci_favicons/#{status.favicon}.ico"
end
end
+
+ describe 'GET trace.json' do
+ let(:pipeline) { create(:ci_pipeline, project: project) }
+ let(:build) { create(:ci_build, pipeline: pipeline) }
+ let(:user) { create(:user) }
+
+ context 'when user is logged in as developer' do
+ before do
+ project.add_developer(user)
+ sign_in(user)
+ get_trace
+ end
+
+ it 'traces build log' do
+ expect(response).to have_http_status(:ok)
+ expect(json_response['id']).to eq build.id
+ expect(json_response['status']).to eq build.status
+ end
+ end
+
+ context 'when user is logged in as non member' do
+ before do
+ sign_in(user)
+ get_trace
+ end
+
+ it 'traces build log' do
+ expect(response).to have_http_status(:ok)
+ expect(json_response['id']).to eq build.id
+ expect(json_response['status']).to eq build.status
+ end
+ end
+
+ def get_trace
+ get :trace, namespace_id: project.namespace,
+ project_id: project,
+ id: build.id,
+ format: :json
+ end
+ end
end
diff --git a/spec/controllers/projects/builds_controller_specs.rb b/spec/controllers/projects/builds_controller_specs.rb
deleted file mode 100644
index d501f7b3155..00000000000
--- a/spec/controllers/projects/builds_controller_specs.rb
+++ /dev/null
@@ -1,47 +0,0 @@
-require 'spec_helper'
-
-describe Projects::BuildsController do
- include ApiHelpers
-
- let(:project) { create(:empty_project, :public) }
-
- describe 'GET trace.json' do
- let(:pipeline) { create(:ci_pipeline, project: project) }
- let(:build) { create(:ci_build, pipeline: pipeline) }
- let(:user) { create(:user) }
-
- context 'when user is logged in as developer' do
- before do
- project.add_developer(user)
- sign_in(user)
- get_trace
- end
-
- it 'traces build log' do
- expect(response).to have_http_status(:ok)
- expect(json_response['id']).to eq build.id
- expect(json_response['status']).to eq build.status
- end
- end
-
- context 'when user is logged in as non member' do
- before do
- sign_in(user)
- get_trace
- end
-
- it 'traces build log' do
- expect(response).to have_http_status(:ok)
- expect(json_response['id']).to eq build.id
- expect(json_response['status']).to eq build.status
- end
- end
-
- def get_trace
- get :trace, namespace_id: project.namespace,
- project_id: project,
- id: build.id,
- format: :json
- end
- end
-end
diff --git a/spec/controllers/projects/environments_controller_spec.rb b/spec/controllers/projects/environments_controller_spec.rb
index 5525fbd8130..5c478534ff3 100644
--- a/spec/controllers/projects/environments_controller_spec.rb
+++ b/spec/controllers/projects/environments_controller_spec.rb
@@ -1,8 +1,6 @@
require 'spec_helper'
describe Projects::EnvironmentsController do
- include ApiHelpers
-
let(:user) { create(:user) }
let(:project) { create(:empty_project) }
diff --git a/spec/controllers/projects/labels_controller_spec.rb b/spec/controllers/projects/labels_controller_spec.rb
index 6a6e9bf378a..05999431d8f 100644
--- a/spec/controllers/projects/labels_controller_spec.rb
+++ b/spec/controllers/projects/labels_controller_spec.rb
@@ -127,7 +127,7 @@ describe Projects::LabelsController do
context 'group owner' do
before do
- GroupMember.add_users_to_group(group, [user], :owner)
+ GroupMember.add_users(group, [user], :owner)
end
it 'gives access' do
diff --git a/spec/controllers/projects/merge_requests_controller_spec.rb b/spec/controllers/projects/merge_requests_controller_spec.rb
index cc393bd24f2..a793da4162a 100644
--- a/spec/controllers/projects/merge_requests_controller_spec.rb
+++ b/spec/controllers/projects/merge_requests_controller_spec.rb
@@ -1,8 +1,6 @@
require 'spec_helper'
describe Projects::MergeRequestsController do
- include ApiHelpers
-
let(:project) { create(:project) }
let(:user) { create(:user) }
let(:merge_request) { create(:merge_request_with_diffs, target_project: project, source_project: project) }
diff --git a/spec/controllers/projects/milestones_controller_spec.rb b/spec/controllers/projects/milestones_controller_spec.rb
index 14207bf6b7a..47e61c3cea8 100644
--- a/spec/controllers/projects/milestones_controller_spec.rb
+++ b/spec/controllers/projects/milestones_controller_spec.rb
@@ -5,6 +5,7 @@ describe Projects::MilestonesController do
let(:user) { create(:user) }
let(:milestone) { create(:milestone, project: project) }
let(:issue) { create(:issue, project: project, milestone: milestone) }
+ let!(:label) { create(:label, project: project, title: 'Issue Label', issues: [issue]) }
let!(:merge_request) { create(:merge_request, source_project: project, target_project: project, milestone: milestone) }
before do
@@ -13,6 +14,20 @@ describe Projects::MilestonesController do
controller.instance_variable_set(:@project, project)
end
+ describe "#show" do
+ render_views
+
+ def view_milestone
+ get :show, namespace_id: project.namespace.id, project_id: project.id, id: milestone.iid
+ end
+
+ it 'shows milestone page' do
+ view_milestone
+
+ expect(response).to have_http_status(200)
+ end
+ end
+
describe "#destroy" do
it "removes milestone" do
expect(issue.milestone_id).to eq(milestone.id)
diff --git a/spec/controllers/projects/pipelines_controller_spec.rb b/spec/controllers/projects/pipelines_controller_spec.rb
index d9192177a06..b9bacc5a64a 100644
--- a/spec/controllers/projects/pipelines_controller_spec.rb
+++ b/spec/controllers/projects/pipelines_controller_spec.rb
@@ -1,8 +1,6 @@
require 'spec_helper'
describe Projects::PipelinesController do
- include ApiHelpers
-
let(:user) { create(:user) }
let(:project) { create(:empty_project, :public) }
diff --git a/spec/controllers/projects/todo_controller_spec.rb b/spec/controllers/projects/todo_controller_spec.rb
index 9a7beeff6fe..c5a4153d991 100644
--- a/spec/controllers/projects/todo_controller_spec.rb
+++ b/spec/controllers/projects/todo_controller_spec.rb
@@ -1,8 +1,6 @@
require('spec_helper')
describe Projects::TodosController do
- include ApiHelpers
-
let(:user) { create(:user) }
let(:project) { create(:empty_project) }
let(:issue) { create(:issue, project: project) }
diff --git a/spec/features/admin/admin_labels_spec.rb b/spec/features/admin/admin_labels_spec.rb
index 6d6c9165c83..fa3d9ee25c0 100644
--- a/spec/features/admin/admin_labels_spec.rb
+++ b/spec/features/admin/admin_labels_spec.rb
@@ -1,8 +1,6 @@
require 'spec_helper'
RSpec.describe 'admin issues labels' do
- include WaitForAjax
-
let!(:bug_label) { Label.create(title: 'bug', template: true) }
let!(:feature_label) { Label.create(title: 'feature', template: true) }
diff --git a/spec/features/admin/admin_users_spec.rb b/spec/features/admin/admin_users_spec.rb
index f6c3bc6a58d..c5b1ef1295c 100644
--- a/spec/features/admin/admin_users_spec.rb
+++ b/spec/features/admin/admin_users_spec.rb
@@ -1,8 +1,6 @@
require 'spec_helper'
describe "Admin::Users", feature: true do
- include WaitForAjax
-
let!(:user) do
create(:omniauth_user, provider: 'twitter', extern_uid: '123456')
end
diff --git a/spec/features/auto_deploy_spec.rb b/spec/features/auto_deploy_spec.rb
index 6f36c74c911..67b0f006854 100644
--- a/spec/features/auto_deploy_spec.rb
+++ b/spec/features/auto_deploy_spec.rb
@@ -1,10 +1,8 @@
require 'spec_helper'
describe 'Auto deploy' do
- include WaitForAjax
-
let(:user) { create(:user) }
- let(:project) { create(:project) }
+ let(:project) { create(:project, :repository) }
before do
project.create_kubernetes_service(
diff --git a/spec/features/boards/add_issues_modal_spec.rb b/spec/features/boards/add_issues_modal_spec.rb
index 248c31115ad..505e0b5c355 100644
--- a/spec/features/boards/add_issues_modal_spec.rb
+++ b/spec/features/boards/add_issues_modal_spec.rb
@@ -1,7 +1,6 @@
require 'rails_helper'
describe 'Issue Boards add issue modal', :feature, :js do
- include WaitForAjax
include WaitForVueResource
let(:project) { create(:empty_project, :public) }
diff --git a/spec/features/boards/boards_spec.rb b/spec/features/boards/boards_spec.rb
index 30ad169e30e..a172ce1e8c0 100644
--- a/spec/features/boards/boards_spec.rb
+++ b/spec/features/boards/boards_spec.rb
@@ -1,7 +1,6 @@
require 'rails_helper'
describe 'Issue Boards', feature: true, js: true do
- include WaitForAjax
include WaitForVueResource
include DragTo
diff --git a/spec/features/boards/new_issue_spec.rb b/spec/features/boards/new_issue_spec.rb
index e6d7cf106d4..f04a1a89e96 100644
--- a/spec/features/boards/new_issue_spec.rb
+++ b/spec/features/boards/new_issue_spec.rb
@@ -1,7 +1,6 @@
require 'rails_helper'
describe 'Issue Boards new issue', feature: true, js: true do
- include WaitForAjax
include WaitForVueResource
let(:project) { create(:empty_project, :public) }
diff --git a/spec/features/boards/sidebar_spec.rb b/spec/features/boards/sidebar_spec.rb
index 3332e07ec31..bafa4f05937 100644
--- a/spec/features/boards/sidebar_spec.rb
+++ b/spec/features/boards/sidebar_spec.rb
@@ -1,7 +1,6 @@
require 'rails_helper'
describe 'Issue Boards', feature: true, js: true do
- include WaitForAjax
include WaitForVueResource
let(:user) { create(:user) }
diff --git a/spec/features/calendar_spec.rb b/spec/features/calendar_spec.rb
index 35d090c4b7f..496faf87a16 100644
--- a/spec/features/calendar_spec.rb
+++ b/spec/features/calendar_spec.rb
@@ -1,10 +1,8 @@
require 'spec_helper'
feature 'Contributions Calendar', :feature, :js do
- include WaitForAjax
-
let(:user) { create(:user) }
- let(:contributed_project) { create(:project, :public) }
+ let(:contributed_project) { create(:empty_project, :public) }
let(:issue_note) { create(:note, project: contributed_project) }
# Ex/ Sunday Jan 1, 2016
diff --git a/spec/features/commits_spec.rb b/spec/features/commits_spec.rb
index 881f1fca4d1..e6c4ab24de5 100644
--- a/spec/features/commits_spec.rb
+++ b/spec/features/commits_spec.rb
@@ -3,7 +3,7 @@ require 'spec_helper'
describe 'Commits' do
include CiStatusHelper
- let(:project) { create(:project) }
+ let(:project) { create(:project, :repository) }
describe 'CI' do
before do
diff --git a/spec/features/copy_as_gfm_spec.rb b/spec/features/copy_as_gfm_spec.rb
index 55df7e45f79..64a6c70061b 100644
--- a/spec/features/copy_as_gfm_spec.rb
+++ b/spec/features/copy_as_gfm_spec.rb
@@ -433,7 +433,7 @@ describe 'Copy as GFM', feature: true, js: true do
end
describe 'Copying code' do
- let(:project) { create(:project) }
+ let(:project) { create(:project, :repository) }
context 'from a diff' do
before do
diff --git a/spec/features/cycle_analytics_spec.rb b/spec/features/cycle_analytics_spec.rb
index 0648c89a5c7..b93275c330b 100644
--- a/spec/features/cycle_analytics_spec.rb
+++ b/spec/features/cycle_analytics_spec.rb
@@ -1,11 +1,9 @@
require 'spec_helper'
feature 'Cycle Analytics', feature: true, js: true do
- include WaitForAjax
-
let(:user) { create(:user) }
let(:guest) { create(:user) }
- let(:project) { create(:project) }
+ let(:project) { create(:project, :repository) }
let(:issue) { create(:issue, project: project, created_at: 2.days.ago) }
let(:milestone) { create(:milestone, project: project) }
let(:mr) { create_merge_request_closing_issue(issue) }
diff --git a/spec/features/dashboard/datetime_on_tooltips_spec.rb b/spec/features/dashboard/datetime_on_tooltips_spec.rb
index dc9d09fa396..0e9e3f78be2 100644
--- a/spec/features/dashboard/datetime_on_tooltips_spec.rb
+++ b/spec/features/dashboard/datetime_on_tooltips_spec.rb
@@ -1,8 +1,6 @@
require 'spec_helper'
feature 'Tooltips on .timeago dates', feature: true, js: true do
- include WaitForAjax
-
let(:user) { create(:user) }
let(:project) { create(:project, name: 'test', namespace: user.namespace) }
let(:created_date) { Date.yesterday.to_time }
diff --git a/spec/features/dashboard/groups_list_spec.rb b/spec/features/dashboard/groups_list_spec.rb
index ca04107d33a..52b4d82e856 100644
--- a/spec/features/dashboard/groups_list_spec.rb
+++ b/spec/features/dashboard/groups_list_spec.rb
@@ -1,8 +1,6 @@
require 'spec_helper'
describe 'Dashboard Groups page', js: true, feature: true do
- include WaitForAjax
-
let!(:user) { create :user }
let!(:group) { create(:group) }
let!(:nested_group) { create(:group, :nested) }
diff --git a/spec/features/dashboard/project_member_activity_index_spec.rb b/spec/features/dashboard/project_member_activity_index_spec.rb
index 49d93db58a9..16c214ae060 100644
--- a/spec/features/dashboard/project_member_activity_index_spec.rb
+++ b/spec/features/dashboard/project_member_activity_index_spec.rb
@@ -1,8 +1,6 @@
require 'spec_helper'
feature 'Project member activity', feature: true, js: true do
- include WaitForAjax
-
let(:user) { create(:user) }
let(:project) { create(:empty_project, :public, name: 'x', namespace: user.namespace) }
diff --git a/spec/features/dashboard_issues_spec.rb b/spec/features/dashboard_issues_spec.rb
index 8c61cdebc4b..b6b87905231 100644
--- a/spec/features/dashboard_issues_spec.rb
+++ b/spec/features/dashboard_issues_spec.rb
@@ -2,7 +2,7 @@ require 'spec_helper'
describe "Dashboard Issues filtering", feature: true, js: true do
let(:user) { create(:user) }
- let(:project) { create(:project) }
+ let(:project) { create(:empty_project) }
let(:milestone) { create(:milestone, project: project) }
context 'filtering by milestone' do
diff --git a/spec/features/expand_collapse_diffs_spec.rb b/spec/features/expand_collapse_diffs_spec.rb
index 8c64b050e19..76c77e0bc5f 100644
--- a/spec/features/expand_collapse_diffs_spec.rb
+++ b/spec/features/expand_collapse_diffs_spec.rb
@@ -1,10 +1,8 @@
require 'spec_helper'
feature 'Expand and collapse diffs', js: true, feature: true do
- include WaitForAjax
-
let(:branch) { 'expand-collapse-diffs' }
- let(:project) { create(:project) }
+ let(:project) { create(:project, :repository) }
before do
login_as :admin
diff --git a/spec/features/explore/groups_list_spec.rb b/spec/features/explore/groups_list_spec.rb
index 9daaaa8e555..8e5421a984b 100644
--- a/spec/features/explore/groups_list_spec.rb
+++ b/spec/features/explore/groups_list_spec.rb
@@ -1,8 +1,6 @@
require 'spec_helper'
describe 'Explore Groups page', js: true, feature: true do
- include WaitForAjax
-
let!(:user) { create :user }
let!(:group) { create(:group) }
let!(:public_group) { create(:group, :public) }
diff --git a/spec/features/gitlab_flavored_markdown_spec.rb b/spec/features/gitlab_flavored_markdown_spec.rb
index 876f33dd03e..01b1aee4fd3 100644
--- a/spec/features/gitlab_flavored_markdown_spec.rb
+++ b/spec/features/gitlab_flavored_markdown_spec.rb
@@ -1,28 +1,28 @@
require 'spec_helper'
describe "GitLab Flavored Markdown", feature: true do
- let(:project) { create(:project) }
+ let(:project) { create(:empty_project) }
let(:issue) { create(:issue, project: project) }
- let(:merge_request) { create(:merge_request, source_project: project, target_project: project) }
let(:fred) do
- u = create(:user, name: "fred")
- project.team << [u, :master]
- u
+ create(:user, name: 'fred') do |user|
+ project.add_master(user)
+ end
end
before do
- allow_any_instance_of(Commit).to receive(:title).
- and_return("fix #{issue.to_reference}\n\nask #{fred.to_reference} for details")
+ login_as(:user)
+ project.add_developer(@user)
end
- let(:commit) { project.commit }
+ describe "for commits" do
+ let(:project) { create(:project, :repository) }
+ let(:commit) { project.commit }
- before do
- login_as :user
- project.team << [@user, :developer]
- end
+ before do
+ allow_any_instance_of(Commit).to receive(:title).
+ and_return("fix #{issue.to_reference}\n\nask #{fred.to_reference} for details")
+ end
- describe "for commits" do
it "renders title in commits#index" do
visit namespace_project_commits_path(project.namespace, project, 'master', limit: 1)
@@ -92,6 +92,8 @@ describe "GitLab Flavored Markdown", feature: true do
end
describe "for merge requests" do
+ let(:project) { create(:project, :repository) }
+
before do
@merge_request = create(:merge_request, source_project: project, target_project: project, title: "fix #{issue.to_reference}")
end
diff --git a/spec/features/global_search_spec.rb b/spec/features/global_search_spec.rb
index f6409e00f22..4b22b07494d 100644
--- a/spec/features/global_search_spec.rb
+++ b/spec/features/global_search_spec.rb
@@ -2,7 +2,7 @@ require 'spec_helper'
feature 'Global search', feature: true do
let(:user) { create(:user) }
- let(:project) { create(:project, namespace: user.namespace) }
+ let(:project) { create(:empty_project, namespace: user.namespace) }
before do
project.team << [user, :master]
diff --git a/spec/features/issues/award_emoji_spec.rb b/spec/features/issues/award_emoji_spec.rb
index 8e67ab028d7..71df3c949db 100644
--- a/spec/features/issues/award_emoji_spec.rb
+++ b/spec/features/issues/award_emoji_spec.rb
@@ -1,7 +1,6 @@
require 'rails_helper'
describe 'Awards Emoji', feature: true do
- include WaitForAjax
include WaitForVueResource
let!(:project) { create(:project, :public) }
diff --git a/spec/features/issues/bulk_assignment_labels_spec.rb b/spec/features/issues/bulk_assignment_labels_spec.rb
index 2f59630b4fb..1de50d6d77e 100644
--- a/spec/features/issues/bulk_assignment_labels_spec.rb
+++ b/spec/features/issues/bulk_assignment_labels_spec.rb
@@ -1,8 +1,6 @@
require 'rails_helper'
feature 'Issues > Labels bulk assignment', feature: true do
- include WaitForAjax
-
let(:user) { create(:user) }
let!(:project) { create(:project) }
let!(:issue1) { create(:issue, project: project, title: "Issue 1") }
diff --git a/spec/features/issues/create_issue_for_single_discussion_in_merge_request.rb b/spec/features/issues/create_issue_for_single_discussion_in_merge_request_spec.rb
index 88e2cc60d79..3a5a79e03f4 100644
--- a/spec/features/issues/create_issue_for_single_discussion_in_merge_request.rb
+++ b/spec/features/issues/create_issue_for_single_discussion_in_merge_request_spec.rb
@@ -4,7 +4,7 @@ feature 'Resolve an open discussion in a merge request by creating an issue', fe
let(:user) { create(:user) }
let(:project) { create(:project, only_allow_merge_if_all_discussions_are_resolved: true) }
let(:merge_request) { create(:merge_request, source_project: project) }
- let!(:discussion) { Discussion.for_diff_notes([create(:diff_note_on_merge_request, noteable: merge_request, project: project)]).first }
+ let!(:discussion) { create(:diff_note_on_merge_request, noteable: merge_request, project: project).to_discussion }
describe 'As a user with access to the project' do
before do
@@ -74,8 +74,8 @@ feature 'Resolve an open discussion in a merge request by creating an issue', fe
it 'Shows a notice to ask someone else to resolve the discussions' do
expect(page).to have_content("The discussion at #{merge_request.to_reference}"\
- "(discussion #{discussion.first_note.id}) will stay unresolved."\
- "Ask someone with permission to resolve it.")
+ " (discussion #{discussion.first_note.id}) will stay unresolved."\
+ " Ask someone with permission to resolve it.")
end
end
end
diff --git a/spec/features/issues/filtered_search/dropdown_assignee_spec.rb b/spec/features/issues/filtered_search/dropdown_assignee_spec.rb
index 3d1a9ed1722..0b573d7cef4 100644
--- a/spec/features/issues/filtered_search/dropdown_assignee_spec.rb
+++ b/spec/features/issues/filtered_search/dropdown_assignee_spec.rb
@@ -2,7 +2,6 @@ require 'rails_helper'
describe 'Dropdown assignee', :feature, :js do
include FilteredSearchHelpers
- include WaitForAjax
let!(:project) { create(:empty_project) }
let!(:user) { create(:user, name: 'administrator', username: 'root') }
diff --git a/spec/features/issues/filtered_search/dropdown_author_spec.rb b/spec/features/issues/filtered_search/dropdown_author_spec.rb
index 990e3b3e60c..0579d6c80ab 100644
--- a/spec/features/issues/filtered_search/dropdown_author_spec.rb
+++ b/spec/features/issues/filtered_search/dropdown_author_spec.rb
@@ -2,7 +2,6 @@ require 'rails_helper'
describe 'Dropdown author', js: true, feature: true do
include FilteredSearchHelpers
- include WaitForAjax
let!(:project) { create(:empty_project) }
let!(:user) { create(:user, name: 'administrator', username: 'root') }
diff --git a/spec/features/issues/filtered_search/dropdown_hint_spec.rb b/spec/features/issues/filtered_search/dropdown_hint_spec.rb
index cae01f37b6b..b9a37cfcc22 100644
--- a/spec/features/issues/filtered_search/dropdown_hint_spec.rb
+++ b/spec/features/issues/filtered_search/dropdown_hint_spec.rb
@@ -2,7 +2,6 @@ require 'rails_helper'
describe 'Dropdown hint', :js, :feature do
include FilteredSearchHelpers
- include WaitForAjax
let!(:project) { create(:empty_project) }
let!(:user) { create(:user) }
diff --git a/spec/features/issues/filtered_search/filter_issues_spec.rb b/spec/features/issues/filtered_search/filter_issues_spec.rb
index 6f00066de4d..81ee0e2e4f6 100644
--- a/spec/features/issues/filtered_search/filter_issues_spec.rb
+++ b/spec/features/issues/filtered_search/filter_issues_spec.rb
@@ -3,7 +3,6 @@ require 'spec_helper'
describe 'Filter issues', js: true, feature: true do
include Devise::Test::IntegrationHelpers
include FilteredSearchHelpers
- include WaitForAjax
let!(:group) { create(:group) }
let!(:project) { create(:project, group: group) }
diff --git a/spec/features/issues/filtered_search/recent_searches_spec.rb b/spec/features/issues/filtered_search/recent_searches_spec.rb
index f506065a242..08fe3b4553b 100644
--- a/spec/features/issues/filtered_search/recent_searches_spec.rb
+++ b/spec/features/issues/filtered_search/recent_searches_spec.rb
@@ -2,7 +2,6 @@ require 'spec_helper'
describe 'Recent searches', js: true, feature: true do
include FilteredSearchHelpers
- include WaitForAjax
let!(:group) { create(:group) }
let!(:project) { create(:project, group: group) }
diff --git a/spec/features/issues/filtered_search/search_bar_spec.rb b/spec/features/issues/filtered_search/search_bar_spec.rb
index 28137f11b92..3ea95aed0a6 100644
--- a/spec/features/issues/filtered_search/search_bar_spec.rb
+++ b/spec/features/issues/filtered_search/search_bar_spec.rb
@@ -2,7 +2,6 @@ require 'rails_helper'
describe 'Search bar', js: true, feature: true do
include FilteredSearchHelpers
- include WaitForAjax
let!(:project) { create(:empty_project) }
let!(:user) { create(:user) }
diff --git a/spec/features/issues/gfm_autocomplete_spec.rb b/spec/features/issues/gfm_autocomplete_spec.rb
index 7135565294b..b571f6bd861 100644
--- a/spec/features/issues/gfm_autocomplete_spec.rb
+++ b/spec/features/issues/gfm_autocomplete_spec.rb
@@ -1,7 +1,6 @@
require 'rails_helper'
feature 'GFM autocomplete', feature: true, js: true do
- include WaitForAjax
let(:user) { create(:user, name: '💃speciąl someone💃', username: 'someone.special') }
let(:project) { create(:project) }
let(:label) { create(:label, project: project, title: 'special+') }
diff --git a/spec/features/issues/issue_sidebar_spec.rb b/spec/features/issues/issue_sidebar_spec.rb
index 85585587fb1..baacd7edb86 100644
--- a/spec/features/issues/issue_sidebar_spec.rb
+++ b/spec/features/issues/issue_sidebar_spec.rb
@@ -1,7 +1,6 @@
require 'rails_helper'
feature 'Issue Sidebar', feature: true do
- include WaitForAjax
include MobileHelpers
let(:project) { create(:project, :public) }
diff --git a/spec/features/issues/update_issues_spec.rb b/spec/features/issues/update_issues_spec.rb
index ae5da3877a8..7fa83c1fcf7 100644
--- a/spec/features/issues/update_issues_spec.rb
+++ b/spec/features/issues/update_issues_spec.rb
@@ -1,8 +1,6 @@
require 'rails_helper'
feature 'Multiple issue updating from issues#index', feature: true do
- include WaitForAjax
-
let!(:project) { create(:project) }
let!(:issue) { create(:issue, project: project) }
let!(:user) { create(:user)}
diff --git a/spec/features/issues/user_uses_slash_commands_spec.rb b/spec/features/issues/user_uses_slash_commands_spec.rb
index 0a9cd11ad6e..4cd6c1171ac 100644
--- a/spec/features/issues/user_uses_slash_commands_spec.rb
+++ b/spec/features/issues/user_uses_slash_commands_spec.rb
@@ -2,7 +2,6 @@ require 'rails_helper'
feature 'Issues > User uses slash commands', feature: true, js: true do
include SlashCommandsHelpers
- include WaitForAjax
it_behaves_like 'issuable record that supports slash commands in its description and notes', :issue do
let(:issuable) { create(:issue, project: project) }
diff --git a/spec/features/issues_spec.rb b/spec/features/issues_spec.rb
index 362d167befa..81cc8513454 100644
--- a/spec/features/issues_spec.rb
+++ b/spec/features/issues_spec.rb
@@ -4,22 +4,14 @@ describe 'Issues', feature: true do
include DropzoneHelper
include IssueHelpers
include SortingHelper
- include WaitForAjax
- let(:project) { create(:project, :public) }
+ let(:project) { create(:empty_project, :public) }
before do
login_as :user
user2 = create(:user)
project.team << [[@user, user2], :developer]
-
- project.repository.create_file(
- @user,
- '.gitlab/issue_templates/bug.md',
- 'this is a test "bug" template',
- message: 'added issue template',
- branch_name: 'master')
end
describe 'Edit issue' do
@@ -378,7 +370,7 @@ describe 'Issues', feature: true do
end
describe 'when I want to reset my incoming email token' do
- let(:project1) { create(:project, namespace: @user.namespace) }
+ let(:project1) { create(:empty_project, namespace: @user.namespace) }
let!(:issue) { create(:issue, project: project1) }
before do
@@ -414,7 +406,8 @@ describe 'Issues', feature: true do
it 'will not send ajax request when no data is changed' do
page.within '.labels' do
click_link 'Edit'
- first('.dropdown-menu-close').click
+
+ find('.dropdown-menu-close', match: :first).click
expect(page).not_to have_selector('.block-loading')
end
@@ -609,7 +602,16 @@ describe 'Issues', feature: true do
end
context 'form filled by URL parameters' do
+ let(:project) { create(:project, :public, :repository) }
+
before do
+ project.repository.create_file(
+ @user,
+ '.gitlab/issue_templates/bug.md',
+ 'this is a test "bug" template',
+ message: 'added issue template',
+ branch_name: 'master')
+
visit new_namespace_project_issue_path(project.namespace, project, issuable_template: 'bug')
end
diff --git a/spec/features/merge_requests/conflicts_spec.rb b/spec/features/merge_requests/conflicts_spec.rb
index 18508a44184..43977ad2fc5 100644
--- a/spec/features/merge_requests/conflicts_spec.rb
+++ b/spec/features/merge_requests/conflicts_spec.rb
@@ -1,8 +1,6 @@
require 'spec_helper'
feature 'Merge request conflict resolution', js: true, feature: true do
- include WaitForAjax
-
let(:user) { create(:user) }
let(:project) { create(:project) }
diff --git a/spec/features/merge_requests/create_new_mr_spec.rb b/spec/features/merge_requests/create_new_mr_spec.rb
index 3a4ec07b2b0..16b09933bda 100644
--- a/spec/features/merge_requests/create_new_mr_spec.rb
+++ b/spec/features/merge_requests/create_new_mr_spec.rb
@@ -20,13 +20,13 @@ feature 'Create New Merge Request', feature: true, js: true do
expect(page).to have_content('Target branch')
first('.js-source-branch').click
- first('.dropdown-source-branch .dropdown-content a', text: 'v1.1.0').click
+ find('.dropdown-source-branch .dropdown-content a', match: :first).click
expect(page).to have_content "b83d6e3"
end
it 'selects the target branch sha when a tag with the same name exists' do
- visit namespace_project_merge_requests_path(project.namespace, project)
+ visit namespace_project_merge_requests_path(project.namespace, project)
click_link 'New merge request'
@@ -46,8 +46,8 @@ feature 'Create New Merge Request', feature: true, js: true do
expect(page).to have_content('Source branch')
expect(page).to have_content('Target branch')
- first('.js-source-branch').click
- first('.dropdown-source-branch .dropdown-content a', text: 'orphaned-branch').click
+ find('.js-source-branch', match: :first).click
+ find('.dropdown-source-branch .dropdown-content a', text: 'orphaned-branch', match: :first).click
click_button "Compare branches"
click_link "Changes"
diff --git a/spec/features/merge_requests/deleted_source_branch_spec.rb b/spec/features/merge_requests/deleted_source_branch_spec.rb
index 0952b17b63e..648678e2b1a 100644
--- a/spec/features/merge_requests/deleted_source_branch_spec.rb
+++ b/spec/features/merge_requests/deleted_source_branch_spec.rb
@@ -4,8 +4,6 @@ require 'spec_helper'
# message to be shown by JavaScript when the source branch was deleted.
# Please do not remove "js: true".
describe 'Deleted source branch', feature: true, js: true do
- include WaitForAjax
-
let(:user) { create(:user) }
let(:merge_request) { create(:merge_request) }
diff --git a/spec/features/merge_requests/diff_notes_avatars_spec.rb b/spec/features/merge_requests/diff_notes_avatars_spec.rb
index 218d95a88b8..b2e170513c4 100644
--- a/spec/features/merge_requests/diff_notes_avatars_spec.rb
+++ b/spec/features/merge_requests/diff_notes_avatars_spec.rb
@@ -1,8 +1,6 @@
require 'spec_helper'
feature 'Diff note avatars', feature: true, js: true do
- include WaitForAjax
-
let(:user) { create(:user) }
let(:project) { create(:project, :public) }
let(:merge_request) { create(:merge_request_with_diffs, source_project: project, author: user, title: "Bug NS-04") }
diff --git a/spec/features/merge_requests/filter_by_labels_spec.rb b/spec/features/merge_requests/filter_by_labels_spec.rb
index 55f3c1863ff..32a9082b9b9 100644
--- a/spec/features/merge_requests/filter_by_labels_spec.rb
+++ b/spec/features/merge_requests/filter_by_labels_spec.rb
@@ -3,7 +3,6 @@ require 'rails_helper'
feature 'Issue filtering by Labels', feature: true, js: true do
include FilteredSearchHelpers
include MergeRequestHelpers
- include WaitForAjax
let(:project) { create(:project, :public) }
let!(:user) { create(:user) }
diff --git a/spec/features/merge_requests/filter_merge_requests_spec.rb b/spec/features/merge_requests/filter_merge_requests_spec.rb
index 70e3997e716..2da60e9f4ad 100644
--- a/spec/features/merge_requests/filter_merge_requests_spec.rb
+++ b/spec/features/merge_requests/filter_merge_requests_spec.rb
@@ -3,7 +3,6 @@ require 'rails_helper'
describe 'Filter merge requests', feature: true do
include FilteredSearchHelpers
include MergeRequestHelpers
- include WaitForAjax
let!(:project) { create(:project) }
let!(:group) { create(:group) }
diff --git a/spec/features/merge_requests/mini_pipeline_graph_spec.rb b/spec/features/merge_requests/mini_pipeline_graph_spec.rb
index 84ad8765d8f..449a60c1d05 100644
--- a/spec/features/merge_requests/mini_pipeline_graph_spec.rb
+++ b/spec/features/merge_requests/mini_pipeline_graph_spec.rb
@@ -1,8 +1,6 @@
require 'rails_helper'
feature 'Mini Pipeline Graph', :js, :feature do
- include WaitForAjax
-
let(:user) { create(:user) }
let(:project) { create(:project, :public) }
let(:merge_request) { create(:merge_request, source_project: project) }
diff --git a/spec/features/merge_requests/pipelines_spec.rb b/spec/features/merge_requests/pipelines_spec.rb
index 9c4c0525267..99e283ac181 100644
--- a/spec/features/merge_requests/pipelines_spec.rb
+++ b/spec/features/merge_requests/pipelines_spec.rb
@@ -1,8 +1,6 @@
require 'spec_helper'
feature 'Pipelines for Merge Requests', feature: true, js: true do
- include WaitForAjax
-
given(:user) { create(:user) }
given(:merge_request) { create(:merge_request) }
given(:project) { merge_request.target_project }
diff --git a/spec/features/merge_requests/reset_filters_spec.rb b/spec/features/merge_requests/reset_filters_spec.rb
index df5943f9136..275f81f50dc 100644
--- a/spec/features/merge_requests/reset_filters_spec.rb
+++ b/spec/features/merge_requests/reset_filters_spec.rb
@@ -3,7 +3,6 @@ require 'rails_helper'
feature 'Merge requests filter clear button', feature: true, js: true do
include FilteredSearchHelpers
include MergeRequestHelpers
- include WaitForAjax
include IssueHelpers
let!(:project) { create(:project, :public) }
diff --git a/spec/features/merge_requests/update_merge_requests_spec.rb b/spec/features/merge_requests/update_merge_requests_spec.rb
index b56fdfe5611..9ecc998785b 100644
--- a/spec/features/merge_requests/update_merge_requests_spec.rb
+++ b/spec/features/merge_requests/update_merge_requests_spec.rb
@@ -1,8 +1,6 @@
require 'rails_helper'
feature 'Multiple merge requests updating from merge_requests#index', feature: true do
- include WaitForAjax
-
let!(:user) { create(:user)}
let!(:project) { create(:project) }
let!(:merge_request) { create(:merge_request, source_project: project, target_project: project) }
diff --git a/spec/features/merge_requests/user_posts_notes.rb b/spec/features/merge_requests/user_posts_notes_spec.rb
index c7cc4d6bc72..c7cc4d6bc72 100644
--- a/spec/features/merge_requests/user_posts_notes.rb
+++ b/spec/features/merge_requests/user_posts_notes_spec.rb
diff --git a/spec/features/merge_requests/user_uses_slash_commands_spec.rb b/spec/features/merge_requests/user_uses_slash_commands_spec.rb
index a1f4eb2688b..1c0f21e5616 100644
--- a/spec/features/merge_requests/user_uses_slash_commands_spec.rb
+++ b/spec/features/merge_requests/user_uses_slash_commands_spec.rb
@@ -2,7 +2,6 @@ require 'rails_helper'
feature 'Merge Requests > User uses slash commands', feature: true, js: true do
include SlashCommandsHelpers
- include WaitForAjax
let(:user) { create(:user) }
let(:project) { create(:project, :public) }
diff --git a/spec/features/merge_requests/versions_spec.rb b/spec/features/merge_requests/versions_spec.rb
index 68a68f5d3f3..7a2da623c58 100644
--- a/spec/features/merge_requests/versions_spec.rb
+++ b/spec/features/merge_requests/versions_spec.rb
@@ -107,14 +107,13 @@ feature 'Merge Request versions', js: true, feature: true do
it 'should have 0 chages between versions' do
page.within '.mr-version-compare-dropdown' do
- expect(page).to have_content 'version 1'
+ expect(find('.dropdown-toggle')).to have_content 'version 1'
end
page.within '.mr-version-dropdown' do
find('.btn-default').click
- find(:link, 'version 1').trigger('click')
+ click_link 'version 1'
end
-
expect(page).to have_content '0 changed files'
end
end
@@ -129,12 +128,12 @@ feature 'Merge Request versions', js: true, feature: true do
it 'should set the compared versions to be the same' do
page.within '.mr-version-compare-dropdown' do
- expect(page).to have_content 'version 2'
+ expect(find('.dropdown-toggle')).to have_content 'version 2'
end
page.within '.mr-version-dropdown' do
find('.btn-default').click
- find(:link, 'version 1').trigger('click')
+ click_link 'version 1'
end
page.within '.mr-version-compare-dropdown' do
diff --git a/spec/features/merge_requests/widget_deployments_spec.rb b/spec/features/merge_requests/widget_deployments_spec.rb
index 6676821b807..00d191ddf2c 100644
--- a/spec/features/merge_requests/widget_deployments_spec.rb
+++ b/spec/features/merge_requests/widget_deployments_spec.rb
@@ -1,8 +1,6 @@
require 'spec_helper'
feature 'Widget Deployments Header', feature: true, js: true do
- include WaitForAjax
-
describe 'when deployed to an environment' do
given(:user) { create(:user) }
given(:project) { merge_request.target_project }
diff --git a/spec/features/merge_requests/widget_spec.rb b/spec/features/merge_requests/widget_spec.rb
index 4e128cd4a7d..d918181a238 100644
--- a/spec/features/merge_requests/widget_spec.rb
+++ b/spec/features/merge_requests/widget_spec.rb
@@ -1,8 +1,6 @@
require 'rails_helper'
describe 'Merge request', :feature, :js do
- include WaitForAjax
-
let(:user) { create(:user) }
let(:project) { create(:project) }
let(:merge_request) { create(:merge_request, source_project: project) }
diff --git a/spec/features/milestone_spec.rb b/spec/features/milestone_spec.rb
index c3297de709a..c07de01c594 100644
--- a/spec/features/milestone_spec.rb
+++ b/spec/features/milestone_spec.rb
@@ -1,8 +1,6 @@
require 'rails_helper'
feature 'Milestone', feature: true do
- include WaitForAjax
-
let(:project) { create(:empty_project, :public) }
let(:user) { create(:user) }
diff --git a/spec/features/milestones/milestones_spec.rb b/spec/features/milestones/milestones_spec.rb
index 2fa3e72ab08..50d7ca39045 100644
--- a/spec/features/milestones/milestones_spec.rb
+++ b/spec/features/milestones/milestones_spec.rb
@@ -1,7 +1,6 @@
require 'rails_helper'
describe 'Milestone draggable', feature: true, js: true do
- include WaitForAjax
include DragTo
let(:milestone) { create(:milestone, project: project, title: 8.14) }
diff --git a/spec/features/participants_autocomplete_spec.rb b/spec/features/participants_autocomplete_spec.rb
index decad589c23..449ce80bc71 100644
--- a/spec/features/participants_autocomplete_spec.rb
+++ b/spec/features/participants_autocomplete_spec.rb
@@ -1,7 +1,7 @@
require 'spec_helper'
feature 'Member autocomplete', :js do
- let(:project) { create(:project, :public) }
+ let(:project) { create(:empty_project, :public) }
let(:user) { create(:user) }
let(:author) { create(:user) }
let(:note) { create(:note, noteable: noteable, project: noteable.project) }
@@ -36,6 +36,7 @@ feature 'Member autocomplete', :js do
end
context 'adding a new note on a Merge Request' do
+ let(:project) { create(:project, :public, :repository) }
let(:noteable) do
create(:merge_request, source_project: project,
target_project: project, author: author)
@@ -48,6 +49,7 @@ feature 'Member autocomplete', :js do
end
context 'adding a new note on a Commit' do
+ let(:project) { create(:project, :public, :repository) }
let(:noteable) { project.commit }
let(:note) { create(:note_on_commit, project: project, commit_id: project.commit.id) }
diff --git a/spec/features/projects/blobs/blob_show_spec.rb b/spec/features/projects/blobs/blob_show_spec.rb
index 01cd268ffe8..7cfa5b9716f 100644
--- a/spec/features/projects/blobs/blob_show_spec.rb
+++ b/spec/features/projects/blobs/blob_show_spec.rb
@@ -1,7 +1,6 @@
require 'spec_helper'
feature 'File blob', feature: true do
- include WaitForAjax
include TreeHelper
let(:project) { create(:project, :public, :test_repo) }
diff --git a/spec/features/projects/blobs/edit_spec.rb b/spec/features/projects/blobs/edit_spec.rb
index aab5a72678e..cc5b1a7e734 100644
--- a/spec/features/projects/blobs/edit_spec.rb
+++ b/spec/features/projects/blobs/edit_spec.rb
@@ -1,7 +1,6 @@
require 'spec_helper'
feature 'Editing file blob', feature: true, js: true do
- include WaitForAjax
include TreeHelper
let(:project) { create(:project, :public, :test_repo) }
diff --git a/spec/features/projects/blobs/user_create_spec.rb b/spec/features/projects/blobs/user_create_spec.rb
index 6ea149956fe..d805450e095 100644
--- a/spec/features/projects/blobs/user_create_spec.rb
+++ b/spec/features/projects/blobs/user_create_spec.rb
@@ -1,7 +1,6 @@
require 'spec_helper'
feature 'New blob creation', feature: true, js: true do
- include WaitForAjax
include TargetBranchHelpers
given(:user) { create(:user) }
diff --git a/spec/features/projects/commit/cherry_pick_spec.rb b/spec/features/projects/commit/cherry_pick_spec.rb
index 0b972d2a439..5d64d42fd61 100644
--- a/spec/features/projects/commit/cherry_pick_spec.rb
+++ b/spec/features/projects/commit/cherry_pick_spec.rb
@@ -1,5 +1,4 @@
require 'spec_helper'
-include WaitForAjax
describe 'Cherry-pick Commits' do
let(:group) { create(:group) }
diff --git a/spec/features/projects/commit/mini_pipeline_graph_spec.rb b/spec/features/projects/commit/mini_pipeline_graph_spec.rb
index 30a2b2bcf8c..98c0f2c63b0 100644
--- a/spec/features/projects/commit/mini_pipeline_graph_spec.rb
+++ b/spec/features/projects/commit/mini_pipeline_graph_spec.rb
@@ -1,8 +1,6 @@
require 'rails_helper'
feature 'Mini Pipeline Graph in Commit View', :js, :feature do
- include WaitForAjax
-
let(:user) { create(:user) }
let(:project) { create(:project, :public) }
diff --git a/spec/features/projects/edit_spec.rb b/spec/features/projects/edit_spec.rb
index 7c319af893b..a263781c43c 100644
--- a/spec/features/projects/edit_spec.rb
+++ b/spec/features/projects/edit_spec.rb
@@ -1,8 +1,6 @@
require 'rails_helper'
feature 'Project edit', feature: true, js: true do
- include WaitForAjax
-
let(:user) { create(:user) }
let(:project) { create(:project) }
diff --git a/spec/features/projects/features_visibility_spec.rb b/spec/features/projects/features_visibility_spec.rb
index 9079350186d..b080a8d500e 100644
--- a/spec/features/projects/features_visibility_spec.rb
+++ b/spec/features/projects/features_visibility_spec.rb
@@ -1,9 +1,6 @@
require 'spec_helper'
-include WaitForAjax
describe 'Edit Project Settings', feature: true do
- include WaitForAjax
-
let(:member) { create(:user) }
let!(:project) { create(:project, :public, path: 'gitlab', name: 'sample') }
let!(:issue) { create(:issue, project: project) }
diff --git a/spec/features/projects/files/creating_a_file_spec.rb b/spec/features/projects/files/creating_a_file_spec.rb
index de6905f2b58..69744ac3948 100644
--- a/spec/features/projects/files/creating_a_file_spec.rb
+++ b/spec/features/projects/files/creating_a_file_spec.rb
@@ -1,8 +1,6 @@
require 'spec_helper'
feature 'User wants to create a file', feature: true do
- include WaitForAjax
-
let(:project) { create(:project) }
let(:user) { create(:user) }
diff --git a/spec/features/projects/files/dockerfile_dropdown_spec.rb b/spec/features/projects/files/dockerfile_dropdown_spec.rb
index 32f33a3ca97..a7cc98a2059 100644
--- a/spec/features/projects/files/dockerfile_dropdown_spec.rb
+++ b/spec/features/projects/files/dockerfile_dropdown_spec.rb
@@ -1,8 +1,6 @@
require 'spec_helper'
feature 'User wants to add a Dockerfile file', feature: true do
- include WaitForAjax
-
before do
user = create(:user)
project = create(:project)
diff --git a/spec/features/projects/files/editing_a_file_spec.rb b/spec/features/projects/files/editing_a_file_spec.rb
index 4da34108b46..7a3afafec29 100644
--- a/spec/features/projects/files/editing_a_file_spec.rb
+++ b/spec/features/projects/files/editing_a_file_spec.rb
@@ -1,8 +1,6 @@
require 'spec_helper'
feature 'User wants to edit a file', feature: true do
- include WaitForAjax
-
let(:project) { create(:project) }
let(:user) { create(:user) }
let(:commit_params) do
diff --git a/spec/features/projects/files/files_sort_submodules_with_folders_spec.rb b/spec/features/projects/files/files_sort_submodules_with_folders_spec.rb
index 10b91d8990b..5c8105de4cb 100644
--- a/spec/features/projects/files/files_sort_submodules_with_folders_spec.rb
+++ b/spec/features/projects/files/files_sort_submodules_with_folders_spec.rb
@@ -1,8 +1,6 @@
require 'spec_helper'
feature 'User views files page', feature: true do
- include WaitForAjax
-
let(:user) { create(:user) }
let(:project) { create(:forked_project_with_submodules) }
diff --git a/spec/features/projects/files/find_file_keyboard_spec.rb b/spec/features/projects/files/find_file_keyboard_spec.rb
index 582349d8d5b..e7a6749d8ac 100644
--- a/spec/features/projects/files/find_file_keyboard_spec.rb
+++ b/spec/features/projects/files/find_file_keyboard_spec.rb
@@ -1,8 +1,6 @@
require 'spec_helper'
feature 'Find file keyboard shortcuts', feature: true, js: true do
- include WaitForAjax
-
let(:user) { create(:user) }
let(:project) { create(:project) }
diff --git a/spec/features/projects/files/gitignore_dropdown_spec.rb b/spec/features/projects/files/gitignore_dropdown_spec.rb
index 9ebef505b92..e59428f8b24 100644
--- a/spec/features/projects/files/gitignore_dropdown_spec.rb
+++ b/spec/features/projects/files/gitignore_dropdown_spec.rb
@@ -1,8 +1,6 @@
require 'spec_helper'
feature 'User wants to add a .gitignore file', feature: true do
- include WaitForAjax
-
before do
user = create(:user)
project = create(:project)
diff --git a/spec/features/projects/files/gitlab_ci_yml_dropdown_spec.rb b/spec/features/projects/files/gitlab_ci_yml_dropdown_spec.rb
index fca40f68b01..85b66b93fba 100644
--- a/spec/features/projects/files/gitlab_ci_yml_dropdown_spec.rb
+++ b/spec/features/projects/files/gitlab_ci_yml_dropdown_spec.rb
@@ -1,8 +1,6 @@
require 'spec_helper'
feature 'User wants to add a .gitlab-ci.yml file', feature: true do
- include WaitForAjax
-
before do
user = create(:user)
project = create(:project)
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 8ff0f5898ec..249830921ac 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
@@ -1,8 +1,6 @@
require 'spec_helper'
feature 'project owner creates a license file', feature: true, js: true do
- include WaitForAjax
-
let(:project_master) { create(:user) }
let(:project) { create(:project) }
background do
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 1a1910455a1..70a41886985 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
@@ -1,8 +1,6 @@
require 'spec_helper'
feature 'project owner sees a link to create a license file in empty project', feature: true, js: true do
- include WaitForAjax
-
let(:project_master) { create(:user) }
let(:project) { create(:empty_project) }
background do
diff --git a/spec/features/projects/files/undo_template_spec.rb b/spec/features/projects/files/undo_template_spec.rb
index c51851d3f94..cd3af0b7d29 100644
--- a/spec/features/projects/files/undo_template_spec.rb
+++ b/spec/features/projects/files/undo_template_spec.rb
@@ -1,26 +1,25 @@
require 'spec_helper'
-include WaitForAjax
-feature 'Template Undo Button', js: true do
+feature 'Template Undo Button', js: true do
let(:project) { create(:project) }
let(:user) { create(:user) }
before do
project.team << [user, :master]
- login_as user
+ login_as user
end
-
- context 'editing a matching file and applying a template' do
+
+ context 'editing a matching file and applying a template' do
before do
- visit namespace_project_edit_blob_path(project.namespace, project, File.join(project.default_branch, "LICENSE"))
+ visit namespace_project_edit_blob_path(project.namespace, project, File.join(project.default_branch, "LICENSE"))
select_file_template('.js-license-selector', 'Apache License 2.0')
end
-
+
scenario 'reverts template application' do
try_template_undo('http://www.apache.org/licenses/', 'Apply a license template')
end
end
-
+
context 'creating a non-matching file' do
before do
visit namespace_project_new_blob_path(project.namespace, project, 'master')
diff --git a/spec/features/projects/issuable_templates_spec.rb b/spec/features/projects/issuable_templates_spec.rb
index 62d0aedda48..d28a853bbc2 100644
--- a/spec/features/projects/issuable_templates_spec.rb
+++ b/spec/features/projects/issuable_templates_spec.rb
@@ -1,8 +1,6 @@
require 'spec_helper'
feature 'issuable templates', feature: true, js: true do
- include WaitForAjax
-
let(:user) { create(:user) }
let(:project) { create(:project, :public) }
@@ -163,12 +161,14 @@ feature 'issuable templates', feature: true, js: true do
end
def select_template(name)
- first('.js-issuable-selector').click
- first('.js-issuable-selector-wrap .dropdown-content a', text: name).click
+ find('.js-issuable-selector').click
+
+ find('.js-issuable-selector-wrap .dropdown-content a', text: name, match: :first).click
end
def select_option(name)
- first('.js-issuable-selector').click
- first('.js-issuable-selector-wrap .dropdown-footer-list a', text: name).click
+ find('.js-issuable-selector').click
+
+ find('.js-issuable-selector-wrap .dropdown-footer-list a', text: name, match: :first).click
end
end
diff --git a/spec/features/projects/labels/update_prioritization_spec.rb b/spec/features/projects/labels/update_prioritization_spec.rb
index 1e900d7e660..836f81fb16d 100644
--- a/spec/features/projects/labels/update_prioritization_spec.rb
+++ b/spec/features/projects/labels/update_prioritization_spec.rb
@@ -1,7 +1,6 @@
require 'spec_helper'
feature 'Prioritize labels', feature: true do
- include WaitForAjax
include DragTo
let(:user) { create(:user) }
diff --git a/spec/features/projects/members/group_links_spec.rb b/spec/features/projects/members/group_links_spec.rb
index cffb935ad5a..ab2b089db2e 100644
--- a/spec/features/projects/members/group_links_spec.rb
+++ b/spec/features/projects/members/group_links_spec.rb
@@ -1,8 +1,6 @@
require 'spec_helper'
feature 'Projects > Members > Anonymous user sees members', feature: true, js: true do
- include WaitForAjax
-
let(:user) { create(:user) }
let(:group) { create(:group, :public) }
let(:project) { create(:empty_project, :public) }
diff --git a/spec/features/projects/members/master_adds_member_with_expiration_date_spec.rb b/spec/features/projects/members/master_adds_member_with_expiration_date_spec.rb
index c3f45be6e4b..19d14ad9af4 100644
--- a/spec/features/projects/members/master_adds_member_with_expiration_date_spec.rb
+++ b/spec/features/projects/members/master_adds_member_with_expiration_date_spec.rb
@@ -1,7 +1,6 @@
require 'spec_helper'
feature 'Projects > Members > Master adds member with expiration date', feature: true, js: true do
- include WaitForAjax
include Select2Helper
include ActiveSupport::Testing::TimeHelpers
diff --git a/spec/features/projects/members/user_requests_access_spec.rb b/spec/features/projects/members/user_requests_access_spec.rb
index de25d45f447..1bf8f710b9f 100644
--- a/spec/features/projects/members/user_requests_access_spec.rb
+++ b/spec/features/projects/members/user_requests_access_spec.rb
@@ -31,6 +31,17 @@ feature 'Projects > Members > User requests access', feature: true do
expect(page).not_to have_content 'Leave Project'
end
+ context 'code access is restricted' do
+ scenario 'user can request access' do
+ project.project_feature.update!(repository_access_level: ProjectFeature::PRIVATE,
+ builds_access_level: ProjectFeature::PRIVATE,
+ merge_requests_access_level: ProjectFeature::PRIVATE)
+ visit namespace_project_path(project.namespace, project)
+
+ expect(page).to have_content 'Request Access'
+ end
+ end
+
scenario 'user is not listed in the project members page' do
click_link 'Request Access'
diff --git a/spec/features/projects/ref_switcher_spec.rb b/spec/features/projects/ref_switcher_spec.rb
index 3b8f0b2d3f8..881ad7910dd 100644
--- a/spec/features/projects/ref_switcher_spec.rb
+++ b/spec/features/projects/ref_switcher_spec.rb
@@ -1,7 +1,6 @@
require 'rails_helper'
feature 'Ref switcher', feature: true, js: true do
- include WaitForAjax
let(:user) { create(:user) }
let(:project) { create(:project, :public) }
diff --git a/spec/features/projects/user_create_dir_spec.rb b/spec/features/projects/user_create_dir_spec.rb
index 2065abfb248..5dfdc465d7d 100644
--- a/spec/features/projects/user_create_dir_spec.rb
+++ b/spec/features/projects/user_create_dir_spec.rb
@@ -1,7 +1,6 @@
require 'spec_helper'
feature 'New directory creation', feature: true, js: true do
- include WaitForAjax
include TargetBranchHelpers
given(:user) { create(:user) }
diff --git a/spec/features/projects/view_on_env_spec.rb b/spec/features/projects/view_on_env_spec.rb
index 34c6a10950f..b7a41ca54e6 100644
--- a/spec/features/projects/view_on_env_spec.rb
+++ b/spec/features/projects/view_on_env_spec.rb
@@ -1,8 +1,6 @@
require 'spec_helper'
describe 'View on environment', js: true do
- include WaitForAjax
-
let(:branch_name) { 'feature' }
let(:file_path) { 'files/ruby/feature.rb' }
let(:project) { create(:project, :repository) }
diff --git a/spec/features/projects_spec.rb b/spec/features/projects_spec.rb
index ba56030e28d..060e19596ae 100644
--- a/spec/features/projects_spec.rb
+++ b/spec/features/projects_spec.rb
@@ -2,7 +2,7 @@ require 'spec_helper'
feature 'Project', feature: true do
describe 'description' do
- let(:project) { create(:project) }
+ let(:project) { create(:project, :repository) }
let(:path) { namespace_project_path(project.namespace, project) }
before do
@@ -36,7 +36,7 @@ feature 'Project', feature: true do
describe 'remove forked relationship', js: true do
let(:user) { create(:user) }
- let(:project) { create(:project, namespace: user.namespace) }
+ let(:project) { create(:empty_project, namespace: user.namespace) }
before do
login_with user
@@ -57,7 +57,7 @@ feature 'Project', feature: true do
describe 'removal', js: true do
let(:user) { create(:user, username: 'test', name: 'test') }
- let(:project) { create(:project, namespace: user.namespace, name: 'project1') }
+ let(:project) { create(:empty_project, namespace: user.namespace, name: 'project1') }
before do
login_with(user)
@@ -75,10 +75,8 @@ feature 'Project', feature: true do
end
describe 'project title' do
- include WaitForAjax
-
let(:user) { create(:user) }
- let(:project) { create(:project, namespace: user.namespace) }
+ let(:project) { create(:empty_project, namespace: user.namespace) }
before do
login_with(user)
@@ -94,8 +92,8 @@ feature 'Project', feature: true do
describe 'project title' do
let(:user) { create(:user) }
- let(:project) { create(:project, namespace: user.namespace) }
- let(:project2) { create(:project, namespace: user.namespace, path: 'test') }
+ let(:project) { create(:empty_project, namespace: user.namespace) }
+ let(:project2) { create(:empty_project, namespace: user.namespace, path: 'test') }
let(:issue) { create(:issue, project: project) }
context 'on issues page', js: true do
diff --git a/spec/features/protected_branches_spec.rb b/spec/features/protected_branches_spec.rb
index 1a3f7b970f6..acc5641f930 100644
--- a/spec/features/protected_branches_spec.rb
+++ b/spec/features/protected_branches_spec.rb
@@ -2,10 +2,8 @@ require 'spec_helper'
Dir["./spec/features/protected_branches/*.rb"].sort.each { |f| require f }
feature 'Projected Branches', feature: true, js: true do
- include WaitForAjax
-
let(:user) { create(:user, :admin) }
- let(:project) { create(:project) }
+ let(:project) { create(:project, :repository) }
before { login_as(user) }
diff --git a/spec/features/protected_tags_spec.rb b/spec/features/protected_tags_spec.rb
index 09e8c850de3..e3aa87ded28 100644
--- a/spec/features/protected_tags_spec.rb
+++ b/spec/features/protected_tags_spec.rb
@@ -2,10 +2,8 @@ require 'spec_helper'
Dir["./spec/features/protected_tags/*.rb"].sort.each { |f| require f }
feature 'Projected Tags', feature: true, js: true do
- include WaitForAjax
-
let(:user) { create(:user, :admin) }
- let(:project) { create(:project) }
+ let(:project) { create(:project, :repository) }
before { login_as(user) }
diff --git a/spec/features/search_spec.rb b/spec/features/search_spec.rb
index e8ad28a00f0..da6388dcdf2 100644
--- a/spec/features/search_spec.rb
+++ b/spec/features/search_spec.rb
@@ -2,10 +2,9 @@ require 'spec_helper'
describe "Search", feature: true do
include FilteredSearchHelpers
- include WaitForAjax
let(:user) { create(:user) }
- let(:project) { create(:project, namespace: user.namespace) }
+ let(:project) { create(:empty_project, namespace: user.namespace) }
let!(:issue) { create(:issue, project: project, assignee: user) }
let!(:issue2) { create(:issue, project: project, author: user) }
@@ -62,6 +61,7 @@ describe "Search", feature: true do
context 'search for comments' do
context 'when comment belongs to a invalid commit' do
+ let(:project) { create(:project, :repository) }
let(:note) { create(:note_on_commit, author: user, project: project, commit_id: project.repository.commit.id, note: 'Bug here') }
before { note.update_attributes(commit_id: 12345678) }
@@ -103,6 +103,7 @@ describe "Search", feature: true do
end
it 'finds a commit' do
+ project = create(:project, :repository) { |p| p.add_reporter(user) }
visit namespace_project_path(project.namespace, project)
page.within '.search' do
@@ -116,6 +117,7 @@ describe "Search", feature: true do
end
it 'finds a code' do
+ project = create(:project, :repository) { |p| p.add_reporter(user) }
visit namespace_project_path(project.namespace, project)
page.within '.search' do
@@ -222,6 +224,8 @@ describe "Search", feature: true do
end
describe 'search for commits' do
+ let(:project) { create(:project, :repository) }
+
before do
visit search_path(project_id: project.id)
end
diff --git a/spec/features/task_lists_spec.rb b/spec/features/task_lists_spec.rb
index a5d14aa19f1..c33692fc4a9 100644
--- a/spec/features/task_lists_spec.rb
+++ b/spec/features/task_lists_spec.rb
@@ -3,7 +3,7 @@ require 'spec_helper'
feature 'Task Lists', feature: true do
include Warden::Test::Helpers
- let(:project) { create(:project) }
+ let(:project) { create(:empty_project) }
let(:user) { create(:user) }
let(:user2) { create(:user) }
@@ -240,6 +240,7 @@ feature 'Task Lists', feature: true do
end
describe 'multiple tasks' do
+ let(:project) { create(:project, :repository) }
let!(:merge) { create(:merge_request, :simple, description: markdown, author: user, source_project: project) }
it 'renders for description' do
diff --git a/spec/features/todos/todos_filtering_spec.rb b/spec/features/todos/todos_filtering_spec.rb
index e8f06916d53..cecb98641a6 100644
--- a/spec/features/todos/todos_filtering_spec.rb
+++ b/spec/features/todos/todos_filtering_spec.rb
@@ -1,8 +1,6 @@
require 'spec_helper'
describe 'Dashboard > User filters todos', feature: true, js: true do
- include WaitForAjax
-
let(:user_1) { create(:user, username: 'user_1', name: 'user_1') }
let(:user_2) { create(:user, username: 'user_2', name: 'user_2') }
diff --git a/spec/features/todos/todos_spec.rb b/spec/features/todos/todos_spec.rb
index c270511c903..50c207fb9cb 100644
--- a/spec/features/todos/todos_spec.rb
+++ b/spec/features/todos/todos_spec.rb
@@ -1,8 +1,6 @@
require 'spec_helper'
describe 'Dashboard Todos', feature: true do
- include WaitForAjax
-
let(:user) { create(:user) }
let(:author) { create(:user) }
let(:project) { create(:project, visibility_level: Gitlab::VisibilityLevel::PUBLIC) }
diff --git a/spec/features/u2f_spec.rb b/spec/features/u2f_spec.rb
index c877cfdd978..544d2dcb87f 100644
--- a/spec/features/u2f_spec.rb
+++ b/spec/features/u2f_spec.rb
@@ -1,8 +1,6 @@
require 'spec_helper'
feature 'Using U2F (Universal 2nd Factor) Devices for Authentication', :js do
- include WaitForAjax
-
before { allow_any_instance_of(U2fHelper).to receive(:inject_u2f_api?).and_return(true) }
def manage_two_factor_authentication
diff --git a/spec/features/users/projects_spec.rb b/spec/features/users/projects_spec.rb
index 1d75fe434b0..373b64808f8 100644
--- a/spec/features/users/projects_spec.rb
+++ b/spec/features/users/projects_spec.rb
@@ -1,8 +1,6 @@
require 'spec_helper'
describe 'Projects tab on a user profile', :feature, :js do
- include WaitForAjax
-
let(:user) { create(:user) }
let!(:project) { create(:empty_project, namespace: user.namespace) }
let!(:project2) { create(:empty_project, namespace: user.namespace) }
diff --git a/spec/features/users/snippets_spec.rb b/spec/features/users/snippets_spec.rb
index ce7e809ec76..1546a06b80c 100644
--- a/spec/features/users/snippets_spec.rb
+++ b/spec/features/users/snippets_spec.rb
@@ -1,8 +1,6 @@
require 'spec_helper'
describe 'Snippets tab on a user profile', feature: true, js: true do
- include WaitForAjax
-
context 'when the user has snippets' do
let(:user) { create(:user) }
let!(:snippets) { create_list(:snippet, 2, :public, author: user) }
diff --git a/spec/features/users_spec.rb b/spec/features/users_spec.rb
index 2de0fbe7ab2..c43feadc808 100644
--- a/spec/features/users_spec.rb
+++ b/spec/features/users_spec.rb
@@ -68,7 +68,6 @@ feature 'Users', feature: true, js: true do
end
feature 'username validation' do
- include WaitForAjax
let(:loading_icon) { '.fa.fa-spinner' }
let(:username_input) { 'new_user_username' }
diff --git a/spec/features/variables_spec.rb b/spec/features/variables_spec.rb
index a362d6fd3b6..b83a230c1f8 100644
--- a/spec/features/variables_spec.rb
+++ b/spec/features/variables_spec.rb
@@ -2,7 +2,7 @@ require 'spec_helper'
describe 'Project variables', js: true do
let(:user) { create(:user) }
- let(:project) { create(:project) }
+ let(:project) { create(:empty_project) }
let(:variable) { create(:ci_variable, key: 'test_key', value: 'test value') }
before do
diff --git a/spec/helpers/ci_status_helper_spec.rb b/spec/helpers/ci_status_helper_spec.rb
index c795fe5a2a3..3dc13001056 100644
--- a/spec/helpers/ci_status_helper_spec.rb
+++ b/spec/helpers/ci_status_helper_spec.rb
@@ -6,25 +6,54 @@ describe CiStatusHelper do
let(:success_commit) { double("Ci::Pipeline", status: 'success') }
let(:failed_commit) { double("Ci::Pipeline", status: 'failed') }
- describe 'ci_icon_for_status' do
+ describe '#ci_icon_for_status' do
it 'renders to correct svg on success' do
- expect(helper).to receive(:render).with('shared/icons/icon_status_success.svg', anything)
+ expect(helper).to receive(:render)
+ .with('shared/icons/icon_status_success.svg', anything)
+
helper.ci_icon_for_status(success_commit.status)
end
+
it 'renders the correct svg on failure' do
- expect(helper).to receive(:render).with('shared/icons/icon_status_failed.svg', anything)
+ expect(helper).to receive(:render)
+ .with('shared/icons/icon_status_failed.svg', anything)
+
helper.ci_icon_for_status(failed_commit.status)
end
end
+ describe '#ci_text_for_status' do
+ context 'when status is manual' do
+ it 'changes the status to blocked' do
+ expect(helper.ci_text_for_status('manual'))
+ .to eq 'blocked'
+ end
+ end
+
+ context 'when status is success' do
+ it 'changes the status to passed' do
+ expect(helper.ci_text_for_status('success'))
+ .to eq 'passed'
+ end
+ end
+
+ context 'when status is something else' do
+ it 'returns status unchanged' do
+ expect(helper.ci_text_for_status('some-status'))
+ .to eq 'some-status'
+ end
+ end
+ end
+
describe "#pipeline_status_cache_key" do
+ let(:pipeline_status) do
+ Gitlab::Cache::Ci::ProjectPipelineStatus
+ .new(build(:project), sha: '123abc', status: 'success')
+ end
+
it "builds a cache key for pipeline status" do
- pipeline_status = Gitlab::Cache::Ci::ProjectPipelineStatus.new(
- build(:project),
- sha: "123abc",
- status: "success"
- )
- expect(helper.pipeline_status_cache_key(pipeline_status)).to eq("pipeline-status/123abc-success")
+ expect(helper.pipeline_status_cache_key(pipeline_status))
+ .to eq("pipeline-status/123abc-success")
end
end
end
diff --git a/spec/helpers/icons_helper_spec.rb b/spec/helpers/icons_helper_spec.rb
index c052981fe73..91c8faea7fd 100644
--- a/spec/helpers/icons_helper_spec.rb
+++ b/spec/helpers/icons_helper_spec.rb
@@ -1,6 +1,21 @@
require 'spec_helper'
describe IconsHelper do
+ describe 'icon' do
+ it 'returns aria-hidden by default' do
+ star = icon('star')
+
+ expect(star['aria-hidden']).to eq 'aria-hidden'
+ end
+
+ it 'does not return aria-hidden if aria-label is set' do
+ up = icon('up', 'aria-label' => 'up')
+
+ expect(up['aria-hidden']).to be_nil
+ expect(up['aria-label']).to eq 'aria-label'
+ end
+ end
+
describe 'file_type_icon_class' do
it 'returns folder class' do
expect(file_type_icon_class('folder', 0, 'folder_name')).to eq 'folder'
diff --git a/spec/helpers/submodule_helper_spec.rb b/spec/helpers/submodule_helper_spec.rb
index 28b8def331d..345bc33a67b 100644
--- a/spec/helpers/submodule_helper_spec.rb
+++ b/spec/helpers/submodule_helper_spec.rb
@@ -70,10 +70,12 @@ describe SubmoduleHelper do
expect(submodule_links(submodule_item)).to eq(['https://github.com/gitlab-org/gitlab-ce', 'https://github.com/gitlab-org/gitlab-ce/tree/hash'])
end
- it 'returns original with non-standard url' do
+ it 'handles urls with no .git on the end' do
stub_url('http://github.com/gitlab-org/gitlab-ce')
- expect(submodule_links(submodule_item)).to eq([repo.submodule_url_for, nil])
+ expect(submodule_links(submodule_item)).to eq(['https://github.com/gitlab-org/gitlab-ce', 'https://github.com/gitlab-org/gitlab-ce/tree/hash'])
+ end
+ it 'returns original with non-standard url' do
stub_url('http://github.com/another/gitlab-org/gitlab-ce.git')
expect(submodule_links(submodule_item)).to eq([repo.submodule_url_for, nil])
end
@@ -95,10 +97,12 @@ describe SubmoduleHelper do
expect(submodule_links(submodule_item)).to eq(['https://gitlab.com/gitlab-org/gitlab-ce', 'https://gitlab.com/gitlab-org/gitlab-ce/tree/hash'])
end
- it 'returns original with non-standard url' do
+ it 'handles urls with no .git on the end' do
stub_url('http://gitlab.com/gitlab-org/gitlab-ce')
- expect(submodule_links(submodule_item)).to eq([repo.submodule_url_for, nil])
+ expect(submodule_links(submodule_item)).to eq(['https://gitlab.com/gitlab-org/gitlab-ce', 'https://gitlab.com/gitlab-org/gitlab-ce/tree/hash'])
+ end
+ it 'returns original with non-standard url' do
stub_url('http://gitlab.com/another/gitlab-org/gitlab-ce.git')
expect(submodule_links(submodule_item)).to eq([repo.submodule_url_for, nil])
end
diff --git a/spec/javascripts/blob/blob_fork_suggestion_spec.js b/spec/javascripts/blob/blob_fork_suggestion_spec.js
index d0d64d75957..d1ab0a32f85 100644
--- a/spec/javascripts/blob/blob_fork_suggestion_spec.js
+++ b/spec/javascripts/blob/blob_fork_suggestion_spec.js
@@ -3,20 +3,21 @@ import BlobForkSuggestion from '~/blob/blob_fork_suggestion';
describe('BlobForkSuggestion', () => {
let blobForkSuggestion;
- const openButtons = [document.createElement('div')];
- const forkButtons = [document.createElement('a')];
- const cancelButtons = [document.createElement('div')];
- const suggestionSections = [document.createElement('div')];
- const actionTextPieces = [document.createElement('div')];
+ const openButton = document.createElement('div');
+ const forkButton = document.createElement('a');
+ const cancelButton = document.createElement('div');
+ const suggestionSection = document.createElement('div');
+ const actionTextPiece = document.createElement('div');
beforeEach(() => {
blobForkSuggestion = new BlobForkSuggestion({
- openButtons,
- forkButtons,
- cancelButtons,
- suggestionSections,
- actionTextPieces,
- });
+ openButtons: openButton,
+ forkButtons: forkButton,
+ cancelButtons: cancelButton,
+ suggestionSections: suggestionSection,
+ actionTextPieces: actionTextPiece,
+ })
+ .init();
});
afterEach(() => {
@@ -25,13 +26,13 @@ describe('BlobForkSuggestion', () => {
it('showSuggestionSection', () => {
blobForkSuggestion.showSuggestionSection('/foo', 'foo');
- expect(suggestionSections[0].classList.contains('hidden')).toEqual(false);
- expect(forkButtons[0].getAttribute('href')).toEqual('/foo');
- expect(actionTextPieces[0].textContent).toEqual('foo');
+ expect(suggestionSection.classList.contains('hidden')).toEqual(false);
+ expect(forkButton.getAttribute('href')).toEqual('/foo');
+ expect(actionTextPiece.textContent).toEqual('foo');
});
it('hideSuggestionSection', () => {
blobForkSuggestion.hideSuggestionSection();
- expect(suggestionSections[0].classList.contains('hidden')).toEqual(true);
+ expect(suggestionSection.classList.contains('hidden')).toEqual(true);
});
});
diff --git a/spec/javascripts/commit/pipelines/pipelines_spec.js b/spec/javascripts/commit/pipelines/pipelines_spec.js
index 8cac3cad232..ad31448f81c 100644
--- a/spec/javascripts/commit/pipelines/pipelines_spec.js
+++ b/spec/javascripts/commit/pipelines/pipelines_spec.js
@@ -36,6 +36,7 @@ describe('Pipelines table in Commits and Merge requests', () => {
setTimeout(() => {
expect(this.component.$el.querySelector('.empty-state')).toBeDefined();
expect(this.component.$el.querySelector('.realtime-loading')).toBe(null);
+ expect(this.component.$el.querySelector('.js-pipelines-error-state')).toBe(null);
done();
}, 1);
});
@@ -67,6 +68,8 @@ describe('Pipelines table in Commits and Merge requests', () => {
setTimeout(() => {
expect(this.component.$el.querySelectorAll('table > tbody > tr').length).toEqual(1);
expect(this.component.$el.querySelector('.realtime-loading')).toBe(null);
+ expect(this.component.$el.querySelector('.empty-state')).toBe(null);
+ expect(this.component.$el.querySelector('.js-pipelines-error-state')).toBe(null);
done();
}, 0);
});
@@ -95,10 +98,12 @@ describe('Pipelines table in Commits and Merge requests', () => {
this.component.$destroy();
});
- it('should render empty state', function (done) {
+ it('should render error state', function (done) {
setTimeout(() => {
expect(this.component.$el.querySelector('.js-pipelines-error-state')).toBeDefined();
expect(this.component.$el.querySelector('.realtime-loading')).toBe(null);
+ expect(this.component.$el.querySelector('.js-empty-state')).toBe(null);
+ expect(this.component.$el.querySelector('table')).toBe(null);
done();
}, 0);
});
diff --git a/spec/javascripts/environments/environment_actions_spec.js b/spec/javascripts/environments/environment_actions_spec.js
index 6348d97b0a5..676bf61cfd9 100644
--- a/spec/javascripts/environments/environment_actions_spec.js
+++ b/spec/javascripts/environments/environment_actions_spec.js
@@ -1,5 +1,5 @@
import Vue from 'vue';
-import actionsComp from '~/environments/components/environment_actions';
+import actionsComp from '~/environments/components/environment_actions.vue';
describe('Actions Component', () => {
let ActionsComponent;
diff --git a/spec/javascripts/environments/environment_item_spec.js b/spec/javascripts/environments/environment_item_spec.js
index 4d42de4d549..0e141adb628 100644
--- a/spec/javascripts/environments/environment_item_spec.js
+++ b/spec/javascripts/environments/environment_item_spec.js
@@ -1,6 +1,6 @@
import 'timeago.js';
import Vue from 'vue';
-import environmentItemComp from '~/environments/components/environment_item';
+import environmentItemComp from '~/environments/components/environment_item.vue';
describe('Environment item', () => {
let EnvironmentItem;
diff --git a/spec/javascripts/environments/environment_table_spec.js b/spec/javascripts/environments/environment_table_spec.js
index 3df967848a7..effbc6c3ee1 100644
--- a/spec/javascripts/environments/environment_table_spec.js
+++ b/spec/javascripts/environments/environment_table_spec.js
@@ -1,5 +1,5 @@
import Vue from 'vue';
-import environmentTableComp from '~/environments/components/environments_table';
+import environmentTableComp from '~/environments/components/environments_table.vue';
describe('Environment item', () => {
preloadFixtures('static/environments/element.html.raw');
diff --git a/spec/javascripts/fixtures/raw.rb b/spec/javascripts/fixtures/raw.rb
new file mode 100644
index 00000000000..1ce622fc836
--- /dev/null
+++ b/spec/javascripts/fixtures/raw.rb
@@ -0,0 +1,24 @@
+require 'spec_helper'
+
+describe 'Raw files', '(JavaScript fixtures)', type: :controller do
+ include JavaScriptFixturesHelpers
+
+ let(:namespace) { create(:namespace, name: 'frontend-fixtures' )}
+ let(:project) { create(:project, namespace: namespace, path: 'raw-project') }
+
+ before(:all) do
+ clean_frontend_fixtures('blob/notebook/')
+ end
+
+ it 'blob/notebook/basic.json' do |example|
+ blob = project.repository.blob_at('6d85bb69', 'files/ipython/basic.ipynb')
+
+ store_frontend_fixture(blob.data, example.description)
+ end
+
+ it 'blob/notebook/worksheets.json' do |example|
+ blob = project.repository.blob_at('6d85bb69', 'files/ipython/worksheets.ipynb')
+
+ store_frontend_fixture(blob.data, example.description)
+ end
+end
diff --git a/spec/javascripts/notebook/cells/code_spec.js b/spec/javascripts/notebook/cells/code_spec.js
new file mode 100644
index 00000000000..0c432d73f67
--- /dev/null
+++ b/spec/javascripts/notebook/cells/code_spec.js
@@ -0,0 +1,55 @@
+import Vue from 'vue';
+import CodeComponent from '~/notebook/cells/code.vue';
+
+const Component = Vue.extend(CodeComponent);
+
+describe('Code component', () => {
+ let vm;
+ let json;
+
+ beforeEach(() => {
+ json = getJSONFixture('blob/notebook/basic.json');
+ });
+
+ describe('without output', () => {
+ beforeEach((done) => {
+ vm = new Component({
+ propsData: {
+ cell: json.cells[0],
+ },
+ });
+ vm.$mount();
+
+ setTimeout(() => {
+ done();
+ });
+ });
+
+ it('does not render output prompt', () => {
+ expect(vm.$el.querySelectorAll('.prompt').length).toBe(1);
+ });
+ });
+
+ describe('with output', () => {
+ beforeEach((done) => {
+ vm = new Component({
+ propsData: {
+ cell: json.cells[2],
+ },
+ });
+ vm.$mount();
+
+ setTimeout(() => {
+ done();
+ });
+ });
+
+ it('does not render output prompt', () => {
+ expect(vm.$el.querySelectorAll('.prompt').length).toBe(2);
+ });
+
+ it('renders output cell', () => {
+ expect(vm.$el.querySelector('.output')).toBeDefined();
+ });
+ });
+});
diff --git a/spec/javascripts/notebook/cells/markdown_spec.js b/spec/javascripts/notebook/cells/markdown_spec.js
new file mode 100644
index 00000000000..38c976f38d8
--- /dev/null
+++ b/spec/javascripts/notebook/cells/markdown_spec.js
@@ -0,0 +1,41 @@
+import Vue from 'vue';
+import MarkdownComponent from '~/notebook/cells/markdown.vue';
+
+const Component = Vue.extend(MarkdownComponent);
+
+describe('Markdown component', () => {
+ let vm;
+ let cell;
+ let json;
+
+ beforeEach((done) => {
+ json = getJSONFixture('blob/notebook/basic.json');
+
+ cell = json.cells[1];
+
+ vm = new Component({
+ propsData: {
+ cell,
+ },
+ });
+ vm.$mount();
+
+ setTimeout(() => {
+ done();
+ });
+ });
+
+ it('does not render promot', () => {
+ expect(vm.$el.querySelector('.prompt span')).toBeNull();
+ });
+
+ it('does not render the markdown text', () => {
+ expect(
+ vm.$el.querySelector('.markdown').innerHTML.trim(),
+ ).not.toEqual(cell.source.join(''));
+ });
+
+ it('renders the markdown HTML', () => {
+ expect(vm.$el.querySelector('.markdown h1')).not.toBeNull();
+ });
+});
diff --git a/spec/javascripts/notebook/cells/output/index_spec.js b/spec/javascripts/notebook/cells/output/index_spec.js
new file mode 100644
index 00000000000..dbf79f85c7c
--- /dev/null
+++ b/spec/javascripts/notebook/cells/output/index_spec.js
@@ -0,0 +1,126 @@
+import Vue from 'vue';
+import CodeComponent from '~/notebook/cells/output/index.vue';
+
+const Component = Vue.extend(CodeComponent);
+
+describe('Output component', () => {
+ let vm;
+ let json;
+
+ const createComponent = (output) => {
+ vm = new Component({
+ propsData: {
+ output,
+ count: 1,
+ },
+ });
+ vm.$mount();
+ };
+
+ beforeEach(() => {
+ json = getJSONFixture('blob/notebook/basic.json');
+ });
+
+ describe('text output', () => {
+ beforeEach((done) => {
+ createComponent(json.cells[2].outputs[0]);
+
+ setTimeout(() => {
+ done();
+ });
+ });
+
+ it('renders as plain text', () => {
+ expect(vm.$el.querySelector('pre')).not.toBeNull();
+ });
+
+ it('renders promot', () => {
+ expect(vm.$el.querySelector('.prompt span')).not.toBeNull();
+ });
+ });
+
+ describe('image output', () => {
+ beforeEach((done) => {
+ createComponent(json.cells[3].outputs[0]);
+
+ setTimeout(() => {
+ done();
+ });
+ });
+
+ it('renders as an image', () => {
+ expect(vm.$el.querySelector('img')).not.toBeNull();
+ });
+
+ it('does not render the prompt', () => {
+ expect(vm.$el.querySelector('.prompt span')).toBeNull();
+ });
+ });
+
+ describe('html output', () => {
+ beforeEach((done) => {
+ createComponent(json.cells[4].outputs[0]);
+
+ setTimeout(() => {
+ done();
+ });
+ });
+
+ it('renders raw HTML', () => {
+ expect(vm.$el.querySelector('p')).not.toBeNull();
+ expect(vm.$el.textContent.trim()).toBe('test');
+ });
+
+ it('does not render the prompt', () => {
+ expect(vm.$el.querySelector('.prompt span')).toBeNull();
+ });
+ });
+
+ describe('svg output', () => {
+ beforeEach((done) => {
+ createComponent(json.cells[5].outputs[0]);
+
+ setTimeout(() => {
+ done();
+ });
+ });
+
+ it('renders as an svg', () => {
+ expect(vm.$el.querySelector('svg')).not.toBeNull();
+ });
+
+ it('does not render the prompt', () => {
+ expect(vm.$el.querySelector('.prompt span')).toBeNull();
+ });
+ });
+
+ describe('default to plain text', () => {
+ beforeEach((done) => {
+ createComponent(json.cells[6].outputs[0]);
+
+ setTimeout(() => {
+ done();
+ });
+ });
+
+ it('renders as plain text', () => {
+ expect(vm.$el.querySelector('pre')).not.toBeNull();
+ expect(vm.$el.textContent.trim()).toContain('testing');
+ });
+
+ it('renders promot', () => {
+ expect(vm.$el.querySelector('.prompt span')).not.toBeNull();
+ });
+
+ it('renders as plain text when doesn\'t recognise other types', (done) => {
+ createComponent(json.cells[7].outputs[0]);
+
+ setTimeout(() => {
+ expect(vm.$el.querySelector('pre')).not.toBeNull();
+ expect(vm.$el.textContent.trim()).toContain('testing');
+
+ done();
+ });
+ });
+ });
+});
diff --git a/spec/javascripts/notebook/cells/prompt_spec.js b/spec/javascripts/notebook/cells/prompt_spec.js
new file mode 100644
index 00000000000..207fa433a59
--- /dev/null
+++ b/spec/javascripts/notebook/cells/prompt_spec.js
@@ -0,0 +1,56 @@
+import Vue from 'vue';
+import PromptComponent from '~/notebook/cells/prompt.vue';
+
+const Component = Vue.extend(PromptComponent);
+
+describe('Prompt component', () => {
+ let vm;
+
+ describe('input', () => {
+ beforeEach((done) => {
+ vm = new Component({
+ propsData: {
+ type: 'In',
+ count: 1,
+ },
+ });
+ vm.$mount();
+
+ setTimeout(() => {
+ done();
+ });
+ });
+
+ it('renders in label', () => {
+ expect(vm.$el.textContent.trim()).toContain('In');
+ });
+
+ it('renders count', () => {
+ expect(vm.$el.textContent.trim()).toContain('1');
+ });
+ });
+
+ describe('output', () => {
+ beforeEach((done) => {
+ vm = new Component({
+ propsData: {
+ type: 'Out',
+ count: 1,
+ },
+ });
+ vm.$mount();
+
+ setTimeout(() => {
+ done();
+ });
+ });
+
+ it('renders in label', () => {
+ expect(vm.$el.textContent.trim()).toContain('Out');
+ });
+
+ it('renders count', () => {
+ expect(vm.$el.textContent.trim()).toContain('1');
+ });
+ });
+});
diff --git a/spec/javascripts/notebook/index_spec.js b/spec/javascripts/notebook/index_spec.js
new file mode 100644
index 00000000000..bd63ab35426
--- /dev/null
+++ b/spec/javascripts/notebook/index_spec.js
@@ -0,0 +1,98 @@
+import Vue from 'vue';
+import Notebook from '~/notebook/index.vue';
+
+const Component = Vue.extend(Notebook);
+
+describe('Notebook component', () => {
+ let vm;
+ let json;
+ let jsonWithWorksheet;
+
+ beforeEach(() => {
+ json = getJSONFixture('blob/notebook/basic.json');
+ jsonWithWorksheet = getJSONFixture('blob/notebook/worksheets.json');
+ });
+
+ describe('without JSON', () => {
+ beforeEach((done) => {
+ vm = new Component({
+ propsData: {
+ notebook: {},
+ },
+ });
+ vm.$mount();
+
+ setTimeout(() => {
+ done();
+ });
+ });
+
+ it('does not render', () => {
+ expect(vm.$el.tagName).toBeUndefined();
+ });
+ });
+
+ describe('with JSON', () => {
+ beforeEach((done) => {
+ vm = new Component({
+ propsData: {
+ notebook: json,
+ codeCssClass: 'js-code-class',
+ },
+ });
+ vm.$mount();
+
+ setTimeout(() => {
+ done();
+ });
+ });
+
+ it('renders cells', () => {
+ expect(vm.$el.querySelectorAll('.cell').length).toBe(json.cells.length);
+ });
+
+ it('renders markdown cell', () => {
+ expect(vm.$el.querySelector('.markdown')).not.toBeNull();
+ });
+
+ it('renders code cell', () => {
+ expect(vm.$el.querySelector('pre')).not.toBeNull();
+ });
+
+ it('add code class to code blocks', () => {
+ expect(vm.$el.querySelector('.js-code-class')).not.toBeNull();
+ });
+ });
+
+ describe('with worksheets', () => {
+ beforeEach((done) => {
+ vm = new Component({
+ propsData: {
+ notebook: jsonWithWorksheet,
+ codeCssClass: 'js-code-class',
+ },
+ });
+ vm.$mount();
+
+ setTimeout(() => {
+ done();
+ });
+ });
+
+ it('renders cells', () => {
+ expect(vm.$el.querySelectorAll('.cell').length).toBe(jsonWithWorksheet.worksheets[0].cells.length);
+ });
+
+ it('renders markdown cell', () => {
+ expect(vm.$el.querySelector('.markdown')).not.toBeNull();
+ });
+
+ it('renders code cell', () => {
+ expect(vm.$el.querySelector('pre')).not.toBeNull();
+ });
+
+ it('add code class to code blocks', () => {
+ expect(vm.$el.querySelector('.js-code-class')).not.toBeNull();
+ });
+ });
+});
diff --git a/spec/javascripts/notebook/lib/highlight_spec.js b/spec/javascripts/notebook/lib/highlight_spec.js
new file mode 100644
index 00000000000..d71c5718858
--- /dev/null
+++ b/spec/javascripts/notebook/lib/highlight_spec.js
@@ -0,0 +1,15 @@
+import Prism from '~/notebook/lib/highlight';
+
+describe('Highlight library', () => {
+ it('imports python language', () => {
+ expect(Prism.languages.python).toBeDefined();
+ });
+
+ it('uses custom CSS classes', () => {
+ const el = document.createElement('div');
+ el.innerHTML = Prism.highlight('console.log("a");', Prism.languages.javascript);
+
+ expect(el.querySelector('.s')).not.toBeNull();
+ expect(el.querySelector('.nf')).not.toBeNull();
+ });
+});
diff --git a/spec/javascripts/shortcuts_spec.js b/spec/javascripts/shortcuts_spec.js
new file mode 100644
index 00000000000..9b8373df29e
--- /dev/null
+++ b/spec/javascripts/shortcuts_spec.js
@@ -0,0 +1,45 @@
+/* global Shortcuts */
+describe('Shortcuts', () => {
+ const fixtureName = 'issues/issue_with_comment.html.raw';
+ const createEvent = (type, target) => $.Event(type, {
+ target,
+ });
+
+ preloadFixtures(fixtureName);
+
+ describe('toggleMarkdownPreview', () => {
+ let sc;
+
+ beforeEach(() => {
+ loadFixtures(fixtureName);
+
+ spyOnEvent('.js-new-note-form .js-md-preview-button', 'focus');
+ spyOnEvent('.edit-note .js-md-preview-button', 'focus');
+
+ sc = new Shortcuts();
+ });
+
+ it('focuses preview button in form', () => {
+ sc.toggleMarkdownPreview(
+ createEvent('KeyboardEvent', document.querySelector('.js-new-note-form .js-note-text'),
+ ));
+
+ expect('focus').toHaveBeenTriggeredOn('.js-new-note-form .js-md-preview-button');
+ });
+
+ it('focues preview button inside edit comment form', (done) => {
+ document.querySelector('.js-note-edit').click();
+
+ setTimeout(() => {
+ sc.toggleMarkdownPreview(
+ createEvent('KeyboardEvent', document.querySelector('.edit-note .js-note-text'),
+ ));
+
+ expect('focus').not.toHaveBeenTriggeredOn('.js-new-note-form .js-md-preview-button');
+ expect('focus').toHaveBeenTriggeredOn('.edit-note .js-md-preview-button');
+
+ done();
+ });
+ });
+ });
+});
diff --git a/spec/lib/banzai/object_renderer_spec.rb b/spec/lib/banzai/object_renderer_spec.rb
index 4817fcd031a..dd2674f9f20 100644
--- a/spec/lib/banzai/object_renderer_spec.rb
+++ b/spec/lib/banzai/object_renderer_spec.rb
@@ -4,13 +4,13 @@ describe Banzai::ObjectRenderer do
let(:project) { create(:empty_project) }
let(:user) { project.owner }
let(:renderer) { described_class.new(project, user, custom_value: 'value') }
- let(:object) { Note.new(note: 'hello', note_html: '<p>hello</p>') }
+ let(:object) { Note.new(note: 'hello', note_html: '<p dir="auto">hello</p>', cached_markdown_version: CacheMarkdownField::CACHE_VERSION) }
describe '#render' do
it 'renders and redacts an Array of objects' do
renderer.render([object], :note)
- expect(object.redacted_note_html).to eq '<p>hello</p>'
+ expect(object.redacted_note_html).to eq '<p dir="auto">hello</p>'
expect(object.user_visible_reference_count).to eq 0
end
diff --git a/spec/lib/banzai/redactor_spec.rb b/spec/lib/banzai/redactor_spec.rb
index 6d2c141e18b..e6f2963193c 100644
--- a/spec/lib/banzai/redactor_spec.rb
+++ b/spec/lib/banzai/redactor_spec.rb
@@ -42,6 +42,31 @@ describe Banzai::Redactor do
end
end
+ context 'when project is in pending delete' do
+ let!(:issue) { create(:issue, project: project) }
+ let(:redactor) { described_class.new(project, user) }
+
+ before do
+ project.update(pending_delete: true)
+ end
+
+ it 'redacts an issue attached' do
+ doc = Nokogiri::HTML.fragment("<a class='gfm' data-reference-type='issue' data-issue='#{issue.id}'>foo</a>")
+
+ redactor.redact([doc])
+
+ expect(doc.to_html).to eq('foo')
+ end
+
+ it 'redacts an external issue' do
+ doc = Nokogiri::HTML.fragment("<a class='gfm' data-reference-type='issue' data-external-issue='#{issue.id}' data-project='#{project.id}'>foo</a>")
+
+ redactor.redact([doc])
+
+ expect(doc.to_html).to eq('foo')
+ end
+ end
+
context 'when reference visible to user' do
it 'does not redact an array of documents' do
doc1_html = '<a class="gfm" data-reference-type="issue">foo</a>'
diff --git a/spec/lib/banzai/renderer_spec.rb b/spec/lib/banzai/renderer_spec.rb
index aaa6b12e67e..e6f8d2a1fed 100644
--- a/spec/lib/banzai/renderer_spec.rb
+++ b/spec/lib/banzai/renderer_spec.rb
@@ -1,73 +1,36 @@
require 'spec_helper'
describe Banzai::Renderer do
- def expect_render(project = :project)
- expected_context = { project: project }
- expect(renderer).to receive(:cacheless_render) { :html }.with(:markdown, expected_context)
- end
-
- def expect_cache_update
- expect(object).to receive(:update_column).with("field_html", :html)
- end
-
- def fake_object(*features)
- markdown = :markdown if features.include?(:markdown)
- html = :html if features.include?(:html)
-
- object = double(
- "object",
- banzai_render_context: { project: :project },
- field: markdown,
- field_html: html
- )
+ def fake_object(fresh:)
+ object = double('object')
- allow(object).to receive(:markdown_cache_field_for).with(:field).and_return("field_html")
- allow(object).to receive(:new_record?).and_return(features.include?(:new))
- allow(object).to receive(:destroyed?).and_return(features.include?(:destroyed))
+ allow(object).to receive(:cached_html_up_to_date?).with(:field).and_return(fresh)
+ allow(object).to receive(:cached_html_for).with(:field).and_return('field_html')
object
end
- describe "#render_field" do
+ describe '#render_field' do
let(:renderer) { Banzai::Renderer }
- let(:subject) { renderer.render_field(object, :field) }
+ subject { renderer.render_field(object, :field) }
- context "with an empty cache" do
- let(:object) { fake_object(:markdown) }
- it "caches and returns the result" do
- expect_render
- expect_cache_update
- expect(subject).to eq(:html)
- end
- end
+ context 'with a stale cache' do
+ let(:object) { fake_object(fresh: false) }
- context "with a filled cache" do
- let(:object) { fake_object(:markdown, :html) }
+ it 'caches and returns the result' do
+ expect(object).to receive(:refresh_markdown_cache!).with(do_update: true)
- it "uses the cache" do
- expect_render.never
- expect_cache_update.never
- should eq(:html)
+ is_expected.to eq('field_html')
end
end
- context "new object" do
- let(:object) { fake_object(:new, :markdown) }
-
- it "doesn't cache the result" do
- expect_render
- expect_cache_update.never
- expect(subject).to eq(:html)
- end
- end
+ context 'with an up-to-date cache' do
+ let(:object) { fake_object(fresh: true) }
- context "destroyed object" do
- let(:object) { fake_object(:destroyed, :markdown) }
+ it 'uses the cache' do
+ expect(object).to receive(:refresh_markdown_cache!).never
- it "doesn't cache the result" do
- expect_render
- expect_cache_update.never
- expect(subject).to eq(:html)
+ is_expected.to eq('field_html')
end
end
end
diff --git a/spec/lib/gitlab/auth_spec.rb b/spec/lib/gitlab/auth_spec.rb
index 03c4879ed6f..d4a43192d03 100644
--- a/spec/lib/gitlab/auth_spec.rb
+++ b/spec/lib/gitlab/auth_spec.rb
@@ -118,7 +118,7 @@ describe Gitlab::Auth, lib: true do
it 'succeeds for OAuth tokens with the `api` scope' do
expect(gl_auth).to receive(:rate_limit!).with('ip', success: true, login: 'oauth2')
- expect(gl_auth.find_for_git_client("oauth2", token_w_api_scope.token, project: nil, ip: 'ip')).to eq(Gitlab::Auth::Result.new(user, nil, :oauth, read_authentication_abilities))
+ expect(gl_auth.find_for_git_client("oauth2", token_w_api_scope.token, project: nil, ip: 'ip')).to eq(Gitlab::Auth::Result.new(user, nil, :oauth, full_authentication_abilities))
end
it 'fails for OAuth tokens with other scopes' do
diff --git a/spec/lib/gitlab/diff/position_tracer_spec.rb b/spec/lib/gitlab/diff/position_tracer_spec.rb
index c166f83664a..a10a251dc4a 100644
--- a/spec/lib/gitlab/diff/position_tracer_spec.rb
+++ b/spec/lib/gitlab/diff/position_tracer_spec.rb
@@ -569,13 +569,8 @@ describe Gitlab::Diff::PositionTracer, lib: true do
# 1 1 BB
# 2 2 A
- it "returns the new position" do
- expect_new_position(
- old_path: file_name,
- new_path: new_file_name,
- old_line: old_position.new_line,
- new_line: old_position.new_line
- )
+ it "returns nil since the line doesn't exist in the new diffs anymore" do
+ expect(subject).to be_nil
end
end
diff --git a/spec/lib/gitlab/git/encoding_helper_spec.rb b/spec/lib/gitlab/git/encoding_helper_spec.rb
index 27bcc241b82..f6ac7b23d1d 100644
--- a/spec/lib/gitlab/git/encoding_helper_spec.rb
+++ b/spec/lib/gitlab/git/encoding_helper_spec.rb
@@ -56,6 +56,10 @@ describe Gitlab::Git::EncodingHelper do
expect(r.encoding.name).to eq('UTF-8')
end
end
+
+ it 'returns empty string on conversion errors' do
+ expect { ext_class.encode_utf8('') }.not_to raise_error(ArgumentError)
+ end
end
describe '#clean' do
diff --git a/spec/lib/gitlab/other_markup.rb b/spec/lib/gitlab/other_markup_spec.rb
index 8f5a353b381..22e80ec46be 100644
--- a/spec/lib/gitlab/other_markup.rb
+++ b/spec/lib/gitlab/other_markup_spec.rb
@@ -1,12 +1,14 @@
require 'spec_helper'
describe Gitlab::OtherMarkup, lib: true do
+ let(:context) { {} }
+
context "XSS Checks" do
links = {
'links' => {
file: 'file.rdoc',
input: 'XSS[JaVaScriPt:alert(1)]',
- output: '<p><a>XSS</a></p>'
+ output: "\n" + '<p><a>XSS</a></p>' + "\n"
}
}
links.each do |name, data|
diff --git a/spec/models/ci/pipeline_spec.rb b/spec/models/ci/pipeline_spec.rb
index d7d6a75d38d..3b222ea1c3d 100644
--- a/spec/models/ci/pipeline_spec.rb
+++ b/spec/models/ci/pipeline_spec.rb
@@ -296,32 +296,56 @@ describe Ci::Pipeline, models: true do
describe 'state machine' do
let(:current) { Time.now.change(usec: 0) }
- let(:build) { create_build('build1', 0) }
- let(:build_b) { create_build('build2', 0) }
- let(:build_c) { create_build('build3', 0) }
+ let(:build) { create_build('build1', queued_at: 0) }
+ let(:build_b) { create_build('build2', queued_at: 0) }
+ let(:build_c) { create_build('build3', queued_at: 0) }
describe '#duration' do
- before do
- travel_to(current + 30) do
- build.run!
- build.success!
- build_b.run!
- build_c.run!
- end
+ context 'when multiple builds are finished' do
+ before do
+ travel_to(current + 30) do
+ build.run!
+ build.success!
+ build_b.run!
+ build_c.run!
+ end
- travel_to(current + 40) do
- build_b.drop!
+ travel_to(current + 40) do
+ build_b.drop!
+ end
+
+ travel_to(current + 70) do
+ build_c.success!
+ end
end
- travel_to(current + 70) do
- build_c.success!
+ it 'matches sum of builds duration' do
+ pipeline.reload
+
+ expect(pipeline.duration).to eq(40)
end
end
- it 'matches sum of builds duration' do
- pipeline.reload
+ context 'when pipeline becomes blocked' do
+ let!(:build) { create_build('build:1') }
+ let!(:action) { create_build('manual:action', :manual) }
+
+ before do
+ travel_to(current + 1.minute) do
+ build.run!
+ end
+
+ travel_to(current + 5.minutes) do
+ build.success!
+ end
+ end
+
+ it 'recalculates pipeline duration' do
+ pipeline.reload
- expect(pipeline.duration).to eq(40)
+ expect(pipeline).to be_manual
+ expect(pipeline.duration).to eq 4.minutes
+ end
end
end
@@ -376,19 +400,20 @@ describe Ci::Pipeline, models: true do
end
describe 'pipeline caching' do
- it 'executes ExpirePipelinesCacheService' do
- expect_any_instance_of(Ci::ExpirePipelineCacheService).to receive(:execute).with(pipeline)
+ it 'performs ExpirePipelinesCacheWorker' do
+ expect(ExpirePipelineCacheWorker).to receive(:perform_async).with(pipeline.id)
pipeline.cancel
end
end
- def create_build(name, queued_at = current, started_from = 0)
- create(:ci_build,
+ def create_build(name, *traits, queued_at: current, started_from: 0, **opts)
+ create(:ci_build, *traits,
name: name,
pipeline: pipeline,
queued_at: queued_at,
- started_at: queued_at + started_from)
+ started_at: queued_at + started_from,
+ **opts)
end
end
@@ -1014,11 +1039,12 @@ describe Ci::Pipeline, models: true do
end
describe "#merge_requests" do
- let(:project) { create(:project, :repository) }
- let(:pipeline) { FactoryGirl.create(:ci_empty_pipeline, status: 'created', project: project, ref: 'master', sha: project.repository.commit('master').id) }
+ let(:project) { create(:empty_project) }
+ let(:pipeline) { create(:ci_empty_pipeline, status: 'created', project: project, ref: 'master', sha: 'a288a022a53a5a944fae87bcec6efc87b7061808') }
it "returns merge requests whose `diff_head_sha` matches the pipeline's SHA" do
merge_request = create(:merge_request, source_project: project, source_branch: pipeline.ref)
+ allow_any_instance_of(MergeRequest).to receive(:diff_head_sha) { 'a288a022a53a5a944fae87bcec6efc87b7061808' }
expect(pipeline.merge_requests).to eq([merge_request])
end
@@ -1037,6 +1063,23 @@ describe Ci::Pipeline, models: true do
end
end
+ describe "#all_merge_requests" do
+ let(:project) { create(:empty_project) }
+ let(:pipeline) { create(:ci_empty_pipeline, status: 'created', project: project, ref: 'master') }
+
+ it "returns all merge requests having the same source branch" do
+ merge_request = create(:merge_request, source_project: project, source_branch: pipeline.ref)
+
+ expect(pipeline.all_merge_requests).to eq([merge_request])
+ end
+
+ it "doesn't return merge requests having a different source branch" do
+ create(:merge_request, source_project: project, source_branch: 'feature', target_branch: 'master')
+
+ expect(pipeline.all_merge_requests).to be_empty
+ end
+ end
+
describe '#stuck?' do
before do
create(:ci_build, :pending, pipeline: pipeline)
diff --git a/spec/models/concerns/cache_markdown_field_spec.rb b/spec/models/concerns/cache_markdown_field_spec.rb
index 6151d53cd91..de0069bdcac 100644
--- a/spec/models/concerns/cache_markdown_field_spec.rb
+++ b/spec/models/concerns/cache_markdown_field_spec.rb
@@ -1,9 +1,6 @@
require 'spec_helper'
describe CacheMarkdownField do
- caching_classes = CacheMarkdownField::CACHING_CLASSES
- CacheMarkdownField::CACHING_CLASSES = ["ThingWithMarkdownFields"].freeze
-
# The minimum necessary ActiveModel to test this concern
class ThingWithMarkdownFields
include ActiveModel::Model
@@ -27,18 +24,19 @@ describe CacheMarkdownField do
cache_markdown_field :foo
cache_markdown_field :baz, pipeline: :single_line
- def self.add_attr(attr_name)
- self.attribute_names += [attr_name]
- define_attribute_methods(attr_name)
- attr_reader(attr_name)
- define_method("#{attr_name}=") do |val|
- send("#{attr_name}_will_change!") unless val == send(attr_name)
- instance_variable_set("@#{attr_name}", val)
+ def self.add_attr(name)
+ self.attribute_names += [name]
+ define_attribute_methods(name)
+ attr_reader(name)
+ define_method("#{name}=") do |value|
+ write_attribute(name, value)
end
end
- [:foo, :foo_html, :bar, :baz, :baz_html].each do |attr_name|
- add_attr(attr_name)
+ add_attr :cached_markdown_version
+
+ [:foo, :foo_html, :bar, :baz, :baz_html].each do |name|
+ add_attr(name)
end
def initialize(*)
@@ -48,6 +46,15 @@ describe CacheMarkdownField do
clear_changes_information
end
+ def read_attribute(name)
+ instance_variable_get("@#{name}")
+ end
+
+ def write_attribute(name, value)
+ send("#{name}_will_change!") unless value == read_attribute(name)
+ instance_variable_set("@#{name}", value)
+ end
+
def save
run_callbacks :save do
changes_applied
@@ -55,127 +62,236 @@ describe CacheMarkdownField do
end
end
- CacheMarkdownField::CACHING_CLASSES = caching_classes
-
def thing_subclass(new_attr)
Class.new(ThingWithMarkdownFields) { add_attr(new_attr) }
end
- let(:markdown) { "`Foo`" }
- let(:html) { "<p><code>Foo</code></p>" }
+ let(:markdown) { '`Foo`' }
+ let(:html) { '<p dir="auto"><code>Foo</code></p>' }
- let(:updated_markdown) { "`Bar`" }
- let(:updated_html) { "<p dir=\"auto\"><code>Bar</code></p>" }
+ let(:updated_markdown) { '`Bar`' }
+ let(:updated_html) { '<p dir="auto"><code>Bar</code></p>' }
- subject { ThingWithMarkdownFields.new(foo: markdown, foo_html: html) }
+ let(:thing) { ThingWithMarkdownFields.new(foo: markdown, foo_html: html, cached_markdown_version: CacheMarkdownField::CACHE_VERSION) }
- describe ".attributes" do
- it "excludes cache attributes" do
- expect(thing_subclass(:qux).new.attributes.keys.sort).to eq(%w[bar baz foo qux])
+ describe '.attributes' do
+ it 'excludes cache attributes' do
+ expect(thing.attributes.keys.sort).to eq(%w[bar baz foo])
end
end
- describe ".cache_markdown_field" do
- it "refuses to allow untracked classes" do
- expect { thing_subclass(:qux).__send__(:cache_markdown_field, :qux) }.to raise_error(RuntimeError)
+ context 'an unchanged markdown field' do
+ before do
+ thing.foo = thing.foo
+ thing.save
end
+
+ it { expect(thing.foo).to eq(markdown) }
+ it { expect(thing.foo_html).to eq(html) }
+ it { expect(thing.foo_html_changed?).not_to be_truthy }
+ it { expect(thing.cached_markdown_version).to eq(CacheMarkdownField::CACHE_VERSION) }
end
- context "an unchanged markdown field" do
+ context 'a changed markdown field' do
before do
- subject.foo = subject.foo
- subject.save
+ thing.foo = updated_markdown
+ thing.save
end
- it { expect(subject.foo).to eq(markdown) }
- it { expect(subject.foo_html).to eq(html) }
- it { expect(subject.foo_html_changed?).not_to be_truthy }
+ it { expect(thing.foo_html).to eq(updated_html) }
+ it { expect(thing.cached_markdown_version).to eq(CacheMarkdownField::CACHE_VERSION) }
end
- context "a changed markdown field" do
+ context 'a non-markdown field changed' do
+ before do
+ thing.bar = 'OK'
+ thing.save
+ end
+
+ it { expect(thing.bar).to eq('OK') }
+ it { expect(thing.foo).to eq(markdown) }
+ it { expect(thing.foo_html).to eq(html) }
+ it { expect(thing.cached_markdown_version).to eq(CacheMarkdownField::CACHE_VERSION) }
+ end
+
+ context 'version is out of date' do
+ let(:thing) { ThingWithMarkdownFields.new(foo: updated_markdown, foo_html: html, cached_markdown_version: nil) }
+
before do
- subject.foo = updated_markdown
- subject.save
+ thing.save
+ end
+
+ it { expect(thing.foo_html).to eq(updated_html) }
+ it { expect(thing.cached_markdown_version).to eq(CacheMarkdownField::CACHE_VERSION) }
+ end
+
+ describe '#cached_html_up_to_date?' do
+ subject { thing.cached_html_up_to_date?(:foo) }
+
+ it 'returns false when the version is absent' do
+ thing.cached_markdown_version = nil
+
+ is_expected.to be_falsy
+ end
+
+ it 'returns false when the version is too early' do
+ thing.cached_markdown_version -= 1
+
+ is_expected.to be_falsy
+ end
+
+ it 'returns false when the version is too late' do
+ thing.cached_markdown_version += 1
+
+ is_expected.to be_falsy
+ end
+
+ it 'returns true when the version is just right' do
+ thing.cached_markdown_version = CacheMarkdownField::CACHE_VERSION
+
+ is_expected.to be_truthy
end
- it { expect(subject.foo_html).to eq(updated_html) }
+ it 'returns false if markdown has been changed but html has not' do
+ thing.foo = updated_html
+
+ is_expected.to be_falsy
+ end
+
+ it 'returns true if markdown has not been changed but html has' do
+ thing.foo_html = updated_html
+
+ is_expected.to be_truthy
+ end
+
+ it 'returns true if markdown and html have both been changed' do
+ thing.foo = updated_markdown
+ thing.foo_html = updated_html
+
+ is_expected.to be_truthy
+ end
end
- context "a non-markdown field changed" do
+ describe '#refresh_markdown_cache!' do
before do
- subject.bar = "OK"
- subject.save
+ thing.foo = updated_markdown
+ end
+
+ context 'do_update: false' do
+ it 'fills all html fields' do
+ thing.refresh_markdown_cache!
+
+ expect(thing.foo_html).to eq(updated_html)
+ expect(thing.foo_html_changed?).to be_truthy
+ expect(thing.baz_html_changed?).to be_truthy
+ end
+
+ it 'does not save the result' do
+ expect(thing).not_to receive(:update_columns)
+
+ thing.refresh_markdown_cache!
+ end
+
+ it 'updates the markdown cache version' do
+ thing.cached_markdown_version = nil
+ thing.refresh_markdown_cache!
+
+ expect(thing.cached_markdown_version).to eq(CacheMarkdownField::CACHE_VERSION)
+ end
end
- it { expect(subject.bar).to eq("OK") }
- it { expect(subject.foo).to eq(markdown) }
- it { expect(subject.foo_html).to eq(html) }
+ context 'do_update: true' do
+ it 'fills all html fields' do
+ thing.refresh_markdown_cache!(do_update: true)
+
+ expect(thing.foo_html).to eq(updated_html)
+ expect(thing.foo_html_changed?).to be_truthy
+ expect(thing.baz_html_changed?).to be_truthy
+ end
+
+ it 'skips saving if not persisted' do
+ expect(thing).to receive(:persisted?).and_return(false)
+ expect(thing).not_to receive(:update_columns)
+
+ thing.refresh_markdown_cache!(do_update: true)
+ end
+
+ it 'saves the changes using #update_columns' do
+ expect(thing).to receive(:persisted?).and_return(true)
+ expect(thing).to receive(:update_columns)
+ .with("foo_html" => updated_html, "baz_html" => "", "cached_markdown_version" => CacheMarkdownField::CACHE_VERSION)
+
+ thing.refresh_markdown_cache!(do_update: true)
+ end
+ end
end
describe '#banzai_render_context' do
- it "sets project to nil if the object lacks a project" do
- context = subject.banzai_render_context(:foo)
- expect(context).to have_key(:project)
+ subject(:context) { thing.banzai_render_context(:foo) }
+
+ it 'sets project to nil if the object lacks a project' do
+ is_expected.to have_key(:project)
expect(context[:project]).to be_nil
end
- it "excludes author if the object lacks an author" do
- context = subject.banzai_render_context(:foo)
- expect(context).not_to have_key(:author)
+ it 'excludes author if the object lacks an author' do
+ is_expected.not_to have_key(:author)
end
- it "raises if the context for an unrecognised field is requested" do
- expect{subject.banzai_render_context(:not_found)}.to raise_error(ArgumentError)
+ it 'raises if the context for an unrecognised field is requested' do
+ expect { thing.banzai_render_context(:not_found) }.to raise_error(ArgumentError)
end
- it "includes the pipeline" do
- context = subject.banzai_render_context(:baz)
- expect(context[:pipeline]).to eq(:single_line)
+ it 'includes the pipeline' do
+ baz = thing.banzai_render_context(:baz)
+
+ expect(baz[:pipeline]).to eq(:single_line)
end
- it "returns copies of the context template" do
- template = subject.cached_markdown_fields[:baz]
- copy = subject.banzai_render_context(:baz)
+ it 'returns copies of the context template' do
+ template = thing.cached_markdown_fields[:baz]
+ copy = thing.banzai_render_context(:baz)
+
expect(copy).not_to be(template)
end
- context "with a project" do
- subject { thing_subclass(:project).new(foo: markdown, foo_html: html, project: :project) }
+ context 'with a project' do
+ let(:thing) { thing_subclass(:project).new(foo: markdown, foo_html: html, project: :project_value) }
- it "sets the project in the context" do
- context = subject.banzai_render_context(:foo)
- expect(context).to have_key(:project)
- expect(context[:project]).to eq(:project)
+ it 'sets the project in the context' do
+ is_expected.to have_key(:project)
+ expect(context[:project]).to eq(:project_value)
end
- it "invalidates the cache when project changes" do
- subject.project = :new_project
+ it 'invalidates the cache when project changes' do
+ thing.project = :new_project
allow(Banzai::Renderer).to receive(:cacheless_render_field).and_return(updated_html)
- subject.save
+ thing.save
- expect(subject.foo_html).to eq(updated_html)
- expect(subject.baz_html).to eq(updated_html)
+ expect(thing.foo_html).to eq(updated_html)
+ expect(thing.baz_html).to eq(updated_html)
+ expect(thing.cached_markdown_version).to eq(CacheMarkdownField::CACHE_VERSION)
end
end
- context "with an author" do
- subject { thing_subclass(:author).new(foo: markdown, foo_html: html, author: :author) }
+ context 'with an author' do
+ let(:thing) { thing_subclass(:author).new(foo: markdown, foo_html: html, author: :author_value) }
- it "sets the author in the context" do
- context = subject.banzai_render_context(:foo)
- expect(context).to have_key(:author)
- expect(context[:author]).to eq(:author)
+ it 'sets the author in the context' do
+ is_expected.to have_key(:author)
+ expect(context[:author]).to eq(:author_value)
end
- it "invalidates the cache when author changes" do
- subject.author = :new_author
+ it 'invalidates the cache when author changes' do
+ thing.author = :new_author
allow(Banzai::Renderer).to receive(:cacheless_render_field).and_return(updated_html)
- subject.save
+ thing.save
- expect(subject.foo_html).to eq(updated_html)
- expect(subject.baz_html).to eq(updated_html)
+ expect(thing.foo_html).to eq(updated_html)
+ expect(thing.baz_html).to eq(updated_html)
+ expect(thing.cached_markdown_version).to eq(CacheMarkdownField::CACHE_VERSION)
end
end
end
diff --git a/spec/models/concerns/routable_spec.rb b/spec/models/concerns/routable_spec.rb
index f191605dbdb..221647d7a48 100644
--- a/spec/models/concerns/routable_spec.rb
+++ b/spec/models/concerns/routable_spec.rb
@@ -194,6 +194,24 @@ describe Group, 'Routable' do
it { expect(group.full_path).to eq(group.path) }
it { expect(nested_group.full_path).to eq("#{group.full_path}/#{nested_group.path}") }
+
+ context 'with RequestStore active' do
+ before do
+ RequestStore.begin!
+ end
+
+ after do
+ RequestStore.end!
+ RequestStore.clear!
+ end
+
+ it 'does not load the route table more than once' do
+ expect(group).to receive(:uncached_full_path).once.and_call_original
+
+ 3.times { group.full_path }
+ expect(group.full_path).to eq(group.path)
+ end
+ end
end
describe '#full_name' do
diff --git a/spec/models/member_spec.rb b/spec/models/member_spec.rb
index c720cc9f2c2..b0f3657d3b5 100644
--- a/spec/models/member_spec.rb
+++ b/spec/models/member_spec.rb
@@ -386,6 +386,31 @@ describe Member, models: true do
end
end
+ describe '.add_users' do
+ %w[project group].each do |source_type|
+ context "when source is a #{source_type}" do
+ let!(:source) { create(source_type, :public, :access_requestable) }
+ let!(:user) { create(:user) }
+ let!(:admin) { create(:admin) }
+
+ it 'returns a <Source>Member objects' do
+ members = described_class.add_users(source, [user], :master)
+
+ expect(members).to be_a Array
+ expect(members.first).to be_a "#{source_type.classify}Member".constantize
+ expect(members.first).to be_persisted
+ end
+
+ it 'returns an empty array' do
+ members = described_class.add_users(source, [], :master)
+
+ expect(members).to be_a Array
+ expect(members).to be_empty
+ end
+ end
+ end
+ end
+
describe '#accept_request' do
let(:member) { create(:project_member, requested_at: Time.now.utc) }
diff --git a/spec/models/members/group_member_spec.rb b/spec/models/members/group_member_spec.rb
index 024380b7ebb..17765b25856 100644
--- a/spec/models/members/group_member_spec.rb
+++ b/spec/models/members/group_member_spec.rb
@@ -13,12 +13,12 @@ describe GroupMember, models: true do
end
end
- describe '.add_users_to_group' do
+ describe '.add_users' do
it 'adds the given users to the given group' do
group = create(:group)
users = create_list(:user, 2)
- described_class.add_users_to_group(
+ described_class.add_users(
group,
[users.first.id, users.second],
described_class::MASTER
diff --git a/spec/models/sent_notification_spec.rb b/spec/models/sent_notification_spec.rb
index 6b7eef388be..5710edbc9e0 100644
--- a/spec/models/sent_notification_spec.rb
+++ b/spec/models/sent_notification_spec.rb
@@ -69,6 +69,7 @@ describe SentNotification, model: true do
it 'creates a comment on the issue' do
new_note = subject.create_reply('Test')
expect(new_note.in_reply_to?(note)).to be_truthy
+ expect(new_note.discussion_id).not_to eq(note.discussion_id)
end
end
@@ -79,6 +80,7 @@ describe SentNotification, model: true do
it 'creates a reply on the discussion' do
new_note = subject.create_reply('Test')
expect(new_note.in_reply_to?(note)).to be_truthy
+ expect(new_note.discussion_id).to eq(note.discussion_id)
end
end
@@ -99,6 +101,7 @@ describe SentNotification, model: true do
it 'creates a comment on the merge request' do
new_note = subject.create_reply('Test')
expect(new_note.in_reply_to?(note)).to be_truthy
+ expect(new_note.discussion_id).not_to eq(note.discussion_id)
end
end
@@ -109,6 +112,7 @@ describe SentNotification, model: true do
it 'creates a reply on the discussion' do
new_note = subject.create_reply('Test')
expect(new_note.in_reply_to?(note)).to be_truthy
+ expect(new_note.discussion_id).to eq(note.discussion_id)
end
end
@@ -119,6 +123,7 @@ describe SentNotification, model: true do
it 'creates a reply on the discussion' do
new_note = subject.create_reply('Test')
expect(new_note.in_reply_to?(note)).to be_truthy
+ expect(new_note.discussion_id).to eq(note.discussion_id)
end
end
@@ -140,6 +145,7 @@ describe SentNotification, model: true do
it 'creates a comment on the commit' do
new_note = subject.create_reply('Test')
expect(new_note.in_reply_to?(note)).to be_truthy
+ expect(new_note.discussion_id).not_to eq(note.discussion_id)
end
end
@@ -150,6 +156,7 @@ describe SentNotification, model: true do
it 'creates a reply on the discussion' do
new_note = subject.create_reply('Test')
expect(new_note.in_reply_to?(note)).to be_truthy
+ expect(new_note.discussion_id).to eq(note.discussion_id)
end
end
@@ -160,6 +167,7 @@ describe SentNotification, model: true do
it 'creates a reply on the discussion' do
new_note = subject.create_reply('Test')
expect(new_note.in_reply_to?(note)).to be_truthy
+ expect(new_note.discussion_id).to eq(note.discussion_id)
end
end
end
diff --git a/spec/requests/api/access_requests_spec.rb b/spec/requests/api/access_requests_spec.rb
index 46edbd49b28..c8eacb38e6f 100644
--- a/spec/requests/api/access_requests_spec.rb
+++ b/spec/requests/api/access_requests_spec.rb
@@ -1,8 +1,6 @@
require 'spec_helper'
-describe API::AccessRequests, api: true do
- include ApiHelpers
-
+describe API::AccessRequests do
let(:master) { create(:user) }
let(:developer) { create(:user) }
let(:access_requester) { create(:user) }
diff --git a/spec/requests/api/award_emoji_spec.rb b/spec/requests/api/award_emoji_spec.rb
index f4d4a8a2cc7..bbdef0aeb1b 100644
--- a/spec/requests/api/award_emoji_spec.rb
+++ b/spec/requests/api/award_emoji_spec.rb
@@ -1,7 +1,6 @@
require 'spec_helper'
-describe API::AwardEmoji, api: true do
- include ApiHelpers
+describe API::AwardEmoji do
let(:user) { create(:user) }
let!(:project) { create(:empty_project) }
let(:issue) { create(:issue, project: project) }
diff --git a/spec/requests/api/boards_spec.rb b/spec/requests/api/boards_spec.rb
index 87c36639cd4..c27db716ef8 100644
--- a/spec/requests/api/boards_spec.rb
+++ b/spec/requests/api/boards_spec.rb
@@ -1,8 +1,6 @@
require 'spec_helper'
-describe API::Boards, api: true do
- include ApiHelpers
-
+describe API::Boards do
let(:user) { create(:user) }
let(:user2) { create(:user) }
let(:non_member) { create(:user) }
diff --git a/spec/requests/api/branches_spec.rb b/spec/requests/api/branches_spec.rb
index a70f7beaae0..7eaa89837c8 100644
--- a/spec/requests/api/branches_spec.rb
+++ b/spec/requests/api/branches_spec.rb
@@ -1,9 +1,7 @@
require 'spec_helper'
require 'mime/types'
-describe API::Branches, api: true do
- include ApiHelpers
-
+describe API::Branches do
let(:user) { create(:user) }
let!(:project) { create(:project, :repository, creator: user) }
let!(:master) { create(:project_member, :master, user: user, project: project) }
diff --git a/spec/requests/api/broadcast_messages_spec.rb b/spec/requests/api/broadcast_messages_spec.rb
index 024fa66848c..67989689799 100644
--- a/spec/requests/api/broadcast_messages_spec.rb
+++ b/spec/requests/api/broadcast_messages_spec.rb
@@ -1,8 +1,6 @@
require 'spec_helper'
-describe API::BroadcastMessages, api: true do
- include ApiHelpers
-
+describe API::BroadcastMessages do
let(:user) { create(:user) }
let(:admin) { create(:admin) }
diff --git a/spec/requests/api/commit_statuses_spec.rb b/spec/requests/api/commit_statuses_spec.rb
index d8b3cc041a5..1233cdc64c4 100644
--- a/spec/requests/api/commit_statuses_spec.rb
+++ b/spec/requests/api/commit_statuses_spec.rb
@@ -1,8 +1,6 @@
require 'spec_helper'
-describe API::CommitStatuses, api: true do
- include ApiHelpers
-
+describe API::CommitStatuses do
let!(:project) { create(:project, :repository) }
let(:commit) { project.repository.commit }
let(:guest) { create_user(:guest) }
diff --git a/spec/requests/api/commits_spec.rb b/spec/requests/api/commits_spec.rb
index 42dbab586cd..0b0e4c2b112 100644
--- a/spec/requests/api/commits_spec.rb
+++ b/spec/requests/api/commits_spec.rb
@@ -1,8 +1,7 @@
require 'spec_helper'
require 'mime/types'
-describe API::Commits, api: true do
- include ApiHelpers
+describe API::Commits do
let(:user) { create(:user) }
let(:user2) { create(:user) }
let!(:project) { create(:project, :repository, creator: user, namespace: user.namespace) }
diff --git a/spec/requests/api/deploy_keys_spec.rb b/spec/requests/api/deploy_keys_spec.rb
index e1beac28dab..843e9862b0c 100644
--- a/spec/requests/api/deploy_keys_spec.rb
+++ b/spec/requests/api/deploy_keys_spec.rb
@@ -1,8 +1,6 @@
require 'spec_helper'
-describe API::DeployKeys, api: true do
- include ApiHelpers
-
+describe API::DeployKeys do
let(:user) { create(:user) }
let(:admin) { create(:admin) }
let(:project) { create(:empty_project, creator_id: user.id) }
diff --git a/spec/requests/api/deployments_spec.rb b/spec/requests/api/deployments_spec.rb
index e55575ffbda..90d78d060ca 100644
--- a/spec/requests/api/deployments_spec.rb
+++ b/spec/requests/api/deployments_spec.rb
@@ -1,8 +1,6 @@
require 'spec_helper'
-describe API::Deployments, api: true do
- include ApiHelpers
-
+describe API::Deployments do
let(:user) { create(:user) }
let(:non_member) { create(:user) }
let(:project) { deployment.environment.project }
diff --git a/spec/requests/api/doorkeeper_access_spec.rb b/spec/requests/api/doorkeeper_access_spec.rb
index f6fd567eca5..b5897b2e346 100644
--- a/spec/requests/api/doorkeeper_access_spec.rb
+++ b/spec/requests/api/doorkeeper_access_spec.rb
@@ -1,8 +1,6 @@
require 'spec_helper'
-describe API::API, api: true do
- include ApiHelpers
-
+describe API::API do
let!(:user) { create(:user) }
let!(:application) { Doorkeeper::Application.create!(name: "MyApp", redirect_uri: "https://app.com", owner: user) }
let!(:token) { Doorkeeper::AccessToken.create! application_id: application.id, resource_owner_id: user.id, scopes: "api" }
diff --git a/spec/requests/api/environments_spec.rb b/spec/requests/api/environments_spec.rb
index b54ee8e8b85..aae03c84e1f 100644
--- a/spec/requests/api/environments_spec.rb
+++ b/spec/requests/api/environments_spec.rb
@@ -1,8 +1,6 @@
require 'spec_helper'
-describe API::Environments, api: true do
- include ApiHelpers
-
+describe API::Environments do
let(:user) { create(:user) }
let(:non_member) { create(:user) }
let(:project) { create(:empty_project, :private, namespace: user.namespace) }
diff --git a/spec/requests/api/files_spec.rb b/spec/requests/api/files_spec.rb
index 6db2faed76b..fa28047d49c 100644
--- a/spec/requests/api/files_spec.rb
+++ b/spec/requests/api/files_spec.rb
@@ -1,7 +1,6 @@
require 'spec_helper'
-describe API::Files, api: true do
- include ApiHelpers
+describe API::Files do
let(:user) { create(:user) }
let!(:project) { create(:project, :repository, namespace: user.namespace ) }
let(:guest) { create(:user) { |u| project.add_guest(u) } }
diff --git a/spec/requests/api/groups_spec.rb b/spec/requests/api/groups_spec.rb
index 2545da7b1db..3e27a3bee77 100644
--- a/spec/requests/api/groups_spec.rb
+++ b/spec/requests/api/groups_spec.rb
@@ -1,7 +1,6 @@
require 'spec_helper'
-describe API::Groups, api: true do
- include ApiHelpers
+describe API::Groups do
include UploadHelpers
let(:user1) { create(:user, can_create_group: false) }
diff --git a/spec/requests/api/helpers_spec.rb b/spec/requests/api/helpers_spec.rb
index 988a57a80ea..4845ab1ae1f 100644
--- a/spec/requests/api/helpers_spec.rb
+++ b/spec/requests/api/helpers_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe API::Helpers, api: true do
+describe API::Helpers do
include API::APIGuard::HelperMethods
include API::Helpers
include SentryHelper
diff --git a/spec/requests/api/internal_spec.rb b/spec/requests/api/internal_spec.rb
index 3d6010ede73..429f1a4e375 100644
--- a/spec/requests/api/internal_spec.rb
+++ b/spec/requests/api/internal_spec.rb
@@ -1,7 +1,6 @@
require 'spec_helper'
-describe API::Internal, api: true do
- include ApiHelpers
+describe API::Internal do
let(:user) { create(:user) }
let(:key) { create(:key, user: user) }
let(:project) { create(:project, :repository) }
diff --git a/spec/requests/api/issues_spec.rb b/spec/requests/api/issues_spec.rb
index 551aae7d701..b37be1e0c50 100644
--- a/spec/requests/api/issues_spec.rb
+++ b/spec/requests/api/issues_spec.rb
@@ -1,7 +1,6 @@
require 'spec_helper'
-describe API::Issues, api: true do
- include ApiHelpers
+describe API::Issues do
include EmailHelpers
let(:user) { create(:user) }
diff --git a/spec/requests/api/jobs_spec.rb b/spec/requests/api/jobs_spec.rb
index d8a56c02a63..decb5b91941 100644
--- a/spec/requests/api/jobs_spec.rb
+++ b/spec/requests/api/jobs_spec.rb
@@ -1,8 +1,6 @@
require 'spec_helper'
-describe API::Jobs, api: true do
- include ApiHelpers
-
+describe API::Jobs do
let(:user) { create(:user) }
let(:api_user) { user }
let!(:project) { create(:project, :repository, creator: user, public_builds: false) }
diff --git a/spec/requests/api/keys_spec.rb b/spec/requests/api/keys_spec.rb
index adb33166332..ab957c72984 100644
--- a/spec/requests/api/keys_spec.rb
+++ b/spec/requests/api/keys_spec.rb
@@ -1,8 +1,6 @@
require 'spec_helper'
-describe API::Keys, api: true do
- include ApiHelpers
-
+describe API::Keys do
let(:user) { create(:user) }
let(:admin) { create(:admin) }
let(:key) { create(:key, user: user) }
diff --git a/spec/requests/api/labels_spec.rb b/spec/requests/api/labels_spec.rb
index a1adaba7b98..0c6b55c1630 100644
--- a/spec/requests/api/labels_spec.rb
+++ b/spec/requests/api/labels_spec.rb
@@ -1,8 +1,6 @@
require 'spec_helper'
-describe API::Labels, api: true do
- include ApiHelpers
-
+describe API::Labels do
let(:user) { create(:user) }
let(:project) { create(:empty_project, creator_id: user.id, namespace: user.namespace) }
let!(:label1) { create(:label, title: 'label1', project: project) }
diff --git a/spec/requests/api/lint_spec.rb b/spec/requests/api/lint_spec.rb
index 391fc13a380..df7c91b5bc1 100644
--- a/spec/requests/api/lint_spec.rb
+++ b/spec/requests/api/lint_spec.rb
@@ -1,8 +1,6 @@
require 'spec_helper'
-describe API::Lint, api: true do
- include ApiHelpers
-
+describe API::Lint do
describe 'POST /ci/lint' do
context 'with valid .gitlab-ci.yaml content' do
let(:yaml_content) do
diff --git a/spec/requests/api/members_spec.rb b/spec/requests/api/members_spec.rb
index 84dca51801f..e095053fa03 100644
--- a/spec/requests/api/members_spec.rb
+++ b/spec/requests/api/members_spec.rb
@@ -1,8 +1,6 @@
require 'spec_helper'
-describe API::Members, api: true do
- include ApiHelpers
-
+describe API::Members do
let(:master) { create(:user, username: 'master_user') }
let(:developer) { create(:user) }
let(:access_requester) { create(:user) }
diff --git a/spec/requests/api/merge_request_diffs_spec.rb b/spec/requests/api/merge_request_diffs_spec.rb
index 79f3151ba52..d1b22179888 100644
--- a/spec/requests/api/merge_request_diffs_spec.rb
+++ b/spec/requests/api/merge_request_diffs_spec.rb
@@ -1,8 +1,6 @@
require "spec_helper"
-describe API::MergeRequestDiffs, 'MergeRequestDiffs', api: true do
- include ApiHelpers
-
+describe API::MergeRequestDiffs, 'MergeRequestDiffs' do
let!(:user) { create(:user) }
let!(:merge_request) { create(:merge_request, importing: true) }
let!(:project) { merge_request.target_project }
diff --git a/spec/requests/api/merge_requests_spec.rb b/spec/requests/api/merge_requests_spec.rb
index 61d965e8974..91b1e1aee4d 100644
--- a/spec/requests/api/merge_requests_spec.rb
+++ b/spec/requests/api/merge_requests_spec.rb
@@ -1,12 +1,11 @@
require "spec_helper"
-describe API::MergeRequests, api: true do
- include ApiHelpers
+describe API::MergeRequests do
let(:base_time) { Time.now }
let(:user) { create(:user) }
let(:admin) { create(:user, :admin) }
let(:non_member) { create(:user) }
- let!(:project) { create(:project, :public, :repository, creator: user, namespace: user.namespace) }
+ let!(:project) { create(:project, :public, :repository, creator: user, namespace: user.namespace, only_allow_merge_if_pipeline_succeeds: false) }
let!(:merge_request) { create(:merge_request, :simple, author: user, assignee: user, source_project: project, title: "Test", created_at: base_time) }
let!(:merge_request_closed) { create(:merge_request, state: "closed", author: user, assignee: user, source_project: project, title: "Closed test", created_at: base_time + 1.second) }
let!(:merge_request_merged) { create(:merge_request, state: "merged", author: user, assignee: user, source_project: project, title: "Merged test", created_at: base_time + 2.seconds, merge_commit_sha: '9999999999999999999999999999999999999999') }
@@ -527,6 +526,18 @@ describe API::MergeRequests, api: true do
expect(json_response['merge_when_pipeline_succeeds']).to eq(true)
end
+ it "enables merge when pipeline succeeds if the pipeline is active and only_allow_merge_if_pipeline_succeeds is true" do
+ allow_any_instance_of(MergeRequest).to receive(:head_pipeline).and_return(pipeline)
+ allow(pipeline).to receive(:active?).and_return(true)
+ project.update_attribute(:only_allow_merge_if_pipeline_succeeds, true)
+
+ put api("/projects/#{project.id}/merge_requests/#{merge_request.iid}/merge", user), merge_when_pipeline_succeeds: true
+
+ expect(response).to have_http_status(200)
+ expect(json_response['title']).to eq('Test')
+ expect(json_response['merge_when_pipeline_succeeds']).to eq(true)
+ end
+
it "returns 404 for an invalid merge request IID" do
put api("/projects/#{project.id}/merge_requests/12345/merge", user)
diff --git a/spec/requests/api/milestones_spec.rb b/spec/requests/api/milestones_spec.rb
index 598968aff70..dd74351a2b1 100644
--- a/spec/requests/api/milestones_spec.rb
+++ b/spec/requests/api/milestones_spec.rb
@@ -1,7 +1,6 @@
require 'spec_helper'
-describe API::Milestones, api: true do
- include ApiHelpers
+describe API::Milestones do
let(:user) { create(:user) }
let!(:project) { create(:empty_project, namespace: user.namespace ) }
let!(:closed_milestone) { create(:closed_milestone, project: project, title: 'version1', description: 'closed milestone') }
diff --git a/spec/requests/api/namespaces_spec.rb b/spec/requests/api/namespaces_spec.rb
index da8fa06d0af..3bf16a3ae27 100644
--- a/spec/requests/api/namespaces_spec.rb
+++ b/spec/requests/api/namespaces_spec.rb
@@ -1,7 +1,6 @@
require 'spec_helper'
-describe API::Namespaces, api: true do
- include ApiHelpers
+describe API::Namespaces do
let(:admin) { create(:admin) }
let(:user) { create(:user) }
let!(:group1) { create(:group) }
diff --git a/spec/requests/api/notes_spec.rb b/spec/requests/api/notes_spec.rb
index d8eb8ce921e..6afcd237c3c 100644
--- a/spec/requests/api/notes_spec.rb
+++ b/spec/requests/api/notes_spec.rb
@@ -1,7 +1,6 @@
require 'spec_helper'
-describe API::Notes, api: true do
- include ApiHelpers
+describe API::Notes do
let(:user) { create(:user) }
let!(:project) { create(:empty_project, :public, namespace: user.namespace) }
let!(:issue) { create(:issue, project: project, author: user) }
diff --git a/spec/requests/api/notification_settings_spec.rb b/spec/requests/api/notification_settings_spec.rb
index 39d3afcb78f..f619b7e6eaf 100644
--- a/spec/requests/api/notification_settings_spec.rb
+++ b/spec/requests/api/notification_settings_spec.rb
@@ -1,8 +1,6 @@
require 'spec_helper'
-describe API::NotificationSettings, api: true do
- include ApiHelpers
-
+describe API::NotificationSettings do
let(:user) { create(:user) }
let!(:group) { create(:group) }
let!(:project) { create(:empty_project, :public, creator_id: user.id, namespace: group) }
diff --git a/spec/requests/api/oauth_tokens_spec.rb b/spec/requests/api/oauth_tokens_spec.rb
index 367225df717..819df105960 100644
--- a/spec/requests/api/oauth_tokens_spec.rb
+++ b/spec/requests/api/oauth_tokens_spec.rb
@@ -1,8 +1,6 @@
require 'spec_helper'
-describe API::API, api: true do
- include ApiHelpers
-
+describe API::API do
context 'Resource Owner Password Credentials' do
def request_oauth_token(user)
post '/oauth/token', username: user.username, password: user.password, grant_type: 'password'
diff --git a/spec/requests/api/pipelines_spec.rb b/spec/requests/api/pipelines_spec.rb
index 51af999b455..762345cd41c 100644
--- a/spec/requests/api/pipelines_spec.rb
+++ b/spec/requests/api/pipelines_spec.rb
@@ -1,8 +1,6 @@
require 'spec_helper'
-describe API::Pipelines, api: true do
- include ApiHelpers
-
+describe API::Pipelines do
let(:user) { create(:user) }
let(:non_member) { create(:user) }
let(:project) { create(:project, :repository, creator: user) }
diff --git a/spec/requests/api/project_hooks_spec.rb b/spec/requests/api/project_hooks_spec.rb
index b1603233f9e..aee0e17a153 100644
--- a/spec/requests/api/project_hooks_spec.rb
+++ b/spec/requests/api/project_hooks_spec.rb
@@ -1,7 +1,6 @@
require 'spec_helper'
-describe API::ProjectHooks, 'ProjectHooks', api: true do
- include ApiHelpers
+describe API::ProjectHooks, 'ProjectHooks' do
let(:user) { create(:user) }
let(:user3) { create(:user) }
let!(:project) { create(:empty_project, creator_id: user.id, namespace: user.namespace) }
diff --git a/spec/requests/api/project_snippets_spec.rb b/spec/requests/api/project_snippets_spec.rb
index 9e88c19b0bc..3ab1764f5c3 100644
--- a/spec/requests/api/project_snippets_spec.rb
+++ b/spec/requests/api/project_snippets_spec.rb
@@ -1,8 +1,6 @@
require 'rails_helper'
-describe API::ProjectSnippets, api: true do
- include ApiHelpers
-
+describe API::ProjectSnippets do
let(:project) { create(:empty_project, :public) }
let(:user) { create(:user) }
let(:admin) { create(:admin) }
diff --git a/spec/requests/api/projects_spec.rb b/spec/requests/api/projects_spec.rb
index 74bc4847247..cc03d7a933b 100644
--- a/spec/requests/api/projects_spec.rb
+++ b/spec/requests/api/projects_spec.rb
@@ -1,7 +1,7 @@
# -*- coding: utf-8 -*-
require 'spec_helper'
-describe API::Projects, :api do
+describe API::Projects do
include Gitlab::CurrentSettings
let(:user) { create(:user) }
@@ -24,6 +24,7 @@ describe API::Projects, :api do
namespace: user.namespace,
merge_requests_enabled: false,
issues_enabled: false, wiki_enabled: false,
+ builds_enabled: false,
snippets_enabled: false)
end
let(:project_member3) do
@@ -342,6 +343,7 @@ describe API::Projects, :api do
project = attributes_for(:project, {
path: 'camelCasePath',
issues_enabled: false,
+ jobs_enabled: false,
merge_requests_enabled: false,
wiki_enabled: false,
only_allow_merge_if_pipeline_succeeds: false,
@@ -351,6 +353,8 @@ describe API::Projects, :api do
post api('/projects', user), project
+ expect(response).to have_http_status(201)
+
project.each_pair do |k, v|
next if %i[has_external_issue_tracker issues_enabled merge_requests_enabled wiki_enabled].include?(k)
expect(json_response[k.to_s]).to eq(v)
@@ -1078,7 +1082,9 @@ describe API::Projects, :api do
it 'returns 400 when nothing sent' do
project_param = {}
+
put api("/projects/#{project.id}", user), project_param
+
expect(response).to have_http_status(400)
expect(json_response['error']).to match('at least one parameter must be provided')
end
@@ -1086,7 +1092,9 @@ describe API::Projects, :api do
context 'when unauthenticated' do
it 'returns authentication error' do
project_param = { name: 'bar' }
+
put api("/projects/#{project.id}"), project_param
+
expect(response).to have_http_status(401)
end
end
@@ -1094,8 +1102,11 @@ describe API::Projects, :api do
context 'when authenticated as project owner' do
it 'updates name' do
project_param = { name: 'bar' }
+
put api("/projects/#{project.id}", user), project_param
+
expect(response).to have_http_status(200)
+
project_param.each_pair do |k, v|
expect(json_response[k.to_s]).to eq(v)
end
@@ -1103,8 +1114,11 @@ describe API::Projects, :api do
it 'updates visibility_level' do
project_param = { visibility: 'public' }
+
put api("/projects/#{project3.id}", user), project_param
+
expect(response).to have_http_status(200)
+
project_param.each_pair do |k, v|
expect(json_response[k.to_s]).to eq(v)
end
@@ -1113,17 +1127,23 @@ describe API::Projects, :api do
it 'updates visibility_level from public to private' do
project3.update_attributes({ visibility_level: Gitlab::VisibilityLevel::PUBLIC })
project_param = { visibility: 'private' }
+
put api("/projects/#{project3.id}", user), project_param
+
expect(response).to have_http_status(200)
+
project_param.each_pair do |k, v|
expect(json_response[k.to_s]).to eq(v)
end
+
expect(json_response['visibility']).to eq('private')
end
it 'does not update name to existing name' do
project_param = { name: project3.name }
+
put api("/projects/#{project.id}", user), project_param
+
expect(response).to have_http_status(400)
expect(json_response['message']['name']).to eq(['has already been taken'])
end
@@ -1139,8 +1159,23 @@ describe API::Projects, :api do
it 'updates path & name to existing path & name in different namespace' do
project_param = { path: project4.path, name: project4.name }
+
put api("/projects/#{project3.id}", user), project_param
+
expect(response).to have_http_status(200)
+
+ project_param.each_pair do |k, v|
+ expect(json_response[k.to_s]).to eq(v)
+ end
+ end
+
+ it 'updates jobs_enabled' do
+ project_param = { jobs_enabled: true }
+
+ put api("/projects/#{project3.id}", user), project_param
+
+ expect(response).to have_http_status(200)
+
project_param.each_pair do |k, v|
expect(json_response[k.to_s]).to eq(v)
end
diff --git a/spec/requests/api/repositories_spec.rb b/spec/requests/api/repositories_spec.rb
index 4783d011d54..1a0695615e3 100644
--- a/spec/requests/api/repositories_spec.rb
+++ b/spec/requests/api/repositories_spec.rb
@@ -1,8 +1,7 @@
require 'spec_helper'
require 'mime/types'
-describe API::Repositories, api: true do
- include ApiHelpers
+describe API::Repositories do
include RepoHelpers
include WorkhorseHelpers
diff --git a/spec/requests/api/runner_spec.rb b/spec/requests/api/runner_spec.rb
index 409a59d6c23..be83514ed9c 100644
--- a/spec/requests/api/runner_spec.rb
+++ b/spec/requests/api/runner_spec.rb
@@ -1,7 +1,6 @@
require 'spec_helper'
describe API::Runner do
- include ApiHelpers
include StubGitlabCalls
let(:registration_token) { 'abcdefg123456' }
diff --git a/spec/requests/api/runners_spec.rb b/spec/requests/api/runners_spec.rb
index 8a82543a830..645a5389850 100644
--- a/spec/requests/api/runners_spec.rb
+++ b/spec/requests/api/runners_spec.rb
@@ -1,8 +1,6 @@
require 'spec_helper'
-describe API::Runners, api: true do
- include ApiHelpers
-
+describe API::Runners do
let(:admin) { create(:user, :admin) }
let(:user) { create(:user) }
let(:user2) { create(:user) }
diff --git a/spec/requests/api/services_spec.rb b/spec/requests/api/services_spec.rb
index fd334934ca5..95df3429314 100644
--- a/spec/requests/api/services_spec.rb
+++ b/spec/requests/api/services_spec.rb
@@ -1,8 +1,6 @@
require "spec_helper"
-describe API::Services, api: true do
- include ApiHelpers
-
+describe API::Services do
let(:user) { create(:user) }
let(:admin) { create(:admin) }
let(:user2) { create(:user) }
diff --git a/spec/requests/api/session_spec.rb b/spec/requests/api/session_spec.rb
index 393bf076616..5e77519c867 100644
--- a/spec/requests/api/session_spec.rb
+++ b/spec/requests/api/session_spec.rb
@@ -1,8 +1,6 @@
require 'spec_helper'
-describe API::Session, api: true do
- include ApiHelpers
-
+describe API::Session do
let(:user) { create(:user) }
describe "POST /session" do
diff --git a/spec/requests/api/settings_spec.rb b/spec/requests/api/settings_spec.rb
index 11b4b718e2c..2398ae6219c 100644
--- a/spec/requests/api/settings_spec.rb
+++ b/spec/requests/api/settings_spec.rb
@@ -1,8 +1,6 @@
require 'spec_helper'
-describe API::Settings, 'Settings', api: true do
- include ApiHelpers
-
+describe API::Settings, 'Settings' do
let(:user) { create(:user) }
let(:admin) { create(:admin) }
diff --git a/spec/requests/api/sidekiq_metrics_spec.rb b/spec/requests/api/sidekiq_metrics_spec.rb
index 28067f8ca88..83042d0cb12 100644
--- a/spec/requests/api/sidekiq_metrics_spec.rb
+++ b/spec/requests/api/sidekiq_metrics_spec.rb
@@ -1,8 +1,6 @@
require 'spec_helper'
-describe API::SidekiqMetrics, api: true do
- include ApiHelpers
-
+describe API::SidekiqMetrics do
let(:admin) { create(:user, :admin) }
describe 'GET sidekiq/*' do
diff --git a/spec/requests/api/snippets_spec.rb b/spec/requests/api/snippets_spec.rb
index 5d75b47b3cd..e429cddcf6a 100644
--- a/spec/requests/api/snippets_spec.rb
+++ b/spec/requests/api/snippets_spec.rb
@@ -1,7 +1,6 @@
require 'rails_helper'
-describe API::Snippets, api: true do
- include ApiHelpers
+describe API::Snippets do
let!(:user) { create(:user) }
describe 'GET /snippets/' do
diff --git a/spec/requests/api/system_hooks_spec.rb b/spec/requests/api/system_hooks_spec.rb
index d1e10f12657..c7b84173570 100644
--- a/spec/requests/api/system_hooks_spec.rb
+++ b/spec/requests/api/system_hooks_spec.rb
@@ -1,8 +1,6 @@
require 'spec_helper'
-describe API::SystemHooks, api: true do
- include ApiHelpers
-
+describe API::SystemHooks do
let(:user) { create(:user) }
let(:admin) { create(:admin) }
let!(:hook) { create(:system_hook, url: "http://example.com") }
diff --git a/spec/requests/api/tags_spec.rb b/spec/requests/api/tags_spec.rb
index b132d033a61..ef7d0c3ee41 100644
--- a/spec/requests/api/tags_spec.rb
+++ b/spec/requests/api/tags_spec.rb
@@ -1,8 +1,7 @@
require 'spec_helper'
require 'mime/types'
-describe API::Tags, api: true do
- include ApiHelpers
+describe API::Tags do
include RepoHelpers
let(:user) { create(:user) }
diff --git a/spec/requests/api/templates_spec.rb b/spec/requests/api/templates_spec.rb
index 2c83e119065..cb55985e3f5 100644
--- a/spec/requests/api/templates_spec.rb
+++ b/spec/requests/api/templates_spec.rb
@@ -1,8 +1,6 @@
require 'spec_helper'
-describe API::Templates, api: true do
- include ApiHelpers
-
+describe API::Templates do
context 'the Template Entity' do
before { get api('/templates/gitignores/Ruby') }
diff --git a/spec/requests/api/todos_spec.rb b/spec/requests/api/todos_spec.rb
index b789284fa8d..92533f4dfea 100644
--- a/spec/requests/api/todos_spec.rb
+++ b/spec/requests/api/todos_spec.rb
@@ -1,8 +1,6 @@
require 'spec_helper'
-describe API::Todos, api: true do
- include ApiHelpers
-
+describe API::Todos do
let(:project_1) { create(:empty_project, :test_repo) }
let(:project_2) { create(:empty_project) }
let(:author_1) { create(:user) }
diff --git a/spec/requests/api/triggers_spec.rb b/spec/requests/api/triggers_spec.rb
index d93a734f5b6..16ddade27d9 100644
--- a/spec/requests/api/triggers_spec.rb
+++ b/spec/requests/api/triggers_spec.rb
@@ -1,8 +1,6 @@
require 'spec_helper'
describe API::Triggers do
- include ApiHelpers
-
let(:user) { create(:user) }
let(:user2) { create(:user) }
let!(:trigger_token) { 'secure_token' }
diff --git a/spec/requests/api/users_spec.rb b/spec/requests/api/users_spec.rb
index 1db85da5c2c..4919ad19833 100644
--- a/spec/requests/api/users_spec.rb
+++ b/spec/requests/api/users_spec.rb
@@ -1,9 +1,7 @@
require 'spec_helper'
-describe API::Users, api: true do
- include ApiHelpers
-
- let(:user) { create(:user) }
+describe API::Users do
+ let(:user) { create(:user) }
let(:admin) { create(:admin) }
let(:key) { create(:key, user: user) }
let(:email) { create(:email, user: user) }
diff --git a/spec/requests/api/v3/award_emoji_spec.rb b/spec/requests/api/v3/award_emoji_spec.rb
index eeb4d128c1b..9234710f488 100644
--- a/spec/requests/api/v3/award_emoji_spec.rb
+++ b/spec/requests/api/v3/award_emoji_spec.rb
@@ -1,8 +1,6 @@
require 'spec_helper'
-describe API::V3::AwardEmoji, api: true do
- include ApiHelpers
-
+describe API::V3::AwardEmoji do
let(:user) { create(:user) }
let!(:project) { create(:empty_project) }
let(:issue) { create(:issue, project: project) }
diff --git a/spec/requests/api/v3/boards_spec.rb b/spec/requests/api/v3/boards_spec.rb
index eb95934f354..4d786331d1b 100644
--- a/spec/requests/api/v3/boards_spec.rb
+++ b/spec/requests/api/v3/boards_spec.rb
@@ -1,8 +1,6 @@
require 'spec_helper'
-describe API::V3::Boards, api: true do
- include ApiHelpers
-
+describe API::V3::Boards do
let(:user) { create(:user) }
let(:guest) { create(:user) }
let(:non_member) { create(:user) }
diff --git a/spec/requests/api/v3/branches_spec.rb b/spec/requests/api/v3/branches_spec.rb
index 5dcd4f21f4e..72f8fbe71fb 100644
--- a/spec/requests/api/v3/branches_spec.rb
+++ b/spec/requests/api/v3/branches_spec.rb
@@ -1,9 +1,7 @@
require 'spec_helper'
require 'mime/types'
-describe API::V3::Branches, api: true do
- include ApiHelpers
-
+describe API::V3::Branches do
let(:user) { create(:user) }
let(:user2) { create(:user) }
let!(:project) { create(:project, :repository, creator: user) }
diff --git a/spec/requests/api/v3/broadcast_messages_spec.rb b/spec/requests/api/v3/broadcast_messages_spec.rb
index 06556401a29..948cd78c177 100644
--- a/spec/requests/api/v3/broadcast_messages_spec.rb
+++ b/spec/requests/api/v3/broadcast_messages_spec.rb
@@ -1,8 +1,6 @@
require 'spec_helper'
-describe API::V3::BroadcastMessages, api: true do
- include ApiHelpers
-
+describe API::V3::BroadcastMessages do
let(:user) { create(:user) }
let(:admin) { create(:admin) }
diff --git a/spec/requests/api/v3/builds_spec.rb b/spec/requests/api/v3/builds_spec.rb
index e97d2b0cee0..dc95599546c 100644
--- a/spec/requests/api/v3/builds_spec.rb
+++ b/spec/requests/api/v3/builds_spec.rb
@@ -1,8 +1,6 @@
require 'spec_helper'
-describe API::V3::Builds, api: true do
- include ApiHelpers
-
+describe API::V3::Builds do
let(:user) { create(:user) }
let(:api_user) { user }
let!(:project) { create(:project, :repository, creator: user, public_builds: false) }
diff --git a/spec/requests/api/v3/commits_spec.rb b/spec/requests/api/v3/commits_spec.rb
index 0a28cb9bddb..c2e8c3ae6f7 100644
--- a/spec/requests/api/v3/commits_spec.rb
+++ b/spec/requests/api/v3/commits_spec.rb
@@ -1,8 +1,7 @@
require 'spec_helper'
require 'mime/types'
-describe API::V3::Commits, api: true do
- include ApiHelpers
+describe API::V3::Commits do
let(:user) { create(:user) }
let(:user2) { create(:user) }
let!(:project) { create(:project, :repository, creator: user, namespace: user.namespace) }
diff --git a/spec/requests/api/v3/deploy_keys_spec.rb b/spec/requests/api/v3/deploy_keys_spec.rb
index f5bdf408c5e..b61b2b618a6 100644
--- a/spec/requests/api/v3/deploy_keys_spec.rb
+++ b/spec/requests/api/v3/deploy_keys_spec.rb
@@ -1,8 +1,6 @@
require 'spec_helper'
-describe API::V3::DeployKeys, api: true do
- include ApiHelpers
-
+describe API::V3::DeployKeys do
let(:user) { create(:user) }
let(:admin) { create(:admin) }
let(:project) { create(:empty_project, creator_id: user.id) }
diff --git a/spec/requests/api/v3/deployments_spec.rb b/spec/requests/api/v3/deployments_spec.rb
index 3c5ce407b32..694786c3046 100644
--- a/spec/requests/api/v3/deployments_spec.rb
+++ b/spec/requests/api/v3/deployments_spec.rb
@@ -1,8 +1,6 @@
require 'spec_helper'
-describe API::Deployments, api: true do
- include ApiHelpers
-
+describe API::Deployments do
let(:user) { create(:user) }
let(:non_member) { create(:user) }
let(:project) { deployment.environment.project }
diff --git a/spec/requests/api/v3/environments_spec.rb b/spec/requests/api/v3/environments_spec.rb
index 216192c9d34..99f35723974 100644
--- a/spec/requests/api/v3/environments_spec.rb
+++ b/spec/requests/api/v3/environments_spec.rb
@@ -1,8 +1,6 @@
require 'spec_helper'
-describe API::V3::Environments, api: true do
- include ApiHelpers
-
+describe API::V3::Environments do
let(:user) { create(:user) }
let(:non_member) { create(:user) }
let(:project) { create(:empty_project, :private, namespace: user.namespace) }
diff --git a/spec/requests/api/v3/files_spec.rb b/spec/requests/api/v3/files_spec.rb
index c45e2028e1d..5bcbb441979 100644
--- a/spec/requests/api/v3/files_spec.rb
+++ b/spec/requests/api/v3/files_spec.rb
@@ -1,8 +1,6 @@
require 'spec_helper'
-describe API::V3::Files, api: true do
- include ApiHelpers
-
+describe API::V3::Files do
# I have to remove periods from the end of the name
# This happened when the user's name had a suffix (i.e. "Sr.")
# This seems to be what git does under the hood. For example, this commit:
diff --git a/spec/requests/api/v3/groups_spec.rb b/spec/requests/api/v3/groups_spec.rb
index a71b7d4b008..2862580cc70 100644
--- a/spec/requests/api/v3/groups_spec.rb
+++ b/spec/requests/api/v3/groups_spec.rb
@@ -1,7 +1,6 @@
require 'spec_helper'
-describe API::V3::Groups, api: true do
- include ApiHelpers
+describe API::V3::Groups do
include UploadHelpers
let(:user1) { create(:user, can_create_group: false) }
diff --git a/spec/requests/api/v3/issues_spec.rb b/spec/requests/api/v3/issues_spec.rb
index 91d9057075f..ef5b10a1615 100644
--- a/spec/requests/api/v3/issues_spec.rb
+++ b/spec/requests/api/v3/issues_spec.rb
@@ -1,7 +1,6 @@
require 'spec_helper'
-describe API::V3::Issues, api: true do
- include ApiHelpers
+describe API::V3::Issues do
include EmailHelpers
let(:user) { create(:user) }
diff --git a/spec/requests/api/v3/labels_spec.rb b/spec/requests/api/v3/labels_spec.rb
index dfac357d37c..62faa1cb129 100644
--- a/spec/requests/api/v3/labels_spec.rb
+++ b/spec/requests/api/v3/labels_spec.rb
@@ -1,8 +1,6 @@
require 'spec_helper'
-describe API::V3::Labels, api: true do
- include ApiHelpers
-
+describe API::V3::Labels do
let(:user) { create(:user) }
let(:project) { create(:empty_project, creator_id: user.id, namespace: user.namespace) }
let!(:label1) { create(:label, title: 'label1', project: project) }
diff --git a/spec/requests/api/v3/members_spec.rb b/spec/requests/api/v3/members_spec.rb
index af1c5cff67f..623f02902b8 100644
--- a/spec/requests/api/v3/members_spec.rb
+++ b/spec/requests/api/v3/members_spec.rb
@@ -1,8 +1,6 @@
require 'spec_helper'
-describe API::V3::Members, api: true do
- include ApiHelpers
-
+describe API::V3::Members do
let(:master) { create(:user, username: 'master_user') }
let(:developer) { create(:user) }
let(:access_requester) { create(:user) }
diff --git a/spec/requests/api/v3/merge_request_diffs_spec.rb b/spec/requests/api/v3/merge_request_diffs_spec.rb
index c53800eef30..8020ddab4c8 100644
--- a/spec/requests/api/v3/merge_request_diffs_spec.rb
+++ b/spec/requests/api/v3/merge_request_diffs_spec.rb
@@ -1,8 +1,6 @@
require "spec_helper"
-describe API::V3::MergeRequestDiffs, 'MergeRequestDiffs', api: true do
- include ApiHelpers
-
+describe API::V3::MergeRequestDiffs, 'MergeRequestDiffs' do
let!(:user) { create(:user) }
let!(:merge_request) { create(:merge_request, importing: true) }
let!(:project) { merge_request.target_project }
diff --git a/spec/requests/api/v3/merge_requests_spec.rb b/spec/requests/api/v3/merge_requests_spec.rb
index d73e9635c9b..6c2950a6e6f 100644
--- a/spec/requests/api/v3/merge_requests_spec.rb
+++ b/spec/requests/api/v3/merge_requests_spec.rb
@@ -1,7 +1,6 @@
require "spec_helper"
-describe API::MergeRequests, api: true do
- include ApiHelpers
+describe API::MergeRequests do
let(:base_time) { Time.now }
let(:user) { create(:user) }
let(:admin) { create(:user, :admin) }
diff --git a/spec/requests/api/v3/milestones_spec.rb b/spec/requests/api/v3/milestones_spec.rb
index 127c0eec881..f04efc990a7 100644
--- a/spec/requests/api/v3/milestones_spec.rb
+++ b/spec/requests/api/v3/milestones_spec.rb
@@ -1,7 +1,6 @@
require 'spec_helper'
-describe API::V3::Milestones, api: true do
- include ApiHelpers
+describe API::V3::Milestones do
let(:user) { create(:user) }
let!(:project) { create(:empty_project, namespace: user.namespace ) }
let!(:closed_milestone) { create(:closed_milestone, project: project) }
diff --git a/spec/requests/api/v3/notes_spec.rb b/spec/requests/api/v3/notes_spec.rb
index ddef2d5eb04..2bae4a60931 100644
--- a/spec/requests/api/v3/notes_spec.rb
+++ b/spec/requests/api/v3/notes_spec.rb
@@ -1,8 +1,6 @@
require 'spec_helper'
-describe API::V3::Notes, api: true do
- include ApiHelpers
-
+describe API::V3::Notes do
let(:user) { create(:user) }
let!(:project) { create(:empty_project, :public, namespace: user.namespace) }
let!(:issue) { create(:issue, project: project, author: user) }
diff --git a/spec/requests/api/v3/pipelines_spec.rb b/spec/requests/api/v3/pipelines_spec.rb
index 3786eb06932..e1d036ff365 100644
--- a/spec/requests/api/v3/pipelines_spec.rb
+++ b/spec/requests/api/v3/pipelines_spec.rb
@@ -1,8 +1,6 @@
require 'spec_helper'
-describe API::V3::Pipelines, api: true do
- include ApiHelpers
-
+describe API::V3::Pipelines do
let(:user) { create(:user) }
let(:non_member) { create(:user) }
let(:project) { create(:project, :repository, creator: user) }
diff --git a/spec/requests/api/v3/project_hooks_spec.rb b/spec/requests/api/v3/project_hooks_spec.rb
index a981119dc5a..a3a4c77d09d 100644
--- a/spec/requests/api/v3/project_hooks_spec.rb
+++ b/spec/requests/api/v3/project_hooks_spec.rb
@@ -1,7 +1,6 @@
require 'spec_helper'
-describe API::ProjectHooks, 'ProjectHooks', api: true do
- include ApiHelpers
+describe API::ProjectHooks, 'ProjectHooks' do
let(:user) { create(:user) }
let(:user3) { create(:user) }
let!(:project) { create(:project, creator_id: user.id, namespace: user.namespace) }
diff --git a/spec/requests/api/v3/project_snippets_spec.rb b/spec/requests/api/v3/project_snippets_spec.rb
index 957a3bf97ef..365e7365fda 100644
--- a/spec/requests/api/v3/project_snippets_spec.rb
+++ b/spec/requests/api/v3/project_snippets_spec.rb
@@ -1,8 +1,6 @@
require 'rails_helper'
-describe API::ProjectSnippets, api: true do
- include ApiHelpers
-
+describe API::ProjectSnippets do
let(:project) { create(:empty_project, :public) }
let(:user) { create(:user) }
let(:admin) { create(:admin) }
diff --git a/spec/requests/api/v3/projects_spec.rb b/spec/requests/api/v3/projects_spec.rb
index 40531fe7545..e15b90d7a9e 100644
--- a/spec/requests/api/v3/projects_spec.rb
+++ b/spec/requests/api/v3/projects_spec.rb
@@ -1,7 +1,6 @@
require 'spec_helper'
-describe API::V3::Projects, api: true do
- include ApiHelpers
+describe API::V3::Projects do
include Gitlab::CurrentSettings
let(:user) { create(:user) }
diff --git a/spec/requests/api/v3/repositories_spec.rb b/spec/requests/api/v3/repositories_spec.rb
index fef6fb641fa..1a55e2a71cd 100644
--- a/spec/requests/api/v3/repositories_spec.rb
+++ b/spec/requests/api/v3/repositories_spec.rb
@@ -1,8 +1,7 @@
require 'spec_helper'
require 'mime/types'
-describe API::V3::Repositories, api: true do
- include ApiHelpers
+describe API::V3::Repositories do
include RepoHelpers
include WorkhorseHelpers
diff --git a/spec/requests/api/v3/runners_spec.rb b/spec/requests/api/v3/runners_spec.rb
index ca335ce9cf0..dbda2cf34c3 100644
--- a/spec/requests/api/v3/runners_spec.rb
+++ b/spec/requests/api/v3/runners_spec.rb
@@ -1,8 +1,6 @@
require 'spec_helper'
-describe API::V3::Runners, api: true do
- include ApiHelpers
-
+describe API::V3::Runners do
let(:admin) { create(:user, :admin) }
let(:user) { create(:user) }
let(:user2) { create(:user) }
diff --git a/spec/requests/api/v3/services_spec.rb b/spec/requests/api/v3/services_spec.rb
index 3a760a8f25c..3ba62de822a 100644
--- a/spec/requests/api/v3/services_spec.rb
+++ b/spec/requests/api/v3/services_spec.rb
@@ -1,8 +1,6 @@
require "spec_helper"
-describe API::V3::Services, api: true do
- include ApiHelpers
-
+describe API::V3::Services do
let(:user) { create(:user) }
let(:project) { create(:empty_project, creator_id: user.id, namespace: user.namespace) }
diff --git a/spec/requests/api/v3/settings_spec.rb b/spec/requests/api/v3/settings_spec.rb
index a9fa5adac17..41d039b7da0 100644
--- a/spec/requests/api/v3/settings_spec.rb
+++ b/spec/requests/api/v3/settings_spec.rb
@@ -1,8 +1,6 @@
require 'spec_helper'
-describe API::V3::Settings, 'Settings', api: true do
- include ApiHelpers
-
+describe API::V3::Settings, 'Settings' do
let(:user) { create(:user) }
let(:admin) { create(:admin) }
diff --git a/spec/requests/api/v3/snippets_spec.rb b/spec/requests/api/v3/snippets_spec.rb
index 05653bd0d51..4f02b7b1a54 100644
--- a/spec/requests/api/v3/snippets_spec.rb
+++ b/spec/requests/api/v3/snippets_spec.rb
@@ -1,7 +1,6 @@
require 'rails_helper'
-describe API::V3::Snippets, api: true do
- include ApiHelpers
+describe API::V3::Snippets do
let!(:user) { create(:user) }
describe 'GET /snippets/' do
diff --git a/spec/requests/api/v3/system_hooks_spec.rb b/spec/requests/api/v3/system_hooks_spec.rb
index 91038977c82..72c7d14b8ba 100644
--- a/spec/requests/api/v3/system_hooks_spec.rb
+++ b/spec/requests/api/v3/system_hooks_spec.rb
@@ -1,8 +1,6 @@
require 'spec_helper'
-describe API::V3::SystemHooks, api: true do
- include ApiHelpers
-
+describe API::V3::SystemHooks do
let(:user) { create(:user) }
let(:admin) { create(:admin) }
let!(:hook) { create(:system_hook, url: "http://example.com") }
diff --git a/spec/requests/api/v3/tags_spec.rb b/spec/requests/api/v3/tags_spec.rb
index 6870cfd2668..1c4b25c47c3 100644
--- a/spec/requests/api/v3/tags_spec.rb
+++ b/spec/requests/api/v3/tags_spec.rb
@@ -1,8 +1,7 @@
require 'spec_helper'
require 'mime/types'
-describe API::V3::Tags, api: true do
- include ApiHelpers
+describe API::V3::Tags do
include RepoHelpers
let(:user) { create(:user) }
diff --git a/spec/requests/api/v3/templates_spec.rb b/spec/requests/api/v3/templates_spec.rb
index f1e554b98cc..00446c7f29c 100644
--- a/spec/requests/api/v3/templates_spec.rb
+++ b/spec/requests/api/v3/templates_spec.rb
@@ -1,8 +1,6 @@
require 'spec_helper'
-describe API::V3::Templates, api: true do
- include ApiHelpers
-
+describe API::V3::Templates do
shared_examples_for 'the Template Entity' do |path|
before { get v3_api(path) }
diff --git a/spec/requests/api/v3/todos_spec.rb b/spec/requests/api/v3/todos_spec.rb
index 80fa697e949..9c2c4d64257 100644
--- a/spec/requests/api/v3/todos_spec.rb
+++ b/spec/requests/api/v3/todos_spec.rb
@@ -1,8 +1,6 @@
require 'spec_helper'
-describe API::V3::Todos, api: true do
- include ApiHelpers
-
+describe API::V3::Todos do
let(:project_1) { create(:empty_project) }
let(:project_2) { create(:empty_project) }
let(:author_1) { create(:user) }
diff --git a/spec/requests/api/v3/triggers_spec.rb b/spec/requests/api/v3/triggers_spec.rb
index 9233e9621bf..d3de6bf13bc 100644
--- a/spec/requests/api/v3/triggers_spec.rb
+++ b/spec/requests/api/v3/triggers_spec.rb
@@ -1,8 +1,6 @@
require 'spec_helper'
describe API::V3::Triggers do
- include ApiHelpers
-
let(:user) { create(:user) }
let(:user2) { create(:user) }
let!(:trigger_token) { 'secure_token' }
diff --git a/spec/requests/api/v3/users_spec.rb b/spec/requests/api/v3/users_spec.rb
index 19465a9a4ea..e9c57f7c6c3 100644
--- a/spec/requests/api/v3/users_spec.rb
+++ b/spec/requests/api/v3/users_spec.rb
@@ -1,8 +1,6 @@
require 'spec_helper'
-describe API::V3::Users, api: true do
- include ApiHelpers
-
+describe API::V3::Users do
let(:user) { create(:user) }
let(:admin) { create(:admin) }
let(:key) { create(:key, user: user) }
diff --git a/spec/requests/api/variables_spec.rb b/spec/requests/api/variables_spec.rb
index 0c1413119e0..63d6d3001ac 100644
--- a/spec/requests/api/variables_spec.rb
+++ b/spec/requests/api/variables_spec.rb
@@ -1,8 +1,6 @@
require 'spec_helper'
-describe API::Variables, api: true do
- include ApiHelpers
-
+describe API::Variables do
let(:user) { create(:user) }
let(:user2) { create(:user) }
let!(:project) { create(:empty_project, creator_id: user.id) }
diff --git a/spec/requests/api/version_spec.rb b/spec/requests/api/version_spec.rb
index da1b2fda70e..8870d48bbc9 100644
--- a/spec/requests/api/version_spec.rb
+++ b/spec/requests/api/version_spec.rb
@@ -1,8 +1,6 @@
require 'spec_helper'
-describe API::Version, api: true do
- include ApiHelpers
-
+describe API::Version do
describe 'GET /version' do
context 'when unauthenticated' do
it 'returns authentication error' do
diff --git a/spec/requests/ci/api/builds_spec.rb b/spec/requests/ci/api/builds_spec.rb
index ef30d8638dd..108f73bb965 100644
--- a/spec/requests/ci/api/builds_spec.rb
+++ b/spec/requests/ci/api/builds_spec.rb
@@ -1,8 +1,6 @@
require 'spec_helper'
describe Ci::API::Builds do
- include ApiHelpers
-
let(:runner) { FactoryGirl.create(:ci_runner, tag_list: %w(mysql ruby)) }
let(:project) { FactoryGirl.create(:empty_project, shared_runners_enabled: false) }
let(:last_update) { nil }
diff --git a/spec/requests/ci/api/runners_spec.rb b/spec/requests/ci/api/runners_spec.rb
index d50cdfdc2d6..0b9733221d8 100644
--- a/spec/requests/ci/api/runners_spec.rb
+++ b/spec/requests/ci/api/runners_spec.rb
@@ -1,7 +1,6 @@
require 'spec_helper'
describe Ci::API::Runners do
- include ApiHelpers
include StubGitlabCalls
let(:registration_token) { 'abcdefg123456' }
diff --git a/spec/requests/ci/api/triggers_spec.rb b/spec/requests/ci/api/triggers_spec.rb
index 5321f8b134f..26b03c0f148 100644
--- a/spec/requests/ci/api/triggers_spec.rb
+++ b/spec/requests/ci/api/triggers_spec.rb
@@ -1,8 +1,6 @@
require 'spec_helper'
describe Ci::API::Triggers do
- include ApiHelpers
-
describe 'POST /projects/:project_id/refs/:ref/trigger' do
let!(:trigger_token) { 'secure token' }
let!(:project) { create(:project, :repository, ci_id: 10) }
diff --git a/spec/requests/git_http_spec.rb b/spec/requests/git_http_spec.rb
index 316742ff076..6ca3ef18fe6 100644
--- a/spec/requests/git_http_spec.rb
+++ b/spec/requests/git_http_spec.rb
@@ -279,10 +279,10 @@ describe 'Git HTTP requests', lib: true do
expect(response.content_type.to_s).to eq(Gitlab::Workhorse::INTERNAL_API_CONTENT_TYPE)
end
- it "uploads get status 401 (no project existence information leak)" do
+ it "uploads get status 200" do
push_get "#{project.path_with_namespace}.git", user: 'oauth2', password: @token.token
- expect(response).to have_http_status(401)
+ expect(response).to have_http_status(200)
end
end
diff --git a/spec/requests/openid_connect_spec.rb b/spec/requests/openid_connect_spec.rb
index 5206634bca5..a4f85c22943 100644
--- a/spec/requests/openid_connect_spec.rb
+++ b/spec/requests/openid_connect_spec.rb
@@ -1,8 +1,6 @@
require 'spec_helper'
describe 'OpenID Connect requests' do
- include ApiHelpers
-
let(:user) { create :user }
let(:access_grant) { create :oauth_access_grant, application: application, resource_owner_id: user.id }
let(:access_token) { create :oauth_access_token, application: application, resource_owner_id: user.id }
diff --git a/spec/requests/projects/cycle_analytics_events_spec.rb b/spec/requests/projects/cycle_analytics_events_spec.rb
index 0edbffbcd3b..33940f70b1c 100644
--- a/spec/requests/projects/cycle_analytics_events_spec.rb
+++ b/spec/requests/projects/cycle_analytics_events_spec.rb
@@ -1,8 +1,6 @@
require 'spec_helper'
-describe 'cycle analytics events' do
- include ApiHelpers
-
+describe 'cycle analytics events', api: true do
let(:user) { create(:user) }
let(:project) { create(:project, :repository, public_builds: false) }
let(:issue) { create(:issue, project: project, created_at: 2.days.ago) }
diff --git a/spec/services/ci/expire_pipeline_cache_service_spec.rb b/spec/services/ci/expire_pipeline_cache_service_spec.rb
deleted file mode 100644
index 166c6dfc93e..00000000000
--- a/spec/services/ci/expire_pipeline_cache_service_spec.rb
+++ /dev/null
@@ -1,27 +0,0 @@
-require 'spec_helper'
-
-describe Ci::ExpirePipelineCacheService, services: true do
- let(:user) { create(:user) }
- let(:project) { create(:empty_project) }
- let(:pipeline) { create(:ci_pipeline, project: project) }
- subject { described_class.new(project, user) }
-
- describe '#execute' do
- it 'invalidate Etag caching for project pipelines path' do
- pipelines_path = "/#{project.full_path}/pipelines.json"
- new_mr_pipelines_path = "/#{project.full_path}/merge_requests/new.json"
-
- expect_any_instance_of(Gitlab::EtagCaching::Store).to receive(:touch).with(pipelines_path)
- expect_any_instance_of(Gitlab::EtagCaching::Store).to receive(:touch).with(new_mr_pipelines_path)
-
- subject.execute(pipeline)
- end
-
- it 'updates the cached status for a project' do
- expect(Gitlab::Cache::Ci::ProjectPipelineStatus).to receive(:update_for_pipeline).
- with(pipeline)
-
- subject.execute(pipeline)
- end
- end
-end
diff --git a/spec/services/users/migrate_to_ghost_user_service_spec.rb b/spec/services/users/migrate_to_ghost_user_service_spec.rb
index 8c5b7e41c15..9e1edf1ac30 100644
--- a/spec/services/users/migrate_to_ghost_user_service_spec.rb
+++ b/spec/services/users/migrate_to_ghost_user_service_spec.rb
@@ -60,5 +60,23 @@ describe Users::MigrateToGhostUserService, services: true do
end
end
end
+
+ context "when record migration fails with a rollback exception" do
+ before do
+ expect_any_instance_of(MergeRequest::ActiveRecord_Associations_CollectionProxy)
+ .to receive(:update_all).and_raise(ActiveRecord::Rollback)
+ end
+
+ context "for records that were already migrated" do
+ let!(:issue) { create(:issue, project: project, author: user) }
+ let!(:merge_request) { create(:merge_request, source_project: project, author: user, target_branch: "first") }
+
+ it "reverses the migration" do
+ service.execute
+
+ expect(issue.reload.author).to eq(user)
+ end
+ end
+ end
end
end
diff --git a/spec/support/features/issuable_slash_commands_shared_examples.rb b/spec/support/features/issuable_slash_commands_shared_examples.rb
index a4713e53f63..5bbe36d9b7f 100644
--- a/spec/support/features/issuable_slash_commands_shared_examples.rb
+++ b/spec/support/features/issuable_slash_commands_shared_examples.rb
@@ -3,7 +3,6 @@
shared_examples 'issuable record that supports slash commands in its description and notes' do |issuable_type|
include SlashCommandsHelpers
- include WaitForAjax
let(:master) { create(:user) }
let(:assignee) { create(:user, username: 'bob') }
diff --git a/spec/support/login_helpers.rb b/spec/support/login_helpers.rb
index 9ffb00be0b8..e6da852e728 100644
--- a/spec/support/login_helpers.rb
+++ b/spec/support/login_helpers.rb
@@ -84,8 +84,4 @@ module LoginHelpers
def logout_direct
page.driver.submit :delete, '/users/sign_out', {}
end
-
- def skip_ci_admin_auth
- allow_any_instance_of(Ci::Admin::ApplicationController).to receive_messages(authenticate_admin!: true)
- end
end
diff --git a/spec/support/markdown_feature.rb b/spec/support/markdown_feature.rb
index dea0015f105..21a054af4e1 100644
--- a/spec/support/markdown_feature.rb
+++ b/spec/support/markdown_feature.rb
@@ -23,7 +23,7 @@ class MarkdownFeature
# Direct references ----------------------------------------------------------
def project
- @project ||= create(:project).tap do |project|
+ @project ||= create(:project, :repository).tap do |project|
project.team << [user, :master]
end
end
@@ -80,7 +80,7 @@ class MarkdownFeature
def xproject
@xproject ||= begin
group = create(:group, :nested)
- create(:project, namespace: group) do |project|
+ create(:project, :repository, namespace: group) do |project|
project.team << [user, :developer]
end
end
diff --git a/spec/support/services/migrate_to_ghost_user_service_shared_examples.rb b/spec/support/services/migrate_to_ghost_user_service_shared_examples.rb
index 0eac587e973..dcc562c684b 100644
--- a/spec/support/services/migrate_to_ghost_user_service_shared_examples.rb
+++ b/spec/support/services/migrate_to_ghost_user_service_shared_examples.rb
@@ -35,5 +35,57 @@ shared_examples "migrating a deleted user's associated records to the ghost user
expect(user).to be_blocked
end
+
+ context "race conditions" do
+ context "when #{record_class_name} migration fails and is rolled back" do
+ before do
+ expect_any_instance_of(record_class::ActiveRecord_Associations_CollectionProxy)
+ .to receive(:update_all).and_raise(ActiveRecord::Rollback)
+ end
+
+ it 'rolls back the user block' do
+ service.execute
+
+ expect(user.reload).not_to be_blocked
+ end
+
+ it "doesn't unblock an previously-blocked user" do
+ user.block
+
+ service.execute
+
+ expect(user.reload).to be_blocked
+ end
+ end
+
+ context "when #{record_class_name} migration fails with a non-rollback exception" do
+ before do
+ expect_any_instance_of(record_class::ActiveRecord_Associations_CollectionProxy)
+ .to receive(:update_all).and_raise(ArgumentError)
+ end
+
+ it 'rolls back the user block' do
+ service.execute rescue nil
+
+ expect(user.reload).not_to be_blocked
+ end
+
+ it "doesn't unblock an previously-blocked user" do
+ user.block
+
+ service.execute rescue nil
+
+ expect(user.reload).to be_blocked
+ end
+ end
+
+ it "blocks the user before #{record_class_name} migration begins" do
+ expect(service).to receive("migrate_#{record_class_name.parameterize('_')}s".to_sym) do
+ expect(user.reload).to be_blocked
+ end
+
+ service.execute
+ end
+ end
end
end
diff --git a/spec/support/test_env.rb b/spec/support/test_env.rb
index 60c2096a126..5c8ee8d62f5 100644
--- a/spec/support/test_env.rb
+++ b/spec/support/test_env.rb
@@ -38,7 +38,8 @@ module TestEnv
'deleted-image-test' => '6c17798',
'wip' => 'b9238ee',
'csv' => '3dd0896',
- 'v1.1.0' => 'b83d6e3'
+ 'v1.1.0' => 'b83d6e3',
+ 'add-ipython-files' => '6d85bb69'
}.freeze
# gitlab-test-fork is a fork of gitlab-fork, but we don't necessarily
@@ -124,12 +125,13 @@ module TestEnv
raise "Can't clone gitaly"
end
- start_gitaly(gitaly_dir, socket_path)
+ start_gitaly(gitaly_dir)
end
- def start_gitaly(gitaly_dir, socket_path)
+ def start_gitaly(gitaly_dir)
gitaly_exec = File.join(gitaly_dir, 'gitaly')
- @gitaly_pid = spawn({ "GITALY_SOCKET_PATH" => socket_path }, gitaly_exec, [:out, :err] => '/dev/null')
+ gitaly_config = File.join(gitaly_dir, 'config.toml')
+ @gitaly_pid = spawn(gitaly_exec, gitaly_config, [:out, :err] => '/dev/null')
end
def stop_gitaly
diff --git a/spec/support/wait_for_ajax.rb b/spec/support/wait_for_ajax.rb
index 0f9dc2dee75..508de2ee8e1 100644
--- a/spec/support/wait_for_ajax.rb
+++ b/spec/support/wait_for_ajax.rb
@@ -6,10 +6,13 @@ module WaitForAjax
end
def finished_all_ajax_requests?
+ return true unless javascript_test?
+ return true if page.evaluate_script('typeof jQuery === "undefined"')
+
page.evaluate_script('jQuery.active').zero?
end
def javascript_test?
- [:selenium, :webkit, :chrome, :poltergeist].include?(Capybara.current_driver)
+ Capybara.current_driver == Capybara.javascript_driver
end
end
diff --git a/spec/views/projects/_last_commit.html.haml_spec.rb b/spec/views/projects/_last_commit.html.haml_spec.rb
new file mode 100644
index 00000000000..eea1695b171
--- /dev/null
+++ b/spec/views/projects/_last_commit.html.haml_spec.rb
@@ -0,0 +1,22 @@
+require 'spec_helper'
+
+describe 'projects/_last_commit', :view do
+ let(:project) { create(:project, :repository) }
+
+ context 'when there is a pipeline present for the commit' do
+ context 'when pipeline is blocked' do
+ let!(:pipeline) do
+ create(:ci_pipeline, :blocked, project: project,
+ sha: project.commit.id)
+ end
+
+ it 'shows correct pipeline badge' do
+ render 'projects/last_commit', commit: project.commit,
+ project: project,
+ ref: :master
+
+ expect(rendered).to have_text "blocked #{project.commit.short_id}"
+ end
+ end
+ end
+end
diff --git a/spec/views/projects/commit/_commit_box.html.haml_spec.rb b/spec/views/projects/commit/_commit_box.html.haml_spec.rb
index cec87dcecc8..ab120929c6c 100644
--- a/spec/views/projects/commit/_commit_box.html.haml_spec.rb
+++ b/spec/views/projects/commit/_commit_box.html.haml_spec.rb
@@ -1,8 +1,6 @@
require 'spec_helper'
-describe 'projects/commit/_commit_box.html.haml' do
- include Devise::Test::ControllerHelpers
-
+describe 'projects/commit/_commit_box.html.haml', :view do
let(:user) { create(:user) }
let(:project) { create(:project, :repository) }
@@ -18,14 +16,32 @@ describe 'projects/commit/_commit_box.html.haml' do
expect(rendered).to have_text("#{Commit.truncate_sha(project.commit.sha)}")
end
- it 'shows the last pipeline that ran for the commit' do
- create(:ci_pipeline, project: project, sha: project.commit.id, status: 'success')
- create(:ci_pipeline, project: project, sha: project.commit.id, status: 'canceled')
- third_pipeline = create(:ci_pipeline, project: project, sha: project.commit.id, status: 'failed')
+ context 'when there is a pipeline present' do
+ context 'when there are multiple pipelines for a commit' do
+ it 'shows the last pipeline' do
+ create(:ci_pipeline, project: project, sha: project.commit.id, status: 'success')
+ create(:ci_pipeline, project: project, sha: project.commit.id, status: 'canceled')
+ third_pipeline = create(:ci_pipeline, project: project, sha: project.commit.id, status: 'failed')
- render
+ render
+
+ expect(rendered).to have_text("Pipeline ##{third_pipeline.id} failed")
+ end
+ end
- expect(rendered).to have_text("Pipeline ##{third_pipeline.id} failed")
+ context 'when pipeline for the commit is blocked' do
+ let!(:pipeline) do
+ create(:ci_pipeline, :blocked, project: project,
+ sha: project.commit.id)
+ end
+
+ it 'shows correct pipeline description' do
+ render
+
+ expect(rendered).to have_text "Pipeline ##{pipeline.id} " \
+ 'waiting for manual action'
+ end
+ end
end
context 'viewing a commit' do
diff --git a/spec/workers/expire_pipeline_cache_worker_spec.rb b/spec/workers/expire_pipeline_cache_worker_spec.rb
new file mode 100644
index 00000000000..ceba604dea2
--- /dev/null
+++ b/spec/workers/expire_pipeline_cache_worker_spec.rb
@@ -0,0 +1,44 @@
+require 'spec_helper'
+
+describe ExpirePipelineCacheWorker do
+ let(:user) { create(:user) }
+ let(:project) { create(:empty_project) }
+ let(:pipeline) { create(:ci_pipeline, project: project) }
+ subject { described_class.new }
+
+ describe '#perform' do
+ it 'invalidates Etag caching for project pipelines path' do
+ pipelines_path = "/#{project.full_path}/pipelines.json"
+ new_mr_pipelines_path = "/#{project.full_path}/merge_requests/new.json"
+
+ expect_any_instance_of(Gitlab::EtagCaching::Store).to receive(:touch).with(pipelines_path)
+ expect_any_instance_of(Gitlab::EtagCaching::Store).to receive(:touch).with(new_mr_pipelines_path)
+
+ subject.perform(pipeline.id)
+ end
+
+ it 'invalidates Etag caching for merge request pipelines if pipeline runs on any commit of that source branch' do
+ pipeline = create(:ci_empty_pipeline, status: 'created', project: project, ref: 'master')
+ merge_request = create(:merge_request, source_project: project, source_branch: pipeline.ref)
+ merge_request_pipelines_path = "/#{project.full_path}/merge_requests/#{merge_request.iid}/pipelines.json"
+
+ allow_any_instance_of(Gitlab::EtagCaching::Store).to receive(:touch)
+ expect_any_instance_of(Gitlab::EtagCaching::Store).to receive(:touch).with(merge_request_pipelines_path)
+
+ subject.perform(pipeline.id)
+ end
+
+ it "doesn't do anything if the pipeline not exist" do
+ expect_any_instance_of(Gitlab::EtagCaching::Store).not_to receive(:touch)
+
+ subject.perform(617748)
+ end
+
+ it 'updates the cached status for a project' do
+ expect(Gitlab::Cache::Ci::ProjectPipelineStatus).to receive(:update_for_pipeline).
+ with(pipeline)
+
+ subject.perform(pipeline.id)
+ end
+ end
+end
diff --git a/vendor/assets/javascripts/notebooklab.js b/vendor/assets/javascripts/notebooklab.js
deleted file mode 100644
index b8cfdc53b48..00000000000
--- a/vendor/assets/javascripts/notebooklab.js
+++ /dev/null
@@ -1,5733 +0,0 @@
-(function webpackUniversalModuleDefinition(root, factory) {
- if(typeof exports === 'object' && typeof module === 'object')
- module.exports = factory();
- else if(typeof define === 'function' && define.amd)
- define("NotebookLab", [], factory);
- else if(typeof exports === 'object')
- exports["NotebookLab"] = factory();
- else
- root["NotebookLab"] = factory();
-})(this, function() {
-return /******/ (function(modules) { // webpackBootstrap
-/******/ // The module cache
-/******/ var installedModules = {};
-/******/
-/******/ // The require function
-/******/ function __webpack_require__(moduleId) {
-/******/
-/******/ // Check if module is in cache
-/******/ if(installedModules[moduleId])
-/******/ return installedModules[moduleId].exports;
-/******/
-/******/ // Create a new module (and put it into the cache)
-/******/ var module = installedModules[moduleId] = {
-/******/ i: moduleId,
-/******/ l: false,
-/******/ exports: {}
-/******/ };
-/******/
-/******/ // Execute the module function
-/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
-/******/
-/******/ // Flag the module as loaded
-/******/ module.l = true;
-/******/
-/******/ // Return the exports of the module
-/******/ return module.exports;
-/******/ }
-/******/
-/******/
-/******/ // expose the modules object (__webpack_modules__)
-/******/ __webpack_require__.m = modules;
-/******/
-/******/ // expose the module cache
-/******/ __webpack_require__.c = installedModules;
-/******/
-/******/ // identity function for calling harmony imports with the correct context
-/******/ __webpack_require__.i = function(value) { return value; };
-/******/
-/******/ // define getter function for harmony exports
-/******/ __webpack_require__.d = function(exports, name, getter) {
-/******/ if(!__webpack_require__.o(exports, name)) {
-/******/ Object.defineProperty(exports, name, {
-/******/ configurable: false,
-/******/ enumerable: true,
-/******/ get: getter
-/******/ });
-/******/ }
-/******/ };
-/******/
-/******/ // getDefaultExport function for compatibility with non-harmony modules
-/******/ __webpack_require__.n = function(module) {
-/******/ var getter = module && module.__esModule ?
-/******/ function getDefault() { return module['default']; } :
-/******/ function getModuleExports() { return module; };
-/******/ __webpack_require__.d(getter, 'a', getter);
-/******/ return getter;
-/******/ };
-/******/
-/******/ // Object.prototype.hasOwnProperty.call
-/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
-/******/
-/******/ // __webpack_public_path__
-/******/ __webpack_require__.p = "";
-/******/
-/******/ // Load entry module and return exports
-/******/ return __webpack_require__(__webpack_require__.s = 47);
-/******/ })
-/************************************************************************/
-/******/ ([
-/* 0 */
-/***/ (function(module, exports) {
-
-// this module is a runtime utility for cleaner component module output and will
-// be included in the final webpack user bundle
-
-module.exports = function normalizeComponent (
- rawScriptExports,
- compiledTemplate,
- scopeId,
- cssModules
-) {
- var esModule
- var scriptExports = rawScriptExports = rawScriptExports || {}
-
- // ES6 modules interop
- var type = typeof rawScriptExports.default
- if (type === 'object' || type === 'function') {
- esModule = rawScriptExports
- scriptExports = rawScriptExports.default
- }
-
- // Vue.extend constructor export interop
- var options = typeof scriptExports === 'function'
- ? scriptExports.options
- : scriptExports
-
- // render functions
- if (compiledTemplate) {
- options.render = compiledTemplate.render
- options.staticRenderFns = compiledTemplate.staticRenderFns
- }
-
- // scopedId
- if (scopeId) {
- options._scopeId = scopeId
- }
-
- // inject cssModules
- if (cssModules) {
- var computed = Object.create(options.computed || null)
- Object.keys(cssModules).forEach(function (key) {
- var module = cssModules[key]
- computed[key] = function () { return module }
- })
- options.computed = computed
- }
-
- return {
- esModule: esModule,
- exports: scriptExports,
- options: options
- }
-}
-
-
-/***/ }),
-/* 1 */
-/***/ (function(module, exports, __webpack_require__) {
-
-/* WEBPACK VAR INJECTION */(function(Buffer) {/*
- MIT License http://www.opensource.org/licenses/mit-license.php
- Author Tobias Koppers @sokra
-*/
-// css base code, injected by the css-loader
-module.exports = function(useSourceMap) {
- var list = [];
-
- // return the list of modules as css string
- list.toString = function toString() {
- return this.map(function (item) {
- var content = cssWithMappingToString(item, useSourceMap);
- if(item[2]) {
- return "@media " + item[2] + "{" + content + "}";
- } else {
- return content;
- }
- }).join("");
- };
-
- // import a list of modules into the list
- list.i = function(modules, mediaQuery) {
- if(typeof modules === "string")
- modules = [[null, modules, ""]];
- var alreadyImportedModules = {};
- for(var i = 0; i < this.length; i++) {
- var id = this[i][0];
- if(typeof id === "number")
- alreadyImportedModules[id] = true;
- }
- for(i = 0; i < modules.length; i++) {
- var item = modules[i];
- // skip already imported module
- // this implementation is not 100% perfect for weird media query combinations
- // when a module is imported multiple times with different media queries.
- // I hope this will never occur (Hey this way we have smaller bundles)
- if(typeof item[0] !== "number" || !alreadyImportedModules[item[0]]) {
- if(mediaQuery && !item[2]) {
- item[2] = mediaQuery;
- } else if(mediaQuery) {
- item[2] = "(" + item[2] + ") and (" + mediaQuery + ")";
- }
- list.push(item);
- }
- }
- };
- return list;
-};
-
-function cssWithMappingToString(item, useSourceMap) {
- var content = item[1] || '';
- var cssMapping = item[3];
- if (!cssMapping) {
- return content;
- }
-
- if (useSourceMap) {
- var sourceMapping = toComment(cssMapping);
- var sourceURLs = cssMapping.sources.map(function (source) {
- return '/*# sourceURL=' + cssMapping.sourceRoot + source + ' */'
- });
-
- return [content].concat(sourceURLs).concat([sourceMapping]).join('\n');
- }
-
- return [content].join('\n');
-}
-
-// Adapted from convert-source-map (MIT)
-function toComment(sourceMap) {
- var base64 = new Buffer(JSON.stringify(sourceMap)).toString('base64');
- var data = 'sourceMappingURL=data:application/json;charset=utf-8;base64,' + base64;
-
- return '/*# ' + data + ' */';
-}
-
-/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(18).Buffer))
-
-/***/ }),
-/* 2 */
-/***/ (function(module, exports, __webpack_require__) {
-
-
-/* styles */
-__webpack_require__(44)
-
-var Component = __webpack_require__(0)(
- /* script */
- __webpack_require__(13),
- /* template */
- __webpack_require__(39),
- /* scopeId */
- "data-v-4f6bf458",
- /* cssModules */
- null
-)
-
-module.exports = Component.exports
-
-
-/***/ }),
-/* 3 */
-/***/ (function(module, exports, __webpack_require__) {
-
-/*
- MIT License http://www.opensource.org/licenses/mit-license.php
- Author Tobias Koppers @sokra
- Modified by Evan You @yyx990803
-*/
-
-var hasDocument = typeof document !== 'undefined'
-
-if (typeof DEBUG !== 'undefined' && DEBUG) {
- if (!hasDocument) {
- throw new Error(
- 'vue-style-loader cannot be used in a non-browser environment. ' +
- "Use { target: 'node' } in your Webpack config to indicate a server-rendering environment."
- ) }
-}
-
-var listToStyles = __webpack_require__(46)
-
-/*
-type StyleObject = {
- id: number;
- parts: Array<StyleObjectPart>
-}
-
-type StyleObjectPart = {
- css: string;
- media: string;
- sourceMap: ?string
-}
-*/
-
-var stylesInDom = {/*
- [id: number]: {
- id: number,
- refs: number,
- parts: Array<(obj?: StyleObjectPart) => void>
- }
-*/}
-
-var head = hasDocument && (document.head || document.getElementsByTagName('head')[0])
-var singletonElement = null
-var singletonCounter = 0
-var isProduction = false
-var noop = function () {}
-
-// Force single-tag solution on IE6-9, which has a hard limit on the # of <style>
-// tags it will allow on a page
-var isOldIE = typeof navigator !== 'undefined' && /msie [6-9]\b/.test(navigator.userAgent.toLowerCase())
-
-module.exports = function (parentId, list, _isProduction) {
- isProduction = _isProduction
-
- var styles = listToStyles(parentId, list)
- addStylesToDom(styles)
-
- return function update (newList) {
- var mayRemove = []
- for (var i = 0; i < styles.length; i++) {
- var item = styles[i]
- var domStyle = stylesInDom[item.id]
- domStyle.refs--
- mayRemove.push(domStyle)
- }
- if (newList) {
- styles = listToStyles(parentId, newList)
- addStylesToDom(styles)
- } else {
- styles = []
- }
- for (var i = 0; i < mayRemove.length; i++) {
- var domStyle = mayRemove[i]
- if (domStyle.refs === 0) {
- for (var j = 0; j < domStyle.parts.length; j++) {
- domStyle.parts[j]()
- }
- delete stylesInDom[domStyle.id]
- }
- }
- }
-}
-
-function addStylesToDom (styles /* Array<StyleObject> */) {
- for (var i = 0; i < styles.length; i++) {
- var item = styles[i]
- var domStyle = stylesInDom[item.id]
- if (domStyle) {
- domStyle.refs++
- for (var j = 0; j < domStyle.parts.length; j++) {
- domStyle.parts[j](item.parts[j])
- }
- for (; j < item.parts.length; j++) {
- domStyle.parts.push(addStyle(item.parts[j]))
- }
- if (domStyle.parts.length > item.parts.length) {
- domStyle.parts.length = item.parts.length
- }
- } else {
- var parts = []
- for (var j = 0; j < item.parts.length; j++) {
- parts.push(addStyle(item.parts[j]))
- }
- stylesInDom[item.id] = { id: item.id, refs: 1, parts: parts }
- }
- }
-}
-
-function createStyleElement () {
- var styleElement = document.createElement('style')
- styleElement.type = 'text/css'
- head.appendChild(styleElement)
- return styleElement
-}
-
-function addStyle (obj /* StyleObjectPart */) {
- var update, remove
- var styleElement = document.querySelector('style[data-vue-ssr-id~="' + obj.id + '"]')
-
- if (styleElement) {
- if (isProduction) {
- // has SSR styles and in production mode.
- // simply do nothing.
- return noop
- } else {
- // has SSR styles but in dev mode.
- // for some reason Chrome can't handle source map in server-rendered
- // style tags - source maps in <style> only works if the style tag is
- // created and inserted dynamically. So we remove the server rendered
- // styles and inject new ones.
- styleElement.parentNode.removeChild(styleElement)
- }
- }
-
- if (isOldIE) {
- // use singleton mode for IE9.
- var styleIndex = singletonCounter++
- styleElement = singletonElement || (singletonElement = createStyleElement())
- update = applyToSingletonTag.bind(null, styleElement, styleIndex, false)
- remove = applyToSingletonTag.bind(null, styleElement, styleIndex, true)
- } else {
- // use multi-style-tag mode in all other cases
- styleElement = createStyleElement()
- update = applyToTag.bind(null, styleElement)
- remove = function () {
- styleElement.parentNode.removeChild(styleElement)
- }
- }
-
- update(obj)
-
- return function updateStyle (newObj /* StyleObjectPart */) {
- if (newObj) {
- if (newObj.css === obj.css &&
- newObj.media === obj.media &&
- newObj.sourceMap === obj.sourceMap) {
- return
- }
- update(obj = newObj)
- } else {
- remove()
- }
- }
-}
-
-var replaceText = (function () {
- var textStore = []
-
- return function (index, replacement) {
- textStore[index] = replacement
- return textStore.filter(Boolean).join('\n')
- }
-})()
-
-function applyToSingletonTag (styleElement, index, remove, obj) {
- var css = remove ? '' : obj.css
-
- if (styleElement.styleSheet) {
- styleElement.styleSheet.cssText = replaceText(index, css)
- } else {
- var cssNode = document.createTextNode(css)
- var childNodes = styleElement.childNodes
- if (childNodes[index]) styleElement.removeChild(childNodes[index])
- if (childNodes.length) {
- styleElement.insertBefore(cssNode, childNodes[index])
- } else {
- styleElement.appendChild(cssNode)
- }
- }
-}
-
-function applyToTag (styleElement, obj) {
- var css = obj.css
- var media = obj.media
- var sourceMap = obj.sourceMap
-
- if (media) {
- styleElement.setAttribute('media', media)
- }
-
- if (sourceMap) {
- // https://developer.chrome.com/devtools/docs/javascript-debugging
- // this makes source maps inside style tags work properly in Chrome
- css += '\n/*# sourceURL=' + sourceMap.sources[0] + ' */'
- // http://stackoverflow.com/a/26603875
- css += '\n/*# sourceMappingURL=data:application/json;base64,' + btoa(unescape(encodeURIComponent(JSON.stringify(sourceMap)))) + ' */'
- }
-
- if (styleElement.styleSheet) {
- styleElement.styleSheet.cssText = css
- } else {
- while (styleElement.firstChild) {
- styleElement.removeChild(styleElement.firstChild)
- }
- styleElement.appendChild(document.createTextNode(css))
- }
-}
-
-
-/***/ }),
-/* 4 */
-/***/ (function(module, exports) {
-
-var g;
-
-// This works in non-strict mode
-g = (function() {
- return this;
-})();
-
-try {
- // This works if eval is allowed (see CSP)
- g = g || Function("return this")() || (1,eval)("this");
-} catch(e) {
- // This works if the window reference is available
- if(typeof window === "object")
- g = window;
-}
-
-// g can still be undefined, but nothing to do about it...
-// We return undefined, instead of nothing here, so it's
-// easier to handle this case. if(!global) { ...}
-
-module.exports = g;
-
-
-/***/ }),
-/* 5 */
-/***/ (function(module, exports, __webpack_require__) {
-
-var Component = __webpack_require__(0)(
- /* script */
- __webpack_require__(8),
- /* template */
- __webpack_require__(41),
- /* scopeId */
- null,
- /* cssModules */
- null
-)
-
-module.exports = Component.exports
-
-
-/***/ }),
-/* 6 */
-/***/ (function(module, exports, __webpack_require__) {
-
-
-/* styles */
-__webpack_require__(43)
-
-var Component = __webpack_require__(0)(
- /* script */
- __webpack_require__(14),
- /* template */
- __webpack_require__(38),
- /* scopeId */
- null,
- /* cssModules */
- null
-)
-
-module.exports = Component.exports
-
-
-/***/ }),
-/* 7 */
-/***/ (function(module, exports, __webpack_require__) {
-
-"use strict";
-
-
-Object.defineProperty(exports, "__esModule", {
- value: true
-});
-
-var _index = __webpack_require__(5);
-
-var _index2 = _interopRequireDefault(_index);
-
-var _index3 = __webpack_require__(33);
-
-var _index4 = _interopRequireDefault(_index3);
-
-function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
-
-//
-//
-//
-//
-//
-//
-//
-//
-//
-//
-//
-//
-//
-//
-//
-
-exports.default = {
- components: {
- 'code-cell': _index2.default,
- 'output-cell': _index4.default
- },
- props: {
- cell: {
- type: Object,
- required: true
- },
- codeCssClass: {
- type: String,
- required: false,
- default: ''
- }
- },
- computed: {
- rawInputCode: function rawInputCode() {
- if (this.cell.source) {
- return this.cell.source.join('');
- }
-
- return '';
- },
- hasOutput: function hasOutput() {
- return this.cell.outputs.length;
- },
- output: function output() {
- return this.cell.outputs[0];
- }
- }
-};
-
-/***/ }),
-/* 8 */
-/***/ (function(module, exports, __webpack_require__) {
-
-"use strict";
-
-
-Object.defineProperty(exports, "__esModule", {
- value: true
-});
-
-var _highlight = __webpack_require__(16);
-
-var _highlight2 = _interopRequireDefault(_highlight);
-
-var _prompt = __webpack_require__(2);
-
-var _prompt2 = _interopRequireDefault(_prompt);
-
-function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
-
-//
-//
-//
-//
-//
-//
-//
-//
-//
-//
-//
-//
-//
-//
-
-exports.default = {
- components: {
- prompt: _prompt2.default
- },
- props: {
- count: {
- type: Number,
- required: false,
- default: 0
- },
- codeCssClass: {
- type: String,
- required: false,
- default: ''
- },
- type: {
- type: String,
- required: true
- },
- rawCode: {
- type: String,
- required: true
- }
- },
- computed: {
- code: function code() {
- return this.rawCode;
- },
- promptType: function promptType() {
- var type = this.type.split('put')[0];
-
- return type.charAt(0).toUpperCase() + type.slice(1);
- }
- },
- mounted: function mounted() {
- _highlight2.default.highlightElement(this.$refs.code);
- }
-};
-
-/***/ }),
-/* 9 */
-/***/ (function(module, exports, __webpack_require__) {
-
-"use strict";
-
-
-Object.defineProperty(exports, "__esModule", {
- value: true
-});
-
-var _marked = __webpack_require__(25);
-
-var _marked2 = _interopRequireDefault(_marked);
-
-var _prompt = __webpack_require__(2);
-
-var _prompt2 = _interopRequireDefault(_prompt);
-
-function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
-
-//
-//
-//
-//
-//
-//
-//
-
-var renderer = new _marked2.default.Renderer();
-
-/*
- Regex to match KaTex blocks.
-
- Supports the following:
-
- \begin{equation}<math>\end{equation}
- $$<math>$$
- inline $<math>$
-
- The matched text then goes through the KaTex renderer & then outputs the HTML
-*/
-var katexRegexString = '(\n ^\\\\begin{[a-zA-Z]+}\\s\n |\n ^\\$\\$\n |\n \\s\\$(?!\\$)\n)\n (.+?)\n(\n \\s\\\\end{[a-zA-Z]+}$\n |\n \\$\\$$\n |\n \\$\n)\n'.replace(/\s/g, '').trim();
-
-renderer.paragraph = function (t) {
- var text = t;
- var inline = false;
-
- if (typeof katex !== 'undefined') {
- var katexString = text.replace(/\\/g, '\\');
- var matches = new RegExp(katexRegexString, 'gi').exec(katexString);
-
- if (matches && matches.length > 0) {
- if (matches[1].trim() === '$' && matches[3].trim() === '$') {
- inline = true;
-
- text = katexString.replace(matches[0], '') + ' ' + katex.renderToString(matches[2]);
- } else {
- text = katex.renderToString(matches[2]);
- }
- }
- }
-
- return '<p class="' + (inline ? 'inline-katex' : '') + '">' + text + '</p>';
-};
-
-_marked2.default.setOptions({
- sanitize: true,
- renderer: renderer
-});
-
-exports.default = {
- components: {
- prompt: _prompt2.default
- },
- props: {
- cell: {
- type: Object,
- required: true
- }
- },
- computed: {
- markdown: function markdown() {
- return (0, _marked2.default)(this.cell.source.join(''));
- }
- }
-};
-
-/***/ }),
-/* 10 */
-/***/ (function(module, exports, __webpack_require__) {
-
-"use strict";
-
-
-Object.defineProperty(exports, "__esModule", {
- value: true
-});
-
-var _prompt = __webpack_require__(2);
-
-var _prompt2 = _interopRequireDefault(_prompt);
-
-function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
-
-exports.default = {
- props: {
- rawCode: {
- type: String,
- required: true
- }
- },
- components: {
- prompt: _prompt2.default
- }
-}; //
-//
-//
-//
-//
-//
-//
-
-/***/ }),
-/* 11 */
-/***/ (function(module, exports, __webpack_require__) {
-
-"use strict";
-
-
-Object.defineProperty(exports, "__esModule", {
- value: true
-});
-
-var _prompt = __webpack_require__(2);
-
-var _prompt2 = _interopRequireDefault(_prompt);
-
-function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
-
-exports.default = {
- props: {
- outputType: {
- type: String,
- required: true
- },
- rawCode: {
- type: String,
- required: true
- }
- },
- components: {
- prompt: _prompt2.default
- }
-}; //
-//
-//
-//
-//
-//
-//
-//
-
-/***/ }),
-/* 12 */
-/***/ (function(module, exports, __webpack_require__) {
-
-"use strict";
-
-
-Object.defineProperty(exports, "__esModule", {
- value: true
-});
-
-var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; //
-//
-//
-//
-//
-//
-//
-//
-//
-
-var _index = __webpack_require__(5);
-
-var _index2 = _interopRequireDefault(_index);
-
-var _html = __webpack_require__(31);
-
-var _html2 = _interopRequireDefault(_html);
-
-var _image = __webpack_require__(32);
-
-var _image2 = _interopRequireDefault(_image);
-
-function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
-
-exports.default = {
- props: {
- codeCssClass: {
- type: String,
- required: false,
- default: ''
- },
- count: {
- type: Number,
- required: false,
- default: 0
- },
- output: {
- type: Object,
- requred: true
- }
- },
- components: {
- 'code-cell': _index2.default,
- 'html-output': _html2.default,
- 'image-output': _image2.default
- },
- data: function data() {
- return {
- outputType: ''
- };
- },
-
- computed: {
- componentName: function componentName() {
- if (this.output.text) {
- return 'code-cell';
- } else if (this.output.data['image/png']) {
- this.outputType = 'image/png';
-
- return 'image-output';
- } else if (this.output.data['text/html']) {
- this.outputType = 'text/html';
-
- return 'html-output';
- } else if (this.output.data['image/svg+xml']) {
- this.outputType = 'image/svg+xml';
-
- return 'html-output';
- }
-
- this.outputType = 'text/plain';
- return 'code-cell';
- },
- rawCode: function rawCode() {
- if (this.output.text) {
- return this.output.text.join('');
- }
-
- return this.dataForType(this.outputType);
- }
- },
- methods: {
- dataForType: function dataForType(type) {
- var data = this.output.data[type];
-
- if ((typeof data === 'undefined' ? 'undefined' : _typeof(data)) === 'object') {
- data = data.join('');
- }
-
- return data;
- }
- }
-};
-
-/***/ }),
-/* 13 */
-/***/ (function(module, exports, __webpack_require__) {
-
-"use strict";
-
-
-Object.defineProperty(exports, "__esModule", {
- value: true
-});
-//
-//
-//
-//
-//
-//
-//
-//
-
-exports.default = {
- props: {
- type: {
- type: String,
- required: false
- },
- count: {
- type: Number,
- required: false
- }
- }
-};
-
-/***/ }),
-/* 14 */
-/***/ (function(module, exports, __webpack_require__) {
-
-"use strict";
-
-
-Object.defineProperty(exports, "__esModule", {
- value: true
-});
-
-var _cells = __webpack_require__(15);
-
-exports.default = {
- components: {
- 'code-cell': _cells.CodeCell,
- 'markdown-cell': _cells.MarkdownCell
- },
- props: {
- notebook: {
- type: Object,
- required: true
- },
- codeCssClass: {
- type: String,
- required: false,
- default: ''
- }
- },
- methods: {
- cellType: function cellType(type) {
- return type + '-cell';
- }
- },
- computed: {
- cells: function cells() {
- if (this.notebook.worksheets) {
- var data = {
- cells: []
- };
-
- return this.notebook.worksheets.reduce(function (cellData, sheet) {
- var cellDataCopy = cellData;
- cellDataCopy.cells = cellDataCopy.cells.concat(sheet.cells);
- return cellDataCopy;
- }, data).cells;
- }
-
- return this.notebook.cells;
- },
- hasNotebook: function hasNotebook() {
- return Object.keys(this.notebook).length;
- }
- }
-}; //
-//
-//
-//
-//
-//
-//
-//
-//
-//
-//
-
-/***/ }),
-/* 15 */
-/***/ (function(module, exports, __webpack_require__) {
-
-"use strict";
-
-
-Object.defineProperty(exports, "__esModule", {
- value: true
-});
-
-var _markdown = __webpack_require__(30);
-
-Object.defineProperty(exports, 'MarkdownCell', {
- enumerable: true,
- get: function get() {
- return _interopRequireDefault(_markdown).default;
- }
-});
-
-var _code = __webpack_require__(29);
-
-Object.defineProperty(exports, 'CodeCell', {
- enumerable: true,
- get: function get() {
- return _interopRequireDefault(_code).default;
- }
-});
-
-function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
-
-/***/ }),
-/* 16 */
-/***/ (function(module, exports, __webpack_require__) {
-
-"use strict";
-
-
-Object.defineProperty(exports, "__esModule", {
- value: true
-});
-
-var _prismjs = __webpack_require__(28);
-
-var _prismjs2 = _interopRequireDefault(_prismjs);
-
-__webpack_require__(26);
-
-__webpack_require__(27);
-
-function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
-
-_prismjs2.default.plugins.customClass.map({
- comment: 'c',
- error: 'err',
- operator: 'o',
- constant: 'kc',
- namespace: 'kn',
- keyword: 'k',
- string: 's',
- number: 'm',
- 'attr-name': 'na',
- builtin: 'nb',
- entity: 'ni',
- function: 'nf',
- tag: 'nt',
- variable: 'nv'
-});
-
-exports.default = _prismjs2.default;
-
-/***/ }),
-/* 17 */
-/***/ (function(module, exports, __webpack_require__) {
-
-"use strict";
-
-
-exports.byteLength = byteLength
-exports.toByteArray = toByteArray
-exports.fromByteArray = fromByteArray
-
-var lookup = []
-var revLookup = []
-var Arr = typeof Uint8Array !== 'undefined' ? Uint8Array : Array
-
-var code = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
-for (var i = 0, len = code.length; i < len; ++i) {
- lookup[i] = code[i]
- revLookup[code.charCodeAt(i)] = i
-}
-
-revLookup['-'.charCodeAt(0)] = 62
-revLookup['_'.charCodeAt(0)] = 63
-
-function placeHoldersCount (b64) {
- var len = b64.length
- if (len % 4 > 0) {
- throw new Error('Invalid string. Length must be a multiple of 4')
- }
-
- // the number of equal signs (place holders)
- // if there are two placeholders, than the two characters before it
- // represent one byte
- // if there is only one, then the three characters before it represent 2 bytes
- // this is just a cheap hack to not do indexOf twice
- return b64[len - 2] === '=' ? 2 : b64[len - 1] === '=' ? 1 : 0
-}
-
-function byteLength (b64) {
- // base64 is 4/3 + up to two characters of the original data
- return b64.length * 3 / 4 - placeHoldersCount(b64)
-}
-
-function toByteArray (b64) {
- var i, j, l, tmp, placeHolders, arr
- var len = b64.length
- placeHolders = placeHoldersCount(b64)
-
- arr = new Arr(len * 3 / 4 - placeHolders)
-
- // if there are placeholders, only get up to the last complete 4 chars
- l = placeHolders > 0 ? len - 4 : len
-
- var L = 0
-
- for (i = 0, j = 0; i < l; i += 4, j += 3) {
- tmp = (revLookup[b64.charCodeAt(i)] << 18) | (revLookup[b64.charCodeAt(i + 1)] << 12) | (revLookup[b64.charCodeAt(i + 2)] << 6) | revLookup[b64.charCodeAt(i + 3)]
- arr[L++] = (tmp >> 16) & 0xFF
- arr[L++] = (tmp >> 8) & 0xFF
- arr[L++] = tmp & 0xFF
- }
-
- if (placeHolders === 2) {
- tmp = (revLookup[b64.charCodeAt(i)] << 2) | (revLookup[b64.charCodeAt(i + 1)] >> 4)
- arr[L++] = tmp & 0xFF
- } else if (placeHolders === 1) {
- tmp = (revLookup[b64.charCodeAt(i)] << 10) | (revLookup[b64.charCodeAt(i + 1)] << 4) | (revLookup[b64.charCodeAt(i + 2)] >> 2)
- arr[L++] = (tmp >> 8) & 0xFF
- arr[L++] = tmp & 0xFF
- }
-
- return arr
-}
-
-function tripletToBase64 (num) {
- return lookup[num >> 18 & 0x3F] + lookup[num >> 12 & 0x3F] + lookup[num >> 6 & 0x3F] + lookup[num & 0x3F]
-}
-
-function encodeChunk (uint8, start, end) {
- var tmp
- var output = []
- for (var i = start; i < end; i += 3) {
- tmp = (uint8[i] << 16) + (uint8[i + 1] << 8) + (uint8[i + 2])
- output.push(tripletToBase64(tmp))
- }
- return output.join('')
-}
-
-function fromByteArray (uint8) {
- var tmp
- var len = uint8.length
- var extraBytes = len % 3 // if we have 1 byte left, pad 2 bytes
- var output = ''
- var parts = []
- var maxChunkLength = 16383 // must be multiple of 3
-
- // go through the array every three bytes, we'll deal with trailing stuff later
- for (var i = 0, len2 = len - extraBytes; i < len2; i += maxChunkLength) {
- parts.push(encodeChunk(uint8, i, (i + maxChunkLength) > len2 ? len2 : (i + maxChunkLength)))
- }
-
- // pad the end with zeros, but make sure to not forget the extra bytes
- if (extraBytes === 1) {
- tmp = uint8[len - 1]
- output += lookup[tmp >> 2]
- output += lookup[(tmp << 4) & 0x3F]
- output += '=='
- } else if (extraBytes === 2) {
- tmp = (uint8[len - 2] << 8) + (uint8[len - 1])
- output += lookup[tmp >> 10]
- output += lookup[(tmp >> 4) & 0x3F]
- output += lookup[(tmp << 2) & 0x3F]
- output += '='
- }
-
- parts.push(output)
-
- return parts.join('')
-}
-
-
-/***/ }),
-/* 18 */
-/***/ (function(module, exports, __webpack_require__) {
-
-"use strict";
-/* WEBPACK VAR INJECTION */(function(global) {/*!
- * The buffer module from node.js, for the browser.
- *
- * @author Feross Aboukhadijeh <feross@feross.org> <http://feross.org>
- * @license MIT
- */
-/* eslint-disable no-proto */
-
-
-
-var base64 = __webpack_require__(17)
-var ieee754 = __webpack_require__(23)
-var isArray = __webpack_require__(24)
-
-exports.Buffer = Buffer
-exports.SlowBuffer = SlowBuffer
-exports.INSPECT_MAX_BYTES = 50
-
-/**
- * If `Buffer.TYPED_ARRAY_SUPPORT`:
- * === true Use Uint8Array implementation (fastest)
- * === false Use Object implementation (most compatible, even IE6)
- *
- * Browsers that support typed arrays are IE 10+, Firefox 4+, Chrome 7+, Safari 5.1+,
- * Opera 11.6+, iOS 4.2+.
- *
- * Due to various browser bugs, sometimes the Object implementation will be used even
- * when the browser supports typed arrays.
- *
- * Note:
- *
- * - Firefox 4-29 lacks support for adding new properties to `Uint8Array` instances,
- * See: https://bugzilla.mozilla.org/show_bug.cgi?id=695438.
- *
- * - Chrome 9-10 is missing the `TypedArray.prototype.subarray` function.
- *
- * - IE10 has a broken `TypedArray.prototype.subarray` function which returns arrays of
- * incorrect length in some situations.
-
- * We detect these buggy browsers and set `Buffer.TYPED_ARRAY_SUPPORT` to `false` so they
- * get the Object implementation, which is slower but behaves correctly.
- */
-Buffer.TYPED_ARRAY_SUPPORT = global.TYPED_ARRAY_SUPPORT !== undefined
- ? global.TYPED_ARRAY_SUPPORT
- : typedArraySupport()
-
-/*
- * Export kMaxLength after typed array support is determined.
- */
-exports.kMaxLength = kMaxLength()
-
-function typedArraySupport () {
- try {
- var arr = new Uint8Array(1)
- arr.__proto__ = {__proto__: Uint8Array.prototype, foo: function () { return 42 }}
- return arr.foo() === 42 && // typed array instances can be augmented
- typeof arr.subarray === 'function' && // chrome 9-10 lack `subarray`
- arr.subarray(1, 1).byteLength === 0 // ie10 has broken `subarray`
- } catch (e) {
- return false
- }
-}
-
-function kMaxLength () {
- return Buffer.TYPED_ARRAY_SUPPORT
- ? 0x7fffffff
- : 0x3fffffff
-}
-
-function createBuffer (that, length) {
- if (kMaxLength() < length) {
- throw new RangeError('Invalid typed array length')
- }
- if (Buffer.TYPED_ARRAY_SUPPORT) {
- // Return an augmented `Uint8Array` instance, for best performance
- that = new Uint8Array(length)
- that.__proto__ = Buffer.prototype
- } else {
- // Fallback: Return an object instance of the Buffer class
- if (that === null) {
- that = new Buffer(length)
- }
- that.length = length
- }
-
- return that
-}
-
-/**
- * The Buffer constructor returns instances of `Uint8Array` that have their
- * prototype changed to `Buffer.prototype`. Furthermore, `Buffer` is a subclass of
- * `Uint8Array`, so the returned instances will have all the node `Buffer` methods
- * and the `Uint8Array` methods. Square bracket notation works as expected -- it
- * returns a single octet.
- *
- * The `Uint8Array` prototype remains unmodified.
- */
-
-function Buffer (arg, encodingOrOffset, length) {
- if (!Buffer.TYPED_ARRAY_SUPPORT && !(this instanceof Buffer)) {
- return new Buffer(arg, encodingOrOffset, length)
- }
-
- // Common case.
- if (typeof arg === 'number') {
- if (typeof encodingOrOffset === 'string') {
- throw new Error(
- 'If encoding is specified then the first argument must be a string'
- )
- }
- return allocUnsafe(this, arg)
- }
- return from(this, arg, encodingOrOffset, length)
-}
-
-Buffer.poolSize = 8192 // not used by this implementation
-
-// TODO: Legacy, not needed anymore. Remove in next major version.
-Buffer._augment = function (arr) {
- arr.__proto__ = Buffer.prototype
- return arr
-}
-
-function from (that, value, encodingOrOffset, length) {
- if (typeof value === 'number') {
- throw new TypeError('"value" argument must not be a number')
- }
-
- if (typeof ArrayBuffer !== 'undefined' && value instanceof ArrayBuffer) {
- return fromArrayBuffer(that, value, encodingOrOffset, length)
- }
-
- if (typeof value === 'string') {
- return fromString(that, value, encodingOrOffset)
- }
-
- return fromObject(that, value)
-}
-
-/**
- * Functionally equivalent to Buffer(arg, encoding) but throws a TypeError
- * if value is a number.
- * Buffer.from(str[, encoding])
- * Buffer.from(array)
- * Buffer.from(buffer)
- * Buffer.from(arrayBuffer[, byteOffset[, length]])
- **/
-Buffer.from = function (value, encodingOrOffset, length) {
- return from(null, value, encodingOrOffset, length)
-}
-
-if (Buffer.TYPED_ARRAY_SUPPORT) {
- Buffer.prototype.__proto__ = Uint8Array.prototype
- Buffer.__proto__ = Uint8Array
- if (typeof Symbol !== 'undefined' && Symbol.species &&
- Buffer[Symbol.species] === Buffer) {
- // Fix subarray() in ES2016. See: https://github.com/feross/buffer/pull/97
- Object.defineProperty(Buffer, Symbol.species, {
- value: null,
- configurable: true
- })
- }
-}
-
-function assertSize (size) {
- if (typeof size !== 'number') {
- throw new TypeError('"size" argument must be a number')
- } else if (size < 0) {
- throw new RangeError('"size" argument must not be negative')
- }
-}
-
-function alloc (that, size, fill, encoding) {
- assertSize(size)
- if (size <= 0) {
- return createBuffer(that, size)
- }
- if (fill !== undefined) {
- // Only pay attention to encoding if it's a string. This
- // prevents accidentally sending in a number that would
- // be interpretted as a start offset.
- return typeof encoding === 'string'
- ? createBuffer(that, size).fill(fill, encoding)
- : createBuffer(that, size).fill(fill)
- }
- return createBuffer(that, size)
-}
-
-/**
- * Creates a new filled Buffer instance.
- * alloc(size[, fill[, encoding]])
- **/
-Buffer.alloc = function (size, fill, encoding) {
- return alloc(null, size, fill, encoding)
-}
-
-function allocUnsafe (that, size) {
- assertSize(size)
- that = createBuffer(that, size < 0 ? 0 : checked(size) | 0)
- if (!Buffer.TYPED_ARRAY_SUPPORT) {
- for (var i = 0; i < size; ++i) {
- that[i] = 0
- }
- }
- return that
-}
-
-/**
- * Equivalent to Buffer(num), by default creates a non-zero-filled Buffer instance.
- * */
-Buffer.allocUnsafe = function (size) {
- return allocUnsafe(null, size)
-}
-/**
- * Equivalent to SlowBuffer(num), by default creates a non-zero-filled Buffer instance.
- */
-Buffer.allocUnsafeSlow = function (size) {
- return allocUnsafe(null, size)
-}
-
-function fromString (that, string, encoding) {
- if (typeof encoding !== 'string' || encoding === '') {
- encoding = 'utf8'
- }
-
- if (!Buffer.isEncoding(encoding)) {
- throw new TypeError('"encoding" must be a valid string encoding')
- }
-
- var length = byteLength(string, encoding) | 0
- that = createBuffer(that, length)
-
- var actual = that.write(string, encoding)
-
- if (actual !== length) {
- // Writing a hex string, for example, that contains invalid characters will
- // cause everything after the first invalid character to be ignored. (e.g.
- // 'abxxcd' will be treated as 'ab')
- that = that.slice(0, actual)
- }
-
- return that
-}
-
-function fromArrayLike (that, array) {
- var length = array.length < 0 ? 0 : checked(array.length) | 0
- that = createBuffer(that, length)
- for (var i = 0; i < length; i += 1) {
- that[i] = array[i] & 255
- }
- return that
-}
-
-function fromArrayBuffer (that, array, byteOffset, length) {
- array.byteLength // this throws if `array` is not a valid ArrayBuffer
-
- if (byteOffset < 0 || array.byteLength < byteOffset) {
- throw new RangeError('\'offset\' is out of bounds')
- }
-
- if (array.byteLength < byteOffset + (length || 0)) {
- throw new RangeError('\'length\' is out of bounds')
- }
-
- if (byteOffset === undefined && length === undefined) {
- array = new Uint8Array(array)
- } else if (length === undefined) {
- array = new Uint8Array(array, byteOffset)
- } else {
- array = new Uint8Array(array, byteOffset, length)
- }
-
- if (Buffer.TYPED_ARRAY_SUPPORT) {
- // Return an augmented `Uint8Array` instance, for best performance
- that = array
- that.__proto__ = Buffer.prototype
- } else {
- // Fallback: Return an object instance of the Buffer class
- that = fromArrayLike(that, array)
- }
- return that
-}
-
-function fromObject (that, obj) {
- if (Buffer.isBuffer(obj)) {
- var len = checked(obj.length) | 0
- that = createBuffer(that, len)
-
- if (that.length === 0) {
- return that
- }
-
- obj.copy(that, 0, 0, len)
- return that
- }
-
- if (obj) {
- if ((typeof ArrayBuffer !== 'undefined' &&
- obj.buffer instanceof ArrayBuffer) || 'length' in obj) {
- if (typeof obj.length !== 'number' || isnan(obj.length)) {
- return createBuffer(that, 0)
- }
- return fromArrayLike(that, obj)
- }
-
- if (obj.type === 'Buffer' && isArray(obj.data)) {
- return fromArrayLike(that, obj.data)
- }
- }
-
- throw new TypeError('First argument must be a string, Buffer, ArrayBuffer, Array, or array-like object.')
-}
-
-function checked (length) {
- // Note: cannot use `length < kMaxLength()` here because that fails when
- // length is NaN (which is otherwise coerced to zero.)
- if (length >= kMaxLength()) {
- throw new RangeError('Attempt to allocate Buffer larger than maximum ' +
- 'size: 0x' + kMaxLength().toString(16) + ' bytes')
- }
- return length | 0
-}
-
-function SlowBuffer (length) {
- if (+length != length) { // eslint-disable-line eqeqeq
- length = 0
- }
- return Buffer.alloc(+length)
-}
-
-Buffer.isBuffer = function isBuffer (b) {
- return !!(b != null && b._isBuffer)
-}
-
-Buffer.compare = function compare (a, b) {
- if (!Buffer.isBuffer(a) || !Buffer.isBuffer(b)) {
- throw new TypeError('Arguments must be Buffers')
- }
-
- if (a === b) return 0
-
- var x = a.length
- var y = b.length
-
- for (var i = 0, len = Math.min(x, y); i < len; ++i) {
- if (a[i] !== b[i]) {
- x = a[i]
- y = b[i]
- break
- }
- }
-
- if (x < y) return -1
- if (y < x) return 1
- return 0
-}
-
-Buffer.isEncoding = function isEncoding (encoding) {
- switch (String(encoding).toLowerCase()) {
- case 'hex':
- case 'utf8':
- case 'utf-8':
- case 'ascii':
- case 'latin1':
- case 'binary':
- case 'base64':
- case 'ucs2':
- case 'ucs-2':
- case 'utf16le':
- case 'utf-16le':
- return true
- default:
- return false
- }
-}
-
-Buffer.concat = function concat (list, length) {
- if (!isArray(list)) {
- throw new TypeError('"list" argument must be an Array of Buffers')
- }
-
- if (list.length === 0) {
- return Buffer.alloc(0)
- }
-
- var i
- if (length === undefined) {
- length = 0
- for (i = 0; i < list.length; ++i) {
- length += list[i].length
- }
- }
-
- var buffer = Buffer.allocUnsafe(length)
- var pos = 0
- for (i = 0; i < list.length; ++i) {
- var buf = list[i]
- if (!Buffer.isBuffer(buf)) {
- throw new TypeError('"list" argument must be an Array of Buffers')
- }
- buf.copy(buffer, pos)
- pos += buf.length
- }
- return buffer
-}
-
-function byteLength (string, encoding) {
- if (Buffer.isBuffer(string)) {
- return string.length
- }
- if (typeof ArrayBuffer !== 'undefined' && typeof ArrayBuffer.isView === 'function' &&
- (ArrayBuffer.isView(string) || string instanceof ArrayBuffer)) {
- return string.byteLength
- }
- if (typeof string !== 'string') {
- string = '' + string
- }
-
- var len = string.length
- if (len === 0) return 0
-
- // Use a for loop to avoid recursion
- var loweredCase = false
- for (;;) {
- switch (encoding) {
- case 'ascii':
- case 'latin1':
- case 'binary':
- return len
- case 'utf8':
- case 'utf-8':
- case undefined:
- return utf8ToBytes(string).length
- case 'ucs2':
- case 'ucs-2':
- case 'utf16le':
- case 'utf-16le':
- return len * 2
- case 'hex':
- return len >>> 1
- case 'base64':
- return base64ToBytes(string).length
- default:
- if (loweredCase) return utf8ToBytes(string).length // assume utf8
- encoding = ('' + encoding).toLowerCase()
- loweredCase = true
- }
- }
-}
-Buffer.byteLength = byteLength
-
-function slowToString (encoding, start, end) {
- var loweredCase = false
-
- // No need to verify that "this.length <= MAX_UINT32" since it's a read-only
- // property of a typed array.
-
- // This behaves neither like String nor Uint8Array in that we set start/end
- // to their upper/lower bounds if the value passed is out of range.
- // undefined is handled specially as per ECMA-262 6th Edition,
- // Section 13.3.3.7 Runtime Semantics: KeyedBindingInitialization.
- if (start === undefined || start < 0) {
- start = 0
- }
- // Return early if start > this.length. Done here to prevent potential uint32
- // coercion fail below.
- if (start > this.length) {
- return ''
- }
-
- if (end === undefined || end > this.length) {
- end = this.length
- }
-
- if (end <= 0) {
- return ''
- }
-
- // Force coersion to uint32. This will also coerce falsey/NaN values to 0.
- end >>>= 0
- start >>>= 0
-
- if (end <= start) {
- return ''
- }
-
- if (!encoding) encoding = 'utf8'
-
- while (true) {
- switch (encoding) {
- case 'hex':
- return hexSlice(this, start, end)
-
- case 'utf8':
- case 'utf-8':
- return utf8Slice(this, start, end)
-
- case 'ascii':
- return asciiSlice(this, start, end)
-
- case 'latin1':
- case 'binary':
- return latin1Slice(this, start, end)
-
- case 'base64':
- return base64Slice(this, start, end)
-
- case 'ucs2':
- case 'ucs-2':
- case 'utf16le':
- case 'utf-16le':
- return utf16leSlice(this, start, end)
-
- default:
- if (loweredCase) throw new TypeError('Unknown encoding: ' + encoding)
- encoding = (encoding + '').toLowerCase()
- loweredCase = true
- }
- }
-}
-
-// The property is used by `Buffer.isBuffer` and `is-buffer` (in Safari 5-7) to detect
-// Buffer instances.
-Buffer.prototype._isBuffer = true
-
-function swap (b, n, m) {
- var i = b[n]
- b[n] = b[m]
- b[m] = i
-}
-
-Buffer.prototype.swap16 = function swap16 () {
- var len = this.length
- if (len % 2 !== 0) {
- throw new RangeError('Buffer size must be a multiple of 16-bits')
- }
- for (var i = 0; i < len; i += 2) {
- swap(this, i, i + 1)
- }
- return this
-}
-
-Buffer.prototype.swap32 = function swap32 () {
- var len = this.length
- if (len % 4 !== 0) {
- throw new RangeError('Buffer size must be a multiple of 32-bits')
- }
- for (var i = 0; i < len; i += 4) {
- swap(this, i, i + 3)
- swap(this, i + 1, i + 2)
- }
- return this
-}
-
-Buffer.prototype.swap64 = function swap64 () {
- var len = this.length
- if (len % 8 !== 0) {
- throw new RangeError('Buffer size must be a multiple of 64-bits')
- }
- for (var i = 0; i < len; i += 8) {
- swap(this, i, i + 7)
- swap(this, i + 1, i + 6)
- swap(this, i + 2, i + 5)
- swap(this, i + 3, i + 4)
- }
- return this
-}
-
-Buffer.prototype.toString = function toString () {
- var length = this.length | 0
- if (length === 0) return ''
- if (arguments.length === 0) return utf8Slice(this, 0, length)
- return slowToString.apply(this, arguments)
-}
-
-Buffer.prototype.equals = function equals (b) {
- if (!Buffer.isBuffer(b)) throw new TypeError('Argument must be a Buffer')
- if (this === b) return true
- return Buffer.compare(this, b) === 0
-}
-
-Buffer.prototype.inspect = function inspect () {
- var str = ''
- var max = exports.INSPECT_MAX_BYTES
- if (this.length > 0) {
- str = this.toString('hex', 0, max).match(/.{2}/g).join(' ')
- if (this.length > max) str += ' ... '
- }
- return '<Buffer ' + str + '>'
-}
-
-Buffer.prototype.compare = function compare (target, start, end, thisStart, thisEnd) {
- if (!Buffer.isBuffer(target)) {
- throw new TypeError('Argument must be a Buffer')
- }
-
- if (start === undefined) {
- start = 0
- }
- if (end === undefined) {
- end = target ? target.length : 0
- }
- if (thisStart === undefined) {
- thisStart = 0
- }
- if (thisEnd === undefined) {
- thisEnd = this.length
- }
-
- if (start < 0 || end > target.length || thisStart < 0 || thisEnd > this.length) {
- throw new RangeError('out of range index')
- }
-
- if (thisStart >= thisEnd && start >= end) {
- return 0
- }
- if (thisStart >= thisEnd) {
- return -1
- }
- if (start >= end) {
- return 1
- }
-
- start >>>= 0
- end >>>= 0
- thisStart >>>= 0
- thisEnd >>>= 0
-
- if (this === target) return 0
-
- var x = thisEnd - thisStart
- var y = end - start
- var len = Math.min(x, y)
-
- var thisCopy = this.slice(thisStart, thisEnd)
- var targetCopy = target.slice(start, end)
-
- for (var i = 0; i < len; ++i) {
- if (thisCopy[i] !== targetCopy[i]) {
- x = thisCopy[i]
- y = targetCopy[i]
- break
- }
- }
-
- if (x < y) return -1
- if (y < x) return 1
- return 0
-}
-
-// Finds either the first index of `val` in `buffer` at offset >= `byteOffset`,
-// OR the last index of `val` in `buffer` at offset <= `byteOffset`.
-//
-// Arguments:
-// - buffer - a Buffer to search
-// - val - a string, Buffer, or number
-// - byteOffset - an index into `buffer`; will be clamped to an int32
-// - encoding - an optional encoding, relevant is val is a string
-// - dir - true for indexOf, false for lastIndexOf
-function bidirectionalIndexOf (buffer, val, byteOffset, encoding, dir) {
- // Empty buffer means no match
- if (buffer.length === 0) return -1
-
- // Normalize byteOffset
- if (typeof byteOffset === 'string') {
- encoding = byteOffset
- byteOffset = 0
- } else if (byteOffset > 0x7fffffff) {
- byteOffset = 0x7fffffff
- } else if (byteOffset < -0x80000000) {
- byteOffset = -0x80000000
- }
- byteOffset = +byteOffset // Coerce to Number.
- if (isNaN(byteOffset)) {
- // byteOffset: it it's undefined, null, NaN, "foo", etc, search whole buffer
- byteOffset = dir ? 0 : (buffer.length - 1)
- }
-
- // Normalize byteOffset: negative offsets start from the end of the buffer
- if (byteOffset < 0) byteOffset = buffer.length + byteOffset
- if (byteOffset >= buffer.length) {
- if (dir) return -1
- else byteOffset = buffer.length - 1
- } else if (byteOffset < 0) {
- if (dir) byteOffset = 0
- else return -1
- }
-
- // Normalize val
- if (typeof val === 'string') {
- val = Buffer.from(val, encoding)
- }
-
- // Finally, search either indexOf (if dir is true) or lastIndexOf
- if (Buffer.isBuffer(val)) {
- // Special case: looking for empty string/buffer always fails
- if (val.length === 0) {
- return -1
- }
- return arrayIndexOf(buffer, val, byteOffset, encoding, dir)
- } else if (typeof val === 'number') {
- val = val & 0xFF // Search for a byte value [0-255]
- if (Buffer.TYPED_ARRAY_SUPPORT &&
- typeof Uint8Array.prototype.indexOf === 'function') {
- if (dir) {
- return Uint8Array.prototype.indexOf.call(buffer, val, byteOffset)
- } else {
- return Uint8Array.prototype.lastIndexOf.call(buffer, val, byteOffset)
- }
- }
- return arrayIndexOf(buffer, [ val ], byteOffset, encoding, dir)
- }
-
- throw new TypeError('val must be string, number or Buffer')
-}
-
-function arrayIndexOf (arr, val, byteOffset, encoding, dir) {
- var indexSize = 1
- var arrLength = arr.length
- var valLength = val.length
-
- if (encoding !== undefined) {
- encoding = String(encoding).toLowerCase()
- if (encoding === 'ucs2' || encoding === 'ucs-2' ||
- encoding === 'utf16le' || encoding === 'utf-16le') {
- if (arr.length < 2 || val.length < 2) {
- return -1
- }
- indexSize = 2
- arrLength /= 2
- valLength /= 2
- byteOffset /= 2
- }
- }
-
- function read (buf, i) {
- if (indexSize === 1) {
- return buf[i]
- } else {
- return buf.readUInt16BE(i * indexSize)
- }
- }
-
- var i
- if (dir) {
- var foundIndex = -1
- for (i = byteOffset; i < arrLength; i++) {
- if (read(arr, i) === read(val, foundIndex === -1 ? 0 : i - foundIndex)) {
- if (foundIndex === -1) foundIndex = i
- if (i - foundIndex + 1 === valLength) return foundIndex * indexSize
- } else {
- if (foundIndex !== -1) i -= i - foundIndex
- foundIndex = -1
- }
- }
- } else {
- if (byteOffset + valLength > arrLength) byteOffset = arrLength - valLength
- for (i = byteOffset; i >= 0; i--) {
- var found = true
- for (var j = 0; j < valLength; j++) {
- if (read(arr, i + j) !== read(val, j)) {
- found = false
- break
- }
- }
- if (found) return i
- }
- }
-
- return -1
-}
-
-Buffer.prototype.includes = function includes (val, byteOffset, encoding) {
- return this.indexOf(val, byteOffset, encoding) !== -1
-}
-
-Buffer.prototype.indexOf = function indexOf (val, byteOffset, encoding) {
- return bidirectionalIndexOf(this, val, byteOffset, encoding, true)
-}
-
-Buffer.prototype.lastIndexOf = function lastIndexOf (val, byteOffset, encoding) {
- return bidirectionalIndexOf(this, val, byteOffset, encoding, false)
-}
-
-function hexWrite (buf, string, offset, length) {
- offset = Number(offset) || 0
- var remaining = buf.length - offset
- if (!length) {
- length = remaining
- } else {
- length = Number(length)
- if (length > remaining) {
- length = remaining
- }
- }
-
- // must be an even number of digits
- var strLen = string.length
- if (strLen % 2 !== 0) throw new TypeError('Invalid hex string')
-
- if (length > strLen / 2) {
- length = strLen / 2
- }
- for (var i = 0; i < length; ++i) {
- var parsed = parseInt(string.substr(i * 2, 2), 16)
- if (isNaN(parsed)) return i
- buf[offset + i] = parsed
- }
- return i
-}
-
-function utf8Write (buf, string, offset, length) {
- return blitBuffer(utf8ToBytes(string, buf.length - offset), buf, offset, length)
-}
-
-function asciiWrite (buf, string, offset, length) {
- return blitBuffer(asciiToBytes(string), buf, offset, length)
-}
-
-function latin1Write (buf, string, offset, length) {
- return asciiWrite(buf, string, offset, length)
-}
-
-function base64Write (buf, string, offset, length) {
- return blitBuffer(base64ToBytes(string), buf, offset, length)
-}
-
-function ucs2Write (buf, string, offset, length) {
- return blitBuffer(utf16leToBytes(string, buf.length - offset), buf, offset, length)
-}
-
-Buffer.prototype.write = function write (string, offset, length, encoding) {
- // Buffer#write(string)
- if (offset === undefined) {
- encoding = 'utf8'
- length = this.length
- offset = 0
- // Buffer#write(string, encoding)
- } else if (length === undefined && typeof offset === 'string') {
- encoding = offset
- length = this.length
- offset = 0
- // Buffer#write(string, offset[, length][, encoding])
- } else if (isFinite(offset)) {
- offset = offset | 0
- if (isFinite(length)) {
- length = length | 0
- if (encoding === undefined) encoding = 'utf8'
- } else {
- encoding = length
- length = undefined
- }
- // legacy write(string, encoding, offset, length) - remove in v0.13
- } else {
- throw new Error(
- 'Buffer.write(string, encoding, offset[, length]) is no longer supported'
- )
- }
-
- var remaining = this.length - offset
- if (length === undefined || length > remaining) length = remaining
-
- if ((string.length > 0 && (length < 0 || offset < 0)) || offset > this.length) {
- throw new RangeError('Attempt to write outside buffer bounds')
- }
-
- if (!encoding) encoding = 'utf8'
-
- var loweredCase = false
- for (;;) {
- switch (encoding) {
- case 'hex':
- return hexWrite(this, string, offset, length)
-
- case 'utf8':
- case 'utf-8':
- return utf8Write(this, string, offset, length)
-
- case 'ascii':
- return asciiWrite(this, string, offset, length)
-
- case 'latin1':
- case 'binary':
- return latin1Write(this, string, offset, length)
-
- case 'base64':
- // Warning: maxLength not taken into account in base64Write
- return base64Write(this, string, offset, length)
-
- case 'ucs2':
- case 'ucs-2':
- case 'utf16le':
- case 'utf-16le':
- return ucs2Write(this, string, offset, length)
-
- default:
- if (loweredCase) throw new TypeError('Unknown encoding: ' + encoding)
- encoding = ('' + encoding).toLowerCase()
- loweredCase = true
- }
- }
-}
-
-Buffer.prototype.toJSON = function toJSON () {
- return {
- type: 'Buffer',
- data: Array.prototype.slice.call(this._arr || this, 0)
- }
-}
-
-function base64Slice (buf, start, end) {
- if (start === 0 && end === buf.length) {
- return base64.fromByteArray(buf)
- } else {
- return base64.fromByteArray(buf.slice(start, end))
- }
-}
-
-function utf8Slice (buf, start, end) {
- end = Math.min(buf.length, end)
- var res = []
-
- var i = start
- while (i < end) {
- var firstByte = buf[i]
- var codePoint = null
- var bytesPerSequence = (firstByte > 0xEF) ? 4
- : (firstByte > 0xDF) ? 3
- : (firstByte > 0xBF) ? 2
- : 1
-
- if (i + bytesPerSequence <= end) {
- var secondByte, thirdByte, fourthByte, tempCodePoint
-
- switch (bytesPerSequence) {
- case 1:
- if (firstByte < 0x80) {
- codePoint = firstByte
- }
- break
- case 2:
- secondByte = buf[i + 1]
- if ((secondByte & 0xC0) === 0x80) {
- tempCodePoint = (firstByte & 0x1F) << 0x6 | (secondByte & 0x3F)
- if (tempCodePoint > 0x7F) {
- codePoint = tempCodePoint
- }
- }
- break
- case 3:
- secondByte = buf[i + 1]
- thirdByte = buf[i + 2]
- if ((secondByte & 0xC0) === 0x80 && (thirdByte & 0xC0) === 0x80) {
- tempCodePoint = (firstByte & 0xF) << 0xC | (secondByte & 0x3F) << 0x6 | (thirdByte & 0x3F)
- if (tempCodePoint > 0x7FF && (tempCodePoint < 0xD800 || tempCodePoint > 0xDFFF)) {
- codePoint = tempCodePoint
- }
- }
- break
- case 4:
- secondByte = buf[i + 1]
- thirdByte = buf[i + 2]
- fourthByte = buf[i + 3]
- if ((secondByte & 0xC0) === 0x80 && (thirdByte & 0xC0) === 0x80 && (fourthByte & 0xC0) === 0x80) {
- tempCodePoint = (firstByte & 0xF) << 0x12 | (secondByte & 0x3F) << 0xC | (thirdByte & 0x3F) << 0x6 | (fourthByte & 0x3F)
- if (tempCodePoint > 0xFFFF && tempCodePoint < 0x110000) {
- codePoint = tempCodePoint
- }
- }
- }
- }
-
- if (codePoint === null) {
- // we did not generate a valid codePoint so insert a
- // replacement char (U+FFFD) and advance only 1 byte
- codePoint = 0xFFFD
- bytesPerSequence = 1
- } else if (codePoint > 0xFFFF) {
- // encode to utf16 (surrogate pair dance)
- codePoint -= 0x10000
- res.push(codePoint >>> 10 & 0x3FF | 0xD800)
- codePoint = 0xDC00 | codePoint & 0x3FF
- }
-
- res.push(codePoint)
- i += bytesPerSequence
- }
-
- return decodeCodePointsArray(res)
-}
-
-// Based on http://stackoverflow.com/a/22747272/680742, the browser with
-// the lowest limit is Chrome, with 0x10000 args.
-// We go 1 magnitude less, for safety
-var MAX_ARGUMENTS_LENGTH = 0x1000
-
-function decodeCodePointsArray (codePoints) {
- var len = codePoints.length
- if (len <= MAX_ARGUMENTS_LENGTH) {
- return String.fromCharCode.apply(String, codePoints) // avoid extra slice()
- }
-
- // Decode in chunks to avoid "call stack size exceeded".
- var res = ''
- var i = 0
- while (i < len) {
- res += String.fromCharCode.apply(
- String,
- codePoints.slice(i, i += MAX_ARGUMENTS_LENGTH)
- )
- }
- return res
-}
-
-function asciiSlice (buf, start, end) {
- var ret = ''
- end = Math.min(buf.length, end)
-
- for (var i = start; i < end; ++i) {
- ret += String.fromCharCode(buf[i] & 0x7F)
- }
- return ret
-}
-
-function latin1Slice (buf, start, end) {
- var ret = ''
- end = Math.min(buf.length, end)
-
- for (var i = start; i < end; ++i) {
- ret += String.fromCharCode(buf[i])
- }
- return ret
-}
-
-function hexSlice (buf, start, end) {
- var len = buf.length
-
- if (!start || start < 0) start = 0
- if (!end || end < 0 || end > len) end = len
-
- var out = ''
- for (var i = start; i < end; ++i) {
- out += toHex(buf[i])
- }
- return out
-}
-
-function utf16leSlice (buf, start, end) {
- var bytes = buf.slice(start, end)
- var res = ''
- for (var i = 0; i < bytes.length; i += 2) {
- res += String.fromCharCode(bytes[i] + bytes[i + 1] * 256)
- }
- return res
-}
-
-Buffer.prototype.slice = function slice (start, end) {
- var len = this.length
- start = ~~start
- end = end === undefined ? len : ~~end
-
- if (start < 0) {
- start += len
- if (start < 0) start = 0
- } else if (start > len) {
- start = len
- }
-
- if (end < 0) {
- end += len
- if (end < 0) end = 0
- } else if (end > len) {
- end = len
- }
-
- if (end < start) end = start
-
- var newBuf
- if (Buffer.TYPED_ARRAY_SUPPORT) {
- newBuf = this.subarray(start, end)
- newBuf.__proto__ = Buffer.prototype
- } else {
- var sliceLen = end - start
- newBuf = new Buffer(sliceLen, undefined)
- for (var i = 0; i < sliceLen; ++i) {
- newBuf[i] = this[i + start]
- }
- }
-
- return newBuf
-}
-
-/*
- * Need to make sure that buffer isn't trying to write out of bounds.
- */
-function checkOffset (offset, ext, length) {
- if ((offset % 1) !== 0 || offset < 0) throw new RangeError('offset is not uint')
- if (offset + ext > length) throw new RangeError('Trying to access beyond buffer length')
-}
-
-Buffer.prototype.readUIntLE = function readUIntLE (offset, byteLength, noAssert) {
- offset = offset | 0
- byteLength = byteLength | 0
- if (!noAssert) checkOffset(offset, byteLength, this.length)
-
- var val = this[offset]
- var mul = 1
- var i = 0
- while (++i < byteLength && (mul *= 0x100)) {
- val += this[offset + i] * mul
- }
-
- return val
-}
-
-Buffer.prototype.readUIntBE = function readUIntBE (offset, byteLength, noAssert) {
- offset = offset | 0
- byteLength = byteLength | 0
- if (!noAssert) {
- checkOffset(offset, byteLength, this.length)
- }
-
- var val = this[offset + --byteLength]
- var mul = 1
- while (byteLength > 0 && (mul *= 0x100)) {
- val += this[offset + --byteLength] * mul
- }
-
- return val
-}
-
-Buffer.prototype.readUInt8 = function readUInt8 (offset, noAssert) {
- if (!noAssert) checkOffset(offset, 1, this.length)
- return this[offset]
-}
-
-Buffer.prototype.readUInt16LE = function readUInt16LE (offset, noAssert) {
- if (!noAssert) checkOffset(offset, 2, this.length)
- return this[offset] | (this[offset + 1] << 8)
-}
-
-Buffer.prototype.readUInt16BE = function readUInt16BE (offset, noAssert) {
- if (!noAssert) checkOffset(offset, 2, this.length)
- return (this[offset] << 8) | this[offset + 1]
-}
-
-Buffer.prototype.readUInt32LE = function readUInt32LE (offset, noAssert) {
- if (!noAssert) checkOffset(offset, 4, this.length)
-
- return ((this[offset]) |
- (this[offset + 1] << 8) |
- (this[offset + 2] << 16)) +
- (this[offset + 3] * 0x1000000)
-}
-
-Buffer.prototype.readUInt32BE = function readUInt32BE (offset, noAssert) {
- if (!noAssert) checkOffset(offset, 4, this.length)
-
- return (this[offset] * 0x1000000) +
- ((this[offset + 1] << 16) |
- (this[offset + 2] << 8) |
- this[offset + 3])
-}
-
-Buffer.prototype.readIntLE = function readIntLE (offset, byteLength, noAssert) {
- offset = offset | 0
- byteLength = byteLength | 0
- if (!noAssert) checkOffset(offset, byteLength, this.length)
-
- var val = this[offset]
- var mul = 1
- var i = 0
- while (++i < byteLength && (mul *= 0x100)) {
- val += this[offset + i] * mul
- }
- mul *= 0x80
-
- if (val >= mul) val -= Math.pow(2, 8 * byteLength)
-
- return val
-}
-
-Buffer.prototype.readIntBE = function readIntBE (offset, byteLength, noAssert) {
- offset = offset | 0
- byteLength = byteLength | 0
- if (!noAssert) checkOffset(offset, byteLength, this.length)
-
- var i = byteLength
- var mul = 1
- var val = this[offset + --i]
- while (i > 0 && (mul *= 0x100)) {
- val += this[offset + --i] * mul
- }
- mul *= 0x80
-
- if (val >= mul) val -= Math.pow(2, 8 * byteLength)
-
- return val
-}
-
-Buffer.prototype.readInt8 = function readInt8 (offset, noAssert) {
- if (!noAssert) checkOffset(offset, 1, this.length)
- if (!(this[offset] & 0x80)) return (this[offset])
- return ((0xff - this[offset] + 1) * -1)
-}
-
-Buffer.prototype.readInt16LE = function readInt16LE (offset, noAssert) {
- if (!noAssert) checkOffset(offset, 2, this.length)
- var val = this[offset] | (this[offset + 1] << 8)
- return (val & 0x8000) ? val | 0xFFFF0000 : val
-}
-
-Buffer.prototype.readInt16BE = function readInt16BE (offset, noAssert) {
- if (!noAssert) checkOffset(offset, 2, this.length)
- var val = this[offset + 1] | (this[offset] << 8)
- return (val & 0x8000) ? val | 0xFFFF0000 : val
-}
-
-Buffer.prototype.readInt32LE = function readInt32LE (offset, noAssert) {
- if (!noAssert) checkOffset(offset, 4, this.length)
-
- return (this[offset]) |
- (this[offset + 1] << 8) |
- (this[offset + 2] << 16) |
- (this[offset + 3] << 24)
-}
-
-Buffer.prototype.readInt32BE = function readInt32BE (offset, noAssert) {
- if (!noAssert) checkOffset(offset, 4, this.length)
-
- return (this[offset] << 24) |
- (this[offset + 1] << 16) |
- (this[offset + 2] << 8) |
- (this[offset + 3])
-}
-
-Buffer.prototype.readFloatLE = function readFloatLE (offset, noAssert) {
- if (!noAssert) checkOffset(offset, 4, this.length)
- return ieee754.read(this, offset, true, 23, 4)
-}
-
-Buffer.prototype.readFloatBE = function readFloatBE (offset, noAssert) {
- if (!noAssert) checkOffset(offset, 4, this.length)
- return ieee754.read(this, offset, false, 23, 4)
-}
-
-Buffer.prototype.readDoubleLE = function readDoubleLE (offset, noAssert) {
- if (!noAssert) checkOffset(offset, 8, this.length)
- return ieee754.read(this, offset, true, 52, 8)
-}
-
-Buffer.prototype.readDoubleBE = function readDoubleBE (offset, noAssert) {
- if (!noAssert) checkOffset(offset, 8, this.length)
- return ieee754.read(this, offset, false, 52, 8)
-}
-
-function checkInt (buf, value, offset, ext, max, min) {
- if (!Buffer.isBuffer(buf)) throw new TypeError('"buffer" argument must be a Buffer instance')
- if (value > max || value < min) throw new RangeError('"value" argument is out of bounds')
- if (offset + ext > buf.length) throw new RangeError('Index out of range')
-}
-
-Buffer.prototype.writeUIntLE = function writeUIntLE (value, offset, byteLength, noAssert) {
- value = +value
- offset = offset | 0
- byteLength = byteLength | 0
- if (!noAssert) {
- var maxBytes = Math.pow(2, 8 * byteLength) - 1
- checkInt(this, value, offset, byteLength, maxBytes, 0)
- }
-
- var mul = 1
- var i = 0
- this[offset] = value & 0xFF
- while (++i < byteLength && (mul *= 0x100)) {
- this[offset + i] = (value / mul) & 0xFF
- }
-
- return offset + byteLength
-}
-
-Buffer.prototype.writeUIntBE = function writeUIntBE (value, offset, byteLength, noAssert) {
- value = +value
- offset = offset | 0
- byteLength = byteLength | 0
- if (!noAssert) {
- var maxBytes = Math.pow(2, 8 * byteLength) - 1
- checkInt(this, value, offset, byteLength, maxBytes, 0)
- }
-
- var i = byteLength - 1
- var mul = 1
- this[offset + i] = value & 0xFF
- while (--i >= 0 && (mul *= 0x100)) {
- this[offset + i] = (value / mul) & 0xFF
- }
-
- return offset + byteLength
-}
-
-Buffer.prototype.writeUInt8 = function writeUInt8 (value, offset, noAssert) {
- value = +value
- offset = offset | 0
- if (!noAssert) checkInt(this, value, offset, 1, 0xff, 0)
- if (!Buffer.TYPED_ARRAY_SUPPORT) value = Math.floor(value)
- this[offset] = (value & 0xff)
- return offset + 1
-}
-
-function objectWriteUInt16 (buf, value, offset, littleEndian) {
- if (value < 0) value = 0xffff + value + 1
- for (var i = 0, j = Math.min(buf.length - offset, 2); i < j; ++i) {
- buf[offset + i] = (value & (0xff << (8 * (littleEndian ? i : 1 - i)))) >>>
- (littleEndian ? i : 1 - i) * 8
- }
-}
-
-Buffer.prototype.writeUInt16LE = function writeUInt16LE (value, offset, noAssert) {
- value = +value
- offset = offset | 0
- if (!noAssert) checkInt(this, value, offset, 2, 0xffff, 0)
- if (Buffer.TYPED_ARRAY_SUPPORT) {
- this[offset] = (value & 0xff)
- this[offset + 1] = (value >>> 8)
- } else {
- objectWriteUInt16(this, value, offset, true)
- }
- return offset + 2
-}
-
-Buffer.prototype.writeUInt16BE = function writeUInt16BE (value, offset, noAssert) {
- value = +value
- offset = offset | 0
- if (!noAssert) checkInt(this, value, offset, 2, 0xffff, 0)
- if (Buffer.TYPED_ARRAY_SUPPORT) {
- this[offset] = (value >>> 8)
- this[offset + 1] = (value & 0xff)
- } else {
- objectWriteUInt16(this, value, offset, false)
- }
- return offset + 2
-}
-
-function objectWriteUInt32 (buf, value, offset, littleEndian) {
- if (value < 0) value = 0xffffffff + value + 1
- for (var i = 0, j = Math.min(buf.length - offset, 4); i < j; ++i) {
- buf[offset + i] = (value >>> (littleEndian ? i : 3 - i) * 8) & 0xff
- }
-}
-
-Buffer.prototype.writeUInt32LE = function writeUInt32LE (value, offset, noAssert) {
- value = +value
- offset = offset | 0
- if (!noAssert) checkInt(this, value, offset, 4, 0xffffffff, 0)
- if (Buffer.TYPED_ARRAY_SUPPORT) {
- this[offset + 3] = (value >>> 24)
- this[offset + 2] = (value >>> 16)
- this[offset + 1] = (value >>> 8)
- this[offset] = (value & 0xff)
- } else {
- objectWriteUInt32(this, value, offset, true)
- }
- return offset + 4
-}
-
-Buffer.prototype.writeUInt32BE = function writeUInt32BE (value, offset, noAssert) {
- value = +value
- offset = offset | 0
- if (!noAssert) checkInt(this, value, offset, 4, 0xffffffff, 0)
- if (Buffer.TYPED_ARRAY_SUPPORT) {
- this[offset] = (value >>> 24)
- this[offset + 1] = (value >>> 16)
- this[offset + 2] = (value >>> 8)
- this[offset + 3] = (value & 0xff)
- } else {
- objectWriteUInt32(this, value, offset, false)
- }
- return offset + 4
-}
-
-Buffer.prototype.writeIntLE = function writeIntLE (value, offset, byteLength, noAssert) {
- value = +value
- offset = offset | 0
- if (!noAssert) {
- var limit = Math.pow(2, 8 * byteLength - 1)
-
- checkInt(this, value, offset, byteLength, limit - 1, -limit)
- }
-
- var i = 0
- var mul = 1
- var sub = 0
- this[offset] = value & 0xFF
- while (++i < byteLength && (mul *= 0x100)) {
- if (value < 0 && sub === 0 && this[offset + i - 1] !== 0) {
- sub = 1
- }
- this[offset + i] = ((value / mul) >> 0) - sub & 0xFF
- }
-
- return offset + byteLength
-}
-
-Buffer.prototype.writeIntBE = function writeIntBE (value, offset, byteLength, noAssert) {
- value = +value
- offset = offset | 0
- if (!noAssert) {
- var limit = Math.pow(2, 8 * byteLength - 1)
-
- checkInt(this, value, offset, byteLength, limit - 1, -limit)
- }
-
- var i = byteLength - 1
- var mul = 1
- var sub = 0
- this[offset + i] = value & 0xFF
- while (--i >= 0 && (mul *= 0x100)) {
- if (value < 0 && sub === 0 && this[offset + i + 1] !== 0) {
- sub = 1
- }
- this[offset + i] = ((value / mul) >> 0) - sub & 0xFF
- }
-
- return offset + byteLength
-}
-
-Buffer.prototype.writeInt8 = function writeInt8 (value, offset, noAssert) {
- value = +value
- offset = offset | 0
- if (!noAssert) checkInt(this, value, offset, 1, 0x7f, -0x80)
- if (!Buffer.TYPED_ARRAY_SUPPORT) value = Math.floor(value)
- if (value < 0) value = 0xff + value + 1
- this[offset] = (value & 0xff)
- return offset + 1
-}
-
-Buffer.prototype.writeInt16LE = function writeInt16LE (value, offset, noAssert) {
- value = +value
- offset = offset | 0
- if (!noAssert) checkInt(this, value, offset, 2, 0x7fff, -0x8000)
- if (Buffer.TYPED_ARRAY_SUPPORT) {
- this[offset] = (value & 0xff)
- this[offset + 1] = (value >>> 8)
- } else {
- objectWriteUInt16(this, value, offset, true)
- }
- return offset + 2
-}
-
-Buffer.prototype.writeInt16BE = function writeInt16BE (value, offset, noAssert) {
- value = +value
- offset = offset | 0
- if (!noAssert) checkInt(this, value, offset, 2, 0x7fff, -0x8000)
- if (Buffer.TYPED_ARRAY_SUPPORT) {
- this[offset] = (value >>> 8)
- this[offset + 1] = (value & 0xff)
- } else {
- objectWriteUInt16(this, value, offset, false)
- }
- return offset + 2
-}
-
-Buffer.prototype.writeInt32LE = function writeInt32LE (value, offset, noAssert) {
- value = +value
- offset = offset | 0
- if (!noAssert) checkInt(this, value, offset, 4, 0x7fffffff, -0x80000000)
- if (Buffer.TYPED_ARRAY_SUPPORT) {
- this[offset] = (value & 0xff)
- this[offset + 1] = (value >>> 8)
- this[offset + 2] = (value >>> 16)
- this[offset + 3] = (value >>> 24)
- } else {
- objectWriteUInt32(this, value, offset, true)
- }
- return offset + 4
-}
-
-Buffer.prototype.writeInt32BE = function writeInt32BE (value, offset, noAssert) {
- value = +value
- offset = offset | 0
- if (!noAssert) checkInt(this, value, offset, 4, 0x7fffffff, -0x80000000)
- if (value < 0) value = 0xffffffff + value + 1
- if (Buffer.TYPED_ARRAY_SUPPORT) {
- this[offset] = (value >>> 24)
- this[offset + 1] = (value >>> 16)
- this[offset + 2] = (value >>> 8)
- this[offset + 3] = (value & 0xff)
- } else {
- objectWriteUInt32(this, value, offset, false)
- }
- return offset + 4
-}
-
-function checkIEEE754 (buf, value, offset, ext, max, min) {
- if (offset + ext > buf.length) throw new RangeError('Index out of range')
- if (offset < 0) throw new RangeError('Index out of range')
-}
-
-function writeFloat (buf, value, offset, littleEndian, noAssert) {
- if (!noAssert) {
- checkIEEE754(buf, value, offset, 4, 3.4028234663852886e+38, -3.4028234663852886e+38)
- }
- ieee754.write(buf, value, offset, littleEndian, 23, 4)
- return offset + 4
-}
-
-Buffer.prototype.writeFloatLE = function writeFloatLE (value, offset, noAssert) {
- return writeFloat(this, value, offset, true, noAssert)
-}
-
-Buffer.prototype.writeFloatBE = function writeFloatBE (value, offset, noAssert) {
- return writeFloat(this, value, offset, false, noAssert)
-}
-
-function writeDouble (buf, value, offset, littleEndian, noAssert) {
- if (!noAssert) {
- checkIEEE754(buf, value, offset, 8, 1.7976931348623157E+308, -1.7976931348623157E+308)
- }
- ieee754.write(buf, value, offset, littleEndian, 52, 8)
- return offset + 8
-}
-
-Buffer.prototype.writeDoubleLE = function writeDoubleLE (value, offset, noAssert) {
- return writeDouble(this, value, offset, true, noAssert)
-}
-
-Buffer.prototype.writeDoubleBE = function writeDoubleBE (value, offset, noAssert) {
- return writeDouble(this, value, offset, false, noAssert)
-}
-
-// copy(targetBuffer, targetStart=0, sourceStart=0, sourceEnd=buffer.length)
-Buffer.prototype.copy = function copy (target, targetStart, start, end) {
- if (!start) start = 0
- if (!end && end !== 0) end = this.length
- if (targetStart >= target.length) targetStart = target.length
- if (!targetStart) targetStart = 0
- if (end > 0 && end < start) end = start
-
- // Copy 0 bytes; we're done
- if (end === start) return 0
- if (target.length === 0 || this.length === 0) return 0
-
- // Fatal error conditions
- if (targetStart < 0) {
- throw new RangeError('targetStart out of bounds')
- }
- if (start < 0 || start >= this.length) throw new RangeError('sourceStart out of bounds')
- if (end < 0) throw new RangeError('sourceEnd out of bounds')
-
- // Are we oob?
- if (end > this.length) end = this.length
- if (target.length - targetStart < end - start) {
- end = target.length - targetStart + start
- }
-
- var len = end - start
- var i
-
- if (this === target && start < targetStart && targetStart < end) {
- // descending copy from end
- for (i = len - 1; i >= 0; --i) {
- target[i + targetStart] = this[i + start]
- }
- } else if (len < 1000 || !Buffer.TYPED_ARRAY_SUPPORT) {
- // ascending copy from start
- for (i = 0; i < len; ++i) {
- target[i + targetStart] = this[i + start]
- }
- } else {
- Uint8Array.prototype.set.call(
- target,
- this.subarray(start, start + len),
- targetStart
- )
- }
-
- return len
-}
-
-// Usage:
-// buffer.fill(number[, offset[, end]])
-// buffer.fill(buffer[, offset[, end]])
-// buffer.fill(string[, offset[, end]][, encoding])
-Buffer.prototype.fill = function fill (val, start, end, encoding) {
- // Handle string cases:
- if (typeof val === 'string') {
- if (typeof start === 'string') {
- encoding = start
- start = 0
- end = this.length
- } else if (typeof end === 'string') {
- encoding = end
- end = this.length
- }
- if (val.length === 1) {
- var code = val.charCodeAt(0)
- if (code < 256) {
- val = code
- }
- }
- if (encoding !== undefined && typeof encoding !== 'string') {
- throw new TypeError('encoding must be a string')
- }
- if (typeof encoding === 'string' && !Buffer.isEncoding(encoding)) {
- throw new TypeError('Unknown encoding: ' + encoding)
- }
- } else if (typeof val === 'number') {
- val = val & 255
- }
-
- // Invalid ranges are not set to a default, so can range check early.
- if (start < 0 || this.length < start || this.length < end) {
- throw new RangeError('Out of range index')
- }
-
- if (end <= start) {
- return this
- }
-
- start = start >>> 0
- end = end === undefined ? this.length : end >>> 0
-
- if (!val) val = 0
-
- var i
- if (typeof val === 'number') {
- for (i = start; i < end; ++i) {
- this[i] = val
- }
- } else {
- var bytes = Buffer.isBuffer(val)
- ? val
- : utf8ToBytes(new Buffer(val, encoding).toString())
- var len = bytes.length
- for (i = 0; i < end - start; ++i) {
- this[i + start] = bytes[i % len]
- }
- }
-
- return this
-}
-
-// HELPER FUNCTIONS
-// ================
-
-var INVALID_BASE64_RE = /[^+\/0-9A-Za-z-_]/g
-
-function base64clean (str) {
- // Node strips out invalid characters like \n and \t from the string, base64-js does not
- str = stringtrim(str).replace(INVALID_BASE64_RE, '')
- // Node converts strings with length < 2 to ''
- if (str.length < 2) return ''
- // Node allows for non-padded base64 strings (missing trailing ===), base64-js does not
- while (str.length % 4 !== 0) {
- str = str + '='
- }
- return str
-}
-
-function stringtrim (str) {
- if (str.trim) return str.trim()
- return str.replace(/^\s+|\s+$/g, '')
-}
-
-function toHex (n) {
- if (n < 16) return '0' + n.toString(16)
- return n.toString(16)
-}
-
-function utf8ToBytes (string, units) {
- units = units || Infinity
- var codePoint
- var length = string.length
- var leadSurrogate = null
- var bytes = []
-
- for (var i = 0; i < length; ++i) {
- codePoint = string.charCodeAt(i)
-
- // is surrogate component
- if (codePoint > 0xD7FF && codePoint < 0xE000) {
- // last char was a lead
- if (!leadSurrogate) {
- // no lead yet
- if (codePoint > 0xDBFF) {
- // unexpected trail
- if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD)
- continue
- } else if (i + 1 === length) {
- // unpaired lead
- if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD)
- continue
- }
-
- // valid lead
- leadSurrogate = codePoint
-
- continue
- }
-
- // 2 leads in a row
- if (codePoint < 0xDC00) {
- if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD)
- leadSurrogate = codePoint
- continue
- }
-
- // valid surrogate pair
- codePoint = (leadSurrogate - 0xD800 << 10 | codePoint - 0xDC00) + 0x10000
- } else if (leadSurrogate) {
- // valid bmp char, but last char was a lead
- if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD)
- }
-
- leadSurrogate = null
-
- // encode utf8
- if (codePoint < 0x80) {
- if ((units -= 1) < 0) break
- bytes.push(codePoint)
- } else if (codePoint < 0x800) {
- if ((units -= 2) < 0) break
- bytes.push(
- codePoint >> 0x6 | 0xC0,
- codePoint & 0x3F | 0x80
- )
- } else if (codePoint < 0x10000) {
- if ((units -= 3) < 0) break
- bytes.push(
- codePoint >> 0xC | 0xE0,
- codePoint >> 0x6 & 0x3F | 0x80,
- codePoint & 0x3F | 0x80
- )
- } else if (codePoint < 0x110000) {
- if ((units -= 4) < 0) break
- bytes.push(
- codePoint >> 0x12 | 0xF0,
- codePoint >> 0xC & 0x3F | 0x80,
- codePoint >> 0x6 & 0x3F | 0x80,
- codePoint & 0x3F | 0x80
- )
- } else {
- throw new Error('Invalid code point')
- }
- }
-
- return bytes
-}
-
-function asciiToBytes (str) {
- var byteArray = []
- for (var i = 0; i < str.length; ++i) {
- // Node's code seems to be doing this and not & 0x7F..
- byteArray.push(str.charCodeAt(i) & 0xFF)
- }
- return byteArray
-}
-
-function utf16leToBytes (str, units) {
- var c, hi, lo
- var byteArray = []
- for (var i = 0; i < str.length; ++i) {
- if ((units -= 2) < 0) break
-
- c = str.charCodeAt(i)
- hi = c >> 8
- lo = c % 256
- byteArray.push(lo)
- byteArray.push(hi)
- }
-
- return byteArray
-}
-
-function base64ToBytes (str) {
- return base64.toByteArray(base64clean(str))
-}
-
-function blitBuffer (src, dst, offset, length) {
- for (var i = 0; i < length; ++i) {
- if ((i + offset >= dst.length) || (i >= src.length)) break
- dst[i + offset] = src[i]
- }
- return i
-}
-
-function isnan (val) {
- return val !== val // eslint-disable-line no-self-compare
-}
-
-/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(4)))
-
-/***/ }),
-/* 19 */
-/***/ (function(module, exports, __webpack_require__) {
-
-exports = module.exports = __webpack_require__(1)(undefined);
-// imports
-
-
-// module
-exports.push([module.i, ".cell[data-v-3ac4c361]{flex-direction:column}", ""]);
-
-// exports
-
-
-/***/ }),
-/* 20 */
-/***/ (function(module, exports, __webpack_require__) {
-
-exports = module.exports = __webpack_require__(1)(undefined);
-// imports
-
-
-// module
-exports.push([module.i, ".cell,.input,.output{display:flex;width:100%;margin-bottom:10px}.cell pre{margin:0;width:100%}", ""]);
-
-// exports
-
-
-/***/ }),
-/* 21 */
-/***/ (function(module, exports, __webpack_require__) {
-
-exports = module.exports = __webpack_require__(1)(undefined);
-// imports
-
-
-// module
-exports.push([module.i, ".prompt[data-v-4f6bf458]{padding:0 10px;min-width:7em;font-family:monospace}", ""]);
-
-// exports
-
-
-/***/ }),
-/* 22 */
-/***/ (function(module, exports, __webpack_require__) {
-
-exports = module.exports = __webpack_require__(1)(undefined);
-// imports
-
-
-// module
-exports.push([module.i, ".markdown .katex{display:block;text-align:center}.markdown .inline-katex .katex{display:inline;text-align:initial}", ""]);
-
-// exports
-
-
-/***/ }),
-/* 23 */
-/***/ (function(module, exports) {
-
-exports.read = function (buffer, offset, isLE, mLen, nBytes) {
- var e, m
- var eLen = nBytes * 8 - mLen - 1
- var eMax = (1 << eLen) - 1
- var eBias = eMax >> 1
- var nBits = -7
- var i = isLE ? (nBytes - 1) : 0
- var d = isLE ? -1 : 1
- var s = buffer[offset + i]
-
- i += d
-
- e = s & ((1 << (-nBits)) - 1)
- s >>= (-nBits)
- nBits += eLen
- for (; nBits > 0; e = e * 256 + buffer[offset + i], i += d, nBits -= 8) {}
-
- m = e & ((1 << (-nBits)) - 1)
- e >>= (-nBits)
- nBits += mLen
- for (; nBits > 0; m = m * 256 + buffer[offset + i], i += d, nBits -= 8) {}
-
- if (e === 0) {
- e = 1 - eBias
- } else if (e === eMax) {
- return m ? NaN : ((s ? -1 : 1) * Infinity)
- } else {
- m = m + Math.pow(2, mLen)
- e = e - eBias
- }
- return (s ? -1 : 1) * m * Math.pow(2, e - mLen)
-}
-
-exports.write = function (buffer, value, offset, isLE, mLen, nBytes) {
- var e, m, c
- var eLen = nBytes * 8 - mLen - 1
- var eMax = (1 << eLen) - 1
- var eBias = eMax >> 1
- var rt = (mLen === 23 ? Math.pow(2, -24) - Math.pow(2, -77) : 0)
- var i = isLE ? 0 : (nBytes - 1)
- var d = isLE ? 1 : -1
- var s = value < 0 || (value === 0 && 1 / value < 0) ? 1 : 0
-
- value = Math.abs(value)
-
- if (isNaN(value) || value === Infinity) {
- m = isNaN(value) ? 1 : 0
- e = eMax
- } else {
- e = Math.floor(Math.log(value) / Math.LN2)
- if (value * (c = Math.pow(2, -e)) < 1) {
- e--
- c *= 2
- }
- if (e + eBias >= 1) {
- value += rt / c
- } else {
- value += rt * Math.pow(2, 1 - eBias)
- }
- if (value * c >= 2) {
- e++
- c /= 2
- }
-
- if (e + eBias >= eMax) {
- m = 0
- e = eMax
- } else if (e + eBias >= 1) {
- m = (value * c - 1) * Math.pow(2, mLen)
- e = e + eBias
- } else {
- m = value * Math.pow(2, eBias - 1) * Math.pow(2, mLen)
- e = 0
- }
- }
-
- for (; mLen >= 8; buffer[offset + i] = m & 0xff, i += d, m /= 256, mLen -= 8) {}
-
- e = (e << mLen) | m
- eLen += mLen
- for (; eLen > 0; buffer[offset + i] = e & 0xff, i += d, e /= 256, eLen -= 8) {}
-
- buffer[offset + i - d] |= s * 128
-}
-
-
-/***/ }),
-/* 24 */
-/***/ (function(module, exports) {
-
-var toString = {}.toString;
-
-module.exports = Array.isArray || function (arr) {
- return toString.call(arr) == '[object Array]';
-};
-
-
-/***/ }),
-/* 25 */
-/***/ (function(module, exports, __webpack_require__) {
-
-/* WEBPACK VAR INJECTION */(function(global) {/**
- * marked - a markdown parser
- * Copyright (c) 2011-2014, Christopher Jeffrey. (MIT Licensed)
- * https://github.com/chjj/marked
- */
-
-;(function() {
-
-/**
- * Block-Level Grammar
- */
-
-var block = {
- newline: /^\n+/,
- code: /^( {4}[^\n]+\n*)+/,
- fences: noop,
- hr: /^( *[-*_]){3,} *(?:\n+|$)/,
- heading: /^ *(#{1,6}) *([^\n]+?) *#* *(?:\n+|$)/,
- nptable: noop,
- lheading: /^([^\n]+)\n *(=|-){2,} *(?:\n+|$)/,
- blockquote: /^( *>[^\n]+(\n(?!def)[^\n]+)*\n*)+/,
- list: /^( *)(bull) [\s\S]+?(?:hr|def|\n{2,}(?! )(?!\1bull )\n*|\s*$)/,
- html: /^ *(?:comment *(?:\n|\s*$)|closed *(?:\n{2,}|\s*$)|closing *(?:\n{2,}|\s*$))/,
- def: /^ *\[([^\]]+)\]: *<?([^\s>]+)>?(?: +["(]([^\n]+)[")])? *(?:\n+|$)/,
- table: noop,
- paragraph: /^((?:[^\n]+\n?(?!hr|heading|lheading|blockquote|tag|def))+)\n*/,
- text: /^[^\n]+/
-};
-
-block.bullet = /(?:[*+-]|\d+\.)/;
-block.item = /^( *)(bull) [^\n]*(?:\n(?!\1bull )[^\n]*)*/;
-block.item = replace(block.item, 'gm')
- (/bull/g, block.bullet)
- ();
-
-block.list = replace(block.list)
- (/bull/g, block.bullet)
- ('hr', '\\n+(?=\\1?(?:[-*_] *){3,}(?:\\n+|$))')
- ('def', '\\n+(?=' + block.def.source + ')')
- ();
-
-block.blockquote = replace(block.blockquote)
- ('def', block.def)
- ();
-
-block._tag = '(?!(?:'
- + 'a|em|strong|small|s|cite|q|dfn|abbr|data|time|code'
- + '|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo'
- + '|span|br|wbr|ins|del|img)\\b)\\w+(?!:/|[^\\w\\s@]*@)\\b';
-
-block.html = replace(block.html)
- ('comment', /<!--[\s\S]*?-->/)
- ('closed', /<(tag)[\s\S]+?<\/\1>/)
- ('closing', /<tag(?:"[^"]*"|'[^']*'|[^'">])*?>/)
- (/tag/g, block._tag)
- ();
-
-block.paragraph = replace(block.paragraph)
- ('hr', block.hr)
- ('heading', block.heading)
- ('lheading', block.lheading)
- ('blockquote', block.blockquote)
- ('tag', '<' + block._tag)
- ('def', block.def)
- ();
-
-/**
- * Normal Block Grammar
- */
-
-block.normal = merge({}, block);
-
-/**
- * GFM Block Grammar
- */
-
-block.gfm = merge({}, block.normal, {
- fences: /^ *(`{3,}|~{3,})[ \.]*(\S+)? *\n([\s\S]*?)\s*\1 *(?:\n+|$)/,
- paragraph: /^/,
- heading: /^ *(#{1,6}) +([^\n]+?) *#* *(?:\n+|$)/
-});
-
-block.gfm.paragraph = replace(block.paragraph)
- ('(?!', '(?!'
- + block.gfm.fences.source.replace('\\1', '\\2') + '|'
- + block.list.source.replace('\\1', '\\3') + '|')
- ();
-
-/**
- * GFM + Tables Block Grammar
- */
-
-block.tables = merge({}, block.gfm, {
- nptable: /^ *(\S.*\|.*)\n *([-:]+ *\|[-| :]*)\n((?:.*\|.*(?:\n|$))*)\n*/,
- table: /^ *\|(.+)\n *\|( *[-:]+[-| :]*)\n((?: *\|.*(?:\n|$))*)\n*/
-});
-
-/**
- * Block Lexer
- */
-
-function Lexer(options) {
- this.tokens = [];
- this.tokens.links = {};
- this.options = options || marked.defaults;
- this.rules = block.normal;
-
- if (this.options.gfm) {
- if (this.options.tables) {
- this.rules = block.tables;
- } else {
- this.rules = block.gfm;
- }
- }
-}
-
-/**
- * Expose Block Rules
- */
-
-Lexer.rules = block;
-
-/**
- * Static Lex Method
- */
-
-Lexer.lex = function(src, options) {
- var lexer = new Lexer(options);
- return lexer.lex(src);
-};
-
-/**
- * Preprocessing
- */
-
-Lexer.prototype.lex = function(src) {
- src = src
- .replace(/\r\n|\r/g, '\n')
- .replace(/\t/g, ' ')
- .replace(/\u00a0/g, ' ')
- .replace(/\u2424/g, '\n');
-
- return this.token(src, true);
-};
-
-/**
- * Lexing
- */
-
-Lexer.prototype.token = function(src, top, bq) {
- var src = src.replace(/^ +$/gm, '')
- , next
- , loose
- , cap
- , bull
- , b
- , item
- , space
- , i
- , l;
-
- while (src) {
- // newline
- if (cap = this.rules.newline.exec(src)) {
- src = src.substring(cap[0].length);
- if (cap[0].length > 1) {
- this.tokens.push({
- type: 'space'
- });
- }
- }
-
- // code
- if (cap = this.rules.code.exec(src)) {
- src = src.substring(cap[0].length);
- cap = cap[0].replace(/^ {4}/gm, '');
- this.tokens.push({
- type: 'code',
- text: !this.options.pedantic
- ? cap.replace(/\n+$/, '')
- : cap
- });
- continue;
- }
-
- // fences (gfm)
- if (cap = this.rules.fences.exec(src)) {
- src = src.substring(cap[0].length);
- this.tokens.push({
- type: 'code',
- lang: cap[2],
- text: cap[3] || ''
- });
- continue;
- }
-
- // heading
- if (cap = this.rules.heading.exec(src)) {
- src = src.substring(cap[0].length);
- this.tokens.push({
- type: 'heading',
- depth: cap[1].length,
- text: cap[2]
- });
- continue;
- }
-
- // table no leading pipe (gfm)
- if (top && (cap = this.rules.nptable.exec(src))) {
- src = src.substring(cap[0].length);
-
- item = {
- type: 'table',
- header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */),
- align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
- cells: cap[3].replace(/\n$/, '').split('\n')
- };
-
- for (i = 0; i < item.align.length; i++) {
- if (/^ *-+: *$/.test(item.align[i])) {
- item.align[i] = 'right';
- } else if (/^ *:-+: *$/.test(item.align[i])) {
- item.align[i] = 'center';
- } else if (/^ *:-+ *$/.test(item.align[i])) {
- item.align[i] = 'left';
- } else {
- item.align[i] = null;
- }
- }
-
- for (i = 0; i < item.cells.length; i++) {
- item.cells[i] = item.cells[i].split(/ *\| */);
- }
-
- this.tokens.push(item);
-
- continue;
- }
-
- // lheading
- if (cap = this.rules.lheading.exec(src)) {
- src = src.substring(cap[0].length);
- this.tokens.push({
- type: 'heading',
- depth: cap[2] === '=' ? 1 : 2,
- text: cap[1]
- });
- continue;
- }
-
- // hr
- if (cap = this.rules.hr.exec(src)) {
- src = src.substring(cap[0].length);
- this.tokens.push({
- type: 'hr'
- });
- continue;
- }
-
- // blockquote
- if (cap = this.rules.blockquote.exec(src)) {
- src = src.substring(cap[0].length);
-
- this.tokens.push({
- type: 'blockquote_start'
- });
-
- cap = cap[0].replace(/^ *> ?/gm, '');
-
- // Pass `top` to keep the current
- // "toplevel" state. This is exactly
- // how markdown.pl works.
- this.token(cap, top, true);
-
- this.tokens.push({
- type: 'blockquote_end'
- });
-
- continue;
- }
-
- // list
- if (cap = this.rules.list.exec(src)) {
- src = src.substring(cap[0].length);
- bull = cap[2];
-
- this.tokens.push({
- type: 'list_start',
- ordered: bull.length > 1
- });
-
- // Get each top-level item.
- cap = cap[0].match(this.rules.item);
-
- next = false;
- l = cap.length;
- i = 0;
-
- for (; i < l; i++) {
- item = cap[i];
-
- // Remove the list item's bullet
- // so it is seen as the next token.
- space = item.length;
- item = item.replace(/^ *([*+-]|\d+\.) +/, '');
-
- // Outdent whatever the
- // list item contains. Hacky.
- if (~item.indexOf('\n ')) {
- space -= item.length;
- item = !this.options.pedantic
- ? item.replace(new RegExp('^ {1,' + space + '}', 'gm'), '')
- : item.replace(/^ {1,4}/gm, '');
- }
-
- // Determine whether the next list item belongs here.
- // Backpedal if it does not belong in this list.
- if (this.options.smartLists && i !== l - 1) {
- b = block.bullet.exec(cap[i + 1])[0];
- if (bull !== b && !(bull.length > 1 && b.length > 1)) {
- src = cap.slice(i + 1).join('\n') + src;
- i = l - 1;
- }
- }
-
- // Determine whether item is loose or not.
- // Use: /(^|\n)(?! )[^\n]+\n\n(?!\s*$)/
- // for discount behavior.
- loose = next || /\n\n(?!\s*$)/.test(item);
- if (i !== l - 1) {
- next = item.charAt(item.length - 1) === '\n';
- if (!loose) loose = next;
- }
-
- this.tokens.push({
- type: loose
- ? 'loose_item_start'
- : 'list_item_start'
- });
-
- // Recurse.
- this.token(item, false, bq);
-
- this.tokens.push({
- type: 'list_item_end'
- });
- }
-
- this.tokens.push({
- type: 'list_end'
- });
-
- continue;
- }
-
- // html
- if (cap = this.rules.html.exec(src)) {
- src = src.substring(cap[0].length);
- this.tokens.push({
- type: this.options.sanitize
- ? 'paragraph'
- : 'html',
- pre: !this.options.sanitizer
- && (cap[1] === 'pre' || cap[1] === 'script' || cap[1] === 'style'),
- text: cap[0]
- });
- continue;
- }
-
- // def
- if ((!bq && top) && (cap = this.rules.def.exec(src))) {
- src = src.substring(cap[0].length);
- this.tokens.links[cap[1].toLowerCase()] = {
- href: cap[2],
- title: cap[3]
- };
- continue;
- }
-
- // table (gfm)
- if (top && (cap = this.rules.table.exec(src))) {
- src = src.substring(cap[0].length);
-
- item = {
- type: 'table',
- header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */),
- align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
- cells: cap[3].replace(/(?: *\| *)?\n$/, '').split('\n')
- };
-
- for (i = 0; i < item.align.length; i++) {
- if (/^ *-+: *$/.test(item.align[i])) {
- item.align[i] = 'right';
- } else if (/^ *:-+: *$/.test(item.align[i])) {
- item.align[i] = 'center';
- } else if (/^ *:-+ *$/.test(item.align[i])) {
- item.align[i] = 'left';
- } else {
- item.align[i] = null;
- }
- }
-
- for (i = 0; i < item.cells.length; i++) {
- item.cells[i] = item.cells[i]
- .replace(/^ *\| *| *\| *$/g, '')
- .split(/ *\| */);
- }
-
- this.tokens.push(item);
-
- continue;
- }
-
- // top-level paragraph
- if (top && (cap = this.rules.paragraph.exec(src))) {
- src = src.substring(cap[0].length);
- this.tokens.push({
- type: 'paragraph',
- text: cap[1].charAt(cap[1].length - 1) === '\n'
- ? cap[1].slice(0, -1)
- : cap[1]
- });
- continue;
- }
-
- // text
- if (cap = this.rules.text.exec(src)) {
- // Top-level should never reach here.
- src = src.substring(cap[0].length);
- this.tokens.push({
- type: 'text',
- text: cap[0]
- });
- continue;
- }
-
- if (src) {
- throw new
- Error('Infinite loop on byte: ' + src.charCodeAt(0));
- }
- }
-
- return this.tokens;
-};
-
-/**
- * Inline-Level Grammar
- */
-
-var inline = {
- escape: /^\\([\\`*{}\[\]()#+\-.!_>])/,
- autolink: /^<([^ >]+(@|:\/)[^ >]+)>/,
- url: noop,
- tag: /^<!--[\s\S]*?-->|^<\/?\w+(?:"[^"]*"|'[^']*'|[^'">])*?>/,
- link: /^!?\[(inside)\]\(href\)/,
- reflink: /^!?\[(inside)\]\s*\[([^\]]*)\]/,
- nolink: /^!?\[((?:\[[^\]]*\]|[^\[\]])*)\]/,
- strong: /^__([\s\S]+?)__(?!_)|^\*\*([\s\S]+?)\*\*(?!\*)/,
- em: /^\b_((?:[^_]|__)+?)_\b|^\*((?:\*\*|[\s\S])+?)\*(?!\*)/,
- code: /^(`+)\s*([\s\S]*?[^`])\s*\1(?!`)/,
- br: /^ {2,}\n(?!\s*$)/,
- del: noop,
- text: /^[\s\S]+?(?=[\\<!\[_*`]| {2,}\n|$)/
-};
-
-inline._inside = /(?:\[[^\]]*\]|[^\[\]]|\](?=[^\[]*\]))*/;
-inline._href = /\s*<?([\s\S]*?)>?(?:\s+['"]([\s\S]*?)['"])?\s*/;
-
-inline.link = replace(inline.link)
- ('inside', inline._inside)
- ('href', inline._href)
- ();
-
-inline.reflink = replace(inline.reflink)
- ('inside', inline._inside)
- ();
-
-/**
- * Normal Inline Grammar
- */
-
-inline.normal = merge({}, inline);
-
-/**
- * Pedantic Inline Grammar
- */
-
-inline.pedantic = merge({}, inline.normal, {
- strong: /^__(?=\S)([\s\S]*?\S)__(?!_)|^\*\*(?=\S)([\s\S]*?\S)\*\*(?!\*)/,
- em: /^_(?=\S)([\s\S]*?\S)_(?!_)|^\*(?=\S)([\s\S]*?\S)\*(?!\*)/
-});
-
-/**
- * GFM Inline Grammar
- */
-
-inline.gfm = merge({}, inline.normal, {
- escape: replace(inline.escape)('])', '~|])')(),
- url: /^(https?:\/\/[^\s<]+[^<.,:;"')\]\s])/,
- del: /^~~(?=\S)([\s\S]*?\S)~~/,
- text: replace(inline.text)
- (']|', '~]|')
- ('|', '|https?://|')
- ()
-});
-
-/**
- * GFM + Line Breaks Inline Grammar
- */
-
-inline.breaks = merge({}, inline.gfm, {
- br: replace(inline.br)('{2,}', '*')(),
- text: replace(inline.gfm.text)('{2,}', '*')()
-});
-
-/**
- * Inline Lexer & Compiler
- */
-
-function InlineLexer(links, options) {
- this.options = options || marked.defaults;
- this.links = links;
- this.rules = inline.normal;
- this.renderer = this.options.renderer || new Renderer;
- this.renderer.options = this.options;
-
- if (!this.links) {
- throw new
- Error('Tokens array requires a `links` property.');
- }
-
- if (this.options.gfm) {
- if (this.options.breaks) {
- this.rules = inline.breaks;
- } else {
- this.rules = inline.gfm;
- }
- } else if (this.options.pedantic) {
- this.rules = inline.pedantic;
- }
-}
-
-/**
- * Expose Inline Rules
- */
-
-InlineLexer.rules = inline;
-
-/**
- * Static Lexing/Compiling Method
- */
-
-InlineLexer.output = function(src, links, options) {
- var inline = new InlineLexer(links, options);
- return inline.output(src);
-};
-
-/**
- * Lexing/Compiling
- */
-
-InlineLexer.prototype.output = function(src) {
- var out = ''
- , link
- , text
- , href
- , cap;
-
- while (src) {
- // escape
- if (cap = this.rules.escape.exec(src)) {
- src = src.substring(cap[0].length);
- out += cap[1];
- continue;
- }
-
- // autolink
- if (cap = this.rules.autolink.exec(src)) {
- src = src.substring(cap[0].length);
- if (cap[2] === '@') {
- text = cap[1].charAt(6) === ':'
- ? this.mangle(cap[1].substring(7))
- : this.mangle(cap[1]);
- href = this.mangle('mailto:') + text;
- } else {
- text = escape(cap[1]);
- href = text;
- }
- out += this.renderer.link(href, null, text);
- continue;
- }
-
- // url (gfm)
- if (!this.inLink && (cap = this.rules.url.exec(src))) {
- src = src.substring(cap[0].length);
- text = escape(cap[1]);
- href = text;
- out += this.renderer.link(href, null, text);
- continue;
- }
-
- // tag
- if (cap = this.rules.tag.exec(src)) {
- if (!this.inLink && /^<a /i.test(cap[0])) {
- this.inLink = true;
- } else if (this.inLink && /^<\/a>/i.test(cap[0])) {
- this.inLink = false;
- }
- src = src.substring(cap[0].length);
- out += this.options.sanitize
- ? this.options.sanitizer
- ? this.options.sanitizer(cap[0])
- : escape(cap[0])
- : cap[0]
- continue;
- }
-
- // link
- if (cap = this.rules.link.exec(src)) {
- src = src.substring(cap[0].length);
- this.inLink = true;
- out += this.outputLink(cap, {
- href: cap[2],
- title: cap[3]
- });
- this.inLink = false;
- continue;
- }
-
- // reflink, nolink
- if ((cap = this.rules.reflink.exec(src))
- || (cap = this.rules.nolink.exec(src))) {
- src = src.substring(cap[0].length);
- link = (cap[2] || cap[1]).replace(/\s+/g, ' ');
- link = this.links[link.toLowerCase()];
- if (!link || !link.href) {
- out += cap[0].charAt(0);
- src = cap[0].substring(1) + src;
- continue;
- }
- this.inLink = true;
- out += this.outputLink(cap, link);
- this.inLink = false;
- continue;
- }
-
- // strong
- if (cap = this.rules.strong.exec(src)) {
- src = src.substring(cap[0].length);
- out += this.renderer.strong(this.output(cap[2] || cap[1]));
- continue;
- }
-
- // em
- if (cap = this.rules.em.exec(src)) {
- src = src.substring(cap[0].length);
- out += this.renderer.em(this.output(cap[2] || cap[1]));
- continue;
- }
-
- // code
- if (cap = this.rules.code.exec(src)) {
- src = src.substring(cap[0].length);
- out += this.renderer.codespan(escape(cap[2], true));
- continue;
- }
-
- // br
- if (cap = this.rules.br.exec(src)) {
- src = src.substring(cap[0].length);
- out += this.renderer.br();
- continue;
- }
-
- // del (gfm)
- if (cap = this.rules.del.exec(src)) {
- src = src.substring(cap[0].length);
- out += this.renderer.del(this.output(cap[1]));
- continue;
- }
-
- // text
- if (cap = this.rules.text.exec(src)) {
- src = src.substring(cap[0].length);
- out += this.renderer.text(escape(this.smartypants(cap[0])));
- continue;
- }
-
- if (src) {
- throw new
- Error('Infinite loop on byte: ' + src.charCodeAt(0));
- }
- }
-
- return out;
-};
-
-/**
- * Compile Link
- */
-
-InlineLexer.prototype.outputLink = function(cap, link) {
- var href = escape(link.href)
- , title = link.title ? escape(link.title) : null;
-
- return cap[0].charAt(0) !== '!'
- ? this.renderer.link(href, title, this.output(cap[1]))
- : this.renderer.image(href, title, escape(cap[1]));
-};
-
-/**
- * Smartypants Transformations
- */
-
-InlineLexer.prototype.smartypants = function(text) {
- if (!this.options.smartypants) return text;
- return text
- // em-dashes
- .replace(/---/g, '\u2014')
- // en-dashes
- .replace(/--/g, '\u2013')
- // opening singles
- .replace(/(^|[-\u2014/(\[{"\s])'/g, '$1\u2018')
- // closing singles & apostrophes
- .replace(/'/g, '\u2019')
- // opening doubles
- .replace(/(^|[-\u2014/(\[{\u2018\s])"/g, '$1\u201c')
- // closing doubles
- .replace(/"/g, '\u201d')
- // ellipses
- .replace(/\.{3}/g, '\u2026');
-};
-
-/**
- * Mangle Links
- */
-
-InlineLexer.prototype.mangle = function(text) {
- if (!this.options.mangle) return text;
- var out = ''
- , l = text.length
- , i = 0
- , ch;
-
- for (; i < l; i++) {
- ch = text.charCodeAt(i);
- if (Math.random() > 0.5) {
- ch = 'x' + ch.toString(16);
- }
- out += '&#' + ch + ';';
- }
-
- return out;
-};
-
-/**
- * Renderer
- */
-
-function Renderer(options) {
- this.options = options || {};
-}
-
-Renderer.prototype.code = function(code, lang, escaped) {
- if (this.options.highlight) {
- var out = this.options.highlight(code, lang);
- if (out != null && out !== code) {
- escaped = true;
- code = out;
- }
- }
-
- if (!lang) {
- return '<pre><code>'
- + (escaped ? code : escape(code, true))
- + '\n</code></pre>';
- }
-
- return '<pre><code class="'
- + this.options.langPrefix
- + escape(lang, true)
- + '">'
- + (escaped ? code : escape(code, true))
- + '\n</code></pre>\n';
-};
-
-Renderer.prototype.blockquote = function(quote) {
- return '<blockquote>\n' + quote + '</blockquote>\n';
-};
-
-Renderer.prototype.html = function(html) {
- return html;
-};
-
-Renderer.prototype.heading = function(text, level, raw) {
- return '<h'
- + level
- + ' id="'
- + this.options.headerPrefix
- + raw.toLowerCase().replace(/[^\w]+/g, '-')
- + '">'
- + text
- + '</h'
- + level
- + '>\n';
-};
-
-Renderer.prototype.hr = function() {
- return this.options.xhtml ? '<hr/>\n' : '<hr>\n';
-};
-
-Renderer.prototype.list = function(body, ordered) {
- var type = ordered ? 'ol' : 'ul';
- return '<' + type + '>\n' + body + '</' + type + '>\n';
-};
-
-Renderer.prototype.listitem = function(text) {
- return '<li>' + text + '</li>\n';
-};
-
-Renderer.prototype.paragraph = function(text) {
- return '<p>' + text + '</p>\n';
-};
-
-Renderer.prototype.table = function(header, body) {
- return '<table>\n'
- + '<thead>\n'
- + header
- + '</thead>\n'
- + '<tbody>\n'
- + body
- + '</tbody>\n'
- + '</table>\n';
-};
-
-Renderer.prototype.tablerow = function(content) {
- return '<tr>\n' + content + '</tr>\n';
-};
-
-Renderer.prototype.tablecell = function(content, flags) {
- var type = flags.header ? 'th' : 'td';
- var tag = flags.align
- ? '<' + type + ' style="text-align:' + flags.align + '">'
- : '<' + type + '>';
- return tag + content + '</' + type + '>\n';
-};
-
-// span level renderer
-Renderer.prototype.strong = function(text) {
- return '<strong>' + text + '</strong>';
-};
-
-Renderer.prototype.em = function(text) {
- return '<em>' + text + '</em>';
-};
-
-Renderer.prototype.codespan = function(text) {
- return '<code>' + text + '</code>';
-};
-
-Renderer.prototype.br = function() {
- return this.options.xhtml ? '<br/>' : '<br>';
-};
-
-Renderer.prototype.del = function(text) {
- return '<del>' + text + '</del>';
-};
-
-Renderer.prototype.link = function(href, title, text) {
- if (this.options.sanitize) {
- try {
- var prot = decodeURIComponent(unescape(href))
- .replace(/[^\w:]/g, '')
- .toLowerCase();
- } catch (e) {
- return '';
- }
- if (prot.indexOf('javascript:') === 0 || prot.indexOf('vbscript:') === 0) {
- return '';
- }
- }
- var out = '<a href="' + href + '"';
- if (title) {
- out += ' title="' + title + '"';
- }
- out += '>' + text + '</a>';
- return out;
-};
-
-Renderer.prototype.image = function(href, title, text) {
- var out = '<img src="' + href + '" alt="' + text + '"';
- if (title) {
- out += ' title="' + title + '"';
- }
- out += this.options.xhtml ? '/>' : '>';
- return out;
-};
-
-Renderer.prototype.text = function(text) {
- return text;
-};
-
-/**
- * Parsing & Compiling
- */
-
-function Parser(options) {
- this.tokens = [];
- this.token = null;
- this.options = options || marked.defaults;
- this.options.renderer = this.options.renderer || new Renderer;
- this.renderer = this.options.renderer;
- this.renderer.options = this.options;
-}
-
-/**
- * Static Parse Method
- */
-
-Parser.parse = function(src, options, renderer) {
- var parser = new Parser(options, renderer);
- return parser.parse(src);
-};
-
-/**
- * Parse Loop
- */
-
-Parser.prototype.parse = function(src) {
- this.inline = new InlineLexer(src.links, this.options, this.renderer);
- this.tokens = src.reverse();
-
- var out = '';
- while (this.next()) {
- out += this.tok();
- }
-
- return out;
-};
-
-/**
- * Next Token
- */
-
-Parser.prototype.next = function() {
- return this.token = this.tokens.pop();
-};
-
-/**
- * Preview Next Token
- */
-
-Parser.prototype.peek = function() {
- return this.tokens[this.tokens.length - 1] || 0;
-};
-
-/**
- * Parse Text Tokens
- */
-
-Parser.prototype.parseText = function() {
- var body = this.token.text;
-
- while (this.peek().type === 'text') {
- body += '\n' + this.next().text;
- }
-
- return this.inline.output(body);
-};
-
-/**
- * Parse Current Token
- */
-
-Parser.prototype.tok = function() {
- switch (this.token.type) {
- case 'space': {
- return '';
- }
- case 'hr': {
- return this.renderer.hr();
- }
- case 'heading': {
- return this.renderer.heading(
- this.inline.output(this.token.text),
- this.token.depth,
- this.token.text);
- }
- case 'code': {
- return this.renderer.code(this.token.text,
- this.token.lang,
- this.token.escaped);
- }
- case 'table': {
- var header = ''
- , body = ''
- , i
- , row
- , cell
- , flags
- , j;
-
- // header
- cell = '';
- for (i = 0; i < this.token.header.length; i++) {
- flags = { header: true, align: this.token.align[i] };
- cell += this.renderer.tablecell(
- this.inline.output(this.token.header[i]),
- { header: true, align: this.token.align[i] }
- );
- }
- header += this.renderer.tablerow(cell);
-
- for (i = 0; i < this.token.cells.length; i++) {
- row = this.token.cells[i];
-
- cell = '';
- for (j = 0; j < row.length; j++) {
- cell += this.renderer.tablecell(
- this.inline.output(row[j]),
- { header: false, align: this.token.align[j] }
- );
- }
-
- body += this.renderer.tablerow(cell);
- }
- return this.renderer.table(header, body);
- }
- case 'blockquote_start': {
- var body = '';
-
- while (this.next().type !== 'blockquote_end') {
- body += this.tok();
- }
-
- return this.renderer.blockquote(body);
- }
- case 'list_start': {
- var body = ''
- , ordered = this.token.ordered;
-
- while (this.next().type !== 'list_end') {
- body += this.tok();
- }
-
- return this.renderer.list(body, ordered);
- }
- case 'list_item_start': {
- var body = '';
-
- while (this.next().type !== 'list_item_end') {
- body += this.token.type === 'text'
- ? this.parseText()
- : this.tok();
- }
-
- return this.renderer.listitem(body);
- }
- case 'loose_item_start': {
- var body = '';
-
- while (this.next().type !== 'list_item_end') {
- body += this.tok();
- }
-
- return this.renderer.listitem(body);
- }
- case 'html': {
- var html = !this.token.pre && !this.options.pedantic
- ? this.inline.output(this.token.text)
- : this.token.text;
- return this.renderer.html(html);
- }
- case 'paragraph': {
- return this.renderer.paragraph(this.inline.output(this.token.text));
- }
- case 'text': {
- return this.renderer.paragraph(this.parseText());
- }
- }
-};
-
-/**
- * Helpers
- */
-
-function escape(html, encode) {
- return html
- .replace(!encode ? /&(?!#?\w+;)/g : /&/g, '&amp;')
- .replace(/</g, '&lt;')
- .replace(/>/g, '&gt;')
- .replace(/"/g, '&quot;')
- .replace(/'/g, '&#39;');
-}
-
-function unescape(html) {
- // explicitly match decimal, hex, and named HTML entities
- return html.replace(/&(#(?:\d+)|(?:#x[0-9A-Fa-f]+)|(?:\w+));?/g, function(_, n) {
- n = n.toLowerCase();
- if (n === 'colon') return ':';
- if (n.charAt(0) === '#') {
- return n.charAt(1) === 'x'
- ? String.fromCharCode(parseInt(n.substring(2), 16))
- : String.fromCharCode(+n.substring(1));
- }
- return '';
- });
-}
-
-function replace(regex, opt) {
- regex = regex.source;
- opt = opt || '';
- return function self(name, val) {
- if (!name) return new RegExp(regex, opt);
- val = val.source || val;
- val = val.replace(/(^|[^\[])\^/g, '$1');
- regex = regex.replace(name, val);
- return self;
- };
-}
-
-function noop() {}
-noop.exec = noop;
-
-function merge(obj) {
- var i = 1
- , target
- , key;
-
- for (; i < arguments.length; i++) {
- target = arguments[i];
- for (key in target) {
- if (Object.prototype.hasOwnProperty.call(target, key)) {
- obj[key] = target[key];
- }
- }
- }
-
- return obj;
-}
-
-
-/**
- * Marked
- */
-
-function marked(src, opt, callback) {
- if (callback || typeof opt === 'function') {
- if (!callback) {
- callback = opt;
- opt = null;
- }
-
- opt = merge({}, marked.defaults, opt || {});
-
- var highlight = opt.highlight
- , tokens
- , pending
- , i = 0;
-
- try {
- tokens = Lexer.lex(src, opt)
- } catch (e) {
- return callback(e);
- }
-
- pending = tokens.length;
-
- var done = function(err) {
- if (err) {
- opt.highlight = highlight;
- return callback(err);
- }
-
- var out;
-
- try {
- out = Parser.parse(tokens, opt);
- } catch (e) {
- err = e;
- }
-
- opt.highlight = highlight;
-
- return err
- ? callback(err)
- : callback(null, out);
- };
-
- if (!highlight || highlight.length < 3) {
- return done();
- }
-
- delete opt.highlight;
-
- if (!pending) return done();
-
- for (; i < tokens.length; i++) {
- (function(token) {
- if (token.type !== 'code') {
- return --pending || done();
- }
- return highlight(token.text, token.lang, function(err, code) {
- if (err) return done(err);
- if (code == null || code === token.text) {
- return --pending || done();
- }
- token.text = code;
- token.escaped = true;
- --pending || done();
- });
- })(tokens[i]);
- }
-
- return;
- }
- try {
- if (opt) opt = merge({}, marked.defaults, opt);
- return Parser.parse(Lexer.lex(src, opt), opt);
- } catch (e) {
- e.message += '\nPlease report this to https://github.com/chjj/marked.';
- if ((opt || marked.defaults).silent) {
- return '<p>An error occured:</p><pre>'
- + escape(e.message + '', true)
- + '</pre>';
- }
- throw e;
- }
-}
-
-/**
- * Options
- */
-
-marked.options =
-marked.setOptions = function(opt) {
- merge(marked.defaults, opt);
- return marked;
-};
-
-marked.defaults = {
- gfm: true,
- tables: true,
- breaks: false,
- pedantic: false,
- sanitize: false,
- sanitizer: null,
- mangle: true,
- smartLists: false,
- silent: false,
- highlight: null,
- langPrefix: 'lang-',
- smartypants: false,
- headerPrefix: '',
- renderer: new Renderer,
- xhtml: false
-};
-
-/**
- * Expose
- */
-
-marked.Parser = Parser;
-marked.parser = Parser.parse;
-
-marked.Renderer = Renderer;
-
-marked.Lexer = Lexer;
-marked.lexer = Lexer.lex;
-
-marked.InlineLexer = InlineLexer;
-marked.inlineLexer = InlineLexer.output;
-
-marked.parse = marked;
-
-if (true) {
- module.exports = marked;
-} else if (typeof define === 'function' && define.amd) {
- define(function() { return marked; });
-} else {
- this.marked = marked;
-}
-
-}).call(function() {
- return this || (typeof window !== 'undefined' ? window : global);
-}());
-
-/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(4)))
-
-/***/ }),
-/* 26 */
-/***/ (function(module, exports) {
-
-Prism.languages.python= {
- 'triple-quoted-string': {
- pattern: /"""[\s\S]+?"""|'''[\s\S]+?'''/,
- alias: 'string'
- },
- 'comment': {
- pattern: /(^|[^\\])#.*/,
- lookbehind: true
- },
- 'string': {
- pattern: /("|')(?:\\\\|\\?[^\\\r\n])*?\1/,
- greedy: true
- },
- 'function' : {
- pattern: /((?:^|\s)def[ \t]+)[a-zA-Z_][a-zA-Z0-9_]*(?=\()/g,
- lookbehind: true
- },
- 'class-name': {
- pattern: /(\bclass\s+)[a-z0-9_]+/i,
- lookbehind: true
- },
- 'keyword' : /\b(?:as|assert|async|await|break|class|continue|def|del|elif|else|except|exec|finally|for|from|global|if|import|in|is|lambda|pass|print|raise|return|try|while|with|yield)\b/,
- 'boolean' : /\b(?:True|False)\b/,
- 'number' : /\b-?(?:0[bo])?(?:(?:\d|0x[\da-f])[\da-f]*\.?\d*|\.\d+)(?:e[+-]?\d+)?j?\b/i,
- 'operator' : /[-+%=]=?|!=|\*\*?=?|\/\/?=?|<[<=>]?|>[=>]?|[&|^~]|\b(?:or|and|not)\b/,
- 'punctuation' : /[{}[\];(),.:]/
-};
-
-
-/***/ }),
-/* 27 */
-/***/ (function(module, exports, __webpack_require__) {
-
-/* WEBPACK VAR INJECTION */(function(global) {(function(){
-
-if (
- (typeof self === 'undefined' || !self.Prism) &&
- (typeof global === 'undefined' || !global.Prism)
-) {
- return;
-}
-
-var options = {};
-Prism.plugins.customClass = {
- map: function map(cm) {
- options.classMap = cm;
- },
- prefix: function prefix(string) {
- options.prefixString = string;
- }
-}
-
-Prism.hooks.add('wrap', function (env) {
- if (!options.classMap && !options.prefixString) {
- return;
- }
- env.classes = env.classes.map(function(c) {
- return (options.prefixString || '') + (options.classMap[c] || c);
- });
-});
-
-})();
-
-/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(4)))
-
-/***/ }),
-/* 28 */
-/***/ (function(module, exports, __webpack_require__) {
-
-/* WEBPACK VAR INJECTION */(function(global) {
-/* **********************************************
- Begin prism-core.js
-********************************************** */
-
-var _self = (typeof window !== 'undefined')
- ? window // if in browser
- : (
- (typeof WorkerGlobalScope !== 'undefined' && self instanceof WorkerGlobalScope)
- ? self // if in worker
- : {} // if in node js
- );
-
-/**
- * Prism: Lightweight, robust, elegant syntax highlighting
- * MIT license http://www.opensource.org/licenses/mit-license.php/
- * @author Lea Verou http://lea.verou.me
- */
-
-var Prism = (function(){
-
-// Private helper vars
-var lang = /\blang(?:uage)?-(\w+)\b/i;
-var uniqueId = 0;
-
-var _ = _self.Prism = {
- util: {
- encode: function (tokens) {
- if (tokens instanceof Token) {
- return new Token(tokens.type, _.util.encode(tokens.content), tokens.alias);
- } else if (_.util.type(tokens) === 'Array') {
- return tokens.map(_.util.encode);
- } else {
- return tokens.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/\u00a0/g, ' ');
- }
- },
-
- type: function (o) {
- return Object.prototype.toString.call(o).match(/\[object (\w+)\]/)[1];
- },
-
- objId: function (obj) {
- if (!obj['__id']) {
- Object.defineProperty(obj, '__id', { value: ++uniqueId });
- }
- return obj['__id'];
- },
-
- // Deep clone a language definition (e.g. to extend it)
- clone: function (o) {
- var type = _.util.type(o);
-
- switch (type) {
- case 'Object':
- var clone = {};
-
- for (var key in o) {
- if (o.hasOwnProperty(key)) {
- clone[key] = _.util.clone(o[key]);
- }
- }
-
- return clone;
-
- case 'Array':
- // Check for existence for IE8
- return o.map && o.map(function(v) { return _.util.clone(v); });
- }
-
- return o;
- }
- },
-
- languages: {
- extend: function (id, redef) {
- var lang = _.util.clone(_.languages[id]);
-
- for (var key in redef) {
- lang[key] = redef[key];
- }
-
- return lang;
- },
-
- /**
- * Insert a token before another token in a language literal
- * As this needs to recreate the object (we cannot actually insert before keys in object literals),
- * we cannot just provide an object, we need anobject and a key.
- * @param inside The key (or language id) of the parent
- * @param before The key to insert before. If not provided, the function appends instead.
- * @param insert Object with the key/value pairs to insert
- * @param root The object that contains `inside`. If equal to Prism.languages, it can be omitted.
- */
- insertBefore: function (inside, before, insert, root) {
- root = root || _.languages;
- var grammar = root[inside];
-
- if (arguments.length == 2) {
- insert = arguments[1];
-
- for (var newToken in insert) {
- if (insert.hasOwnProperty(newToken)) {
- grammar[newToken] = insert[newToken];
- }
- }
-
- return grammar;
- }
-
- var ret = {};
-
- for (var token in grammar) {
-
- if (grammar.hasOwnProperty(token)) {
-
- if (token == before) {
-
- for (var newToken in insert) {
-
- if (insert.hasOwnProperty(newToken)) {
- ret[newToken] = insert[newToken];
- }
- }
- }
-
- ret[token] = grammar[token];
- }
- }
-
- // Update references in other language definitions
- _.languages.DFS(_.languages, function(key, value) {
- if (value === root[inside] && key != inside) {
- this[key] = ret;
- }
- });
-
- return root[inside] = ret;
- },
-
- // Traverse a language definition with Depth First Search
- DFS: function(o, callback, type, visited) {
- visited = visited || {};
- for (var i in o) {
- if (o.hasOwnProperty(i)) {
- callback.call(o, i, o[i], type || i);
-
- if (_.util.type(o[i]) === 'Object' && !visited[_.util.objId(o[i])]) {
- visited[_.util.objId(o[i])] = true;
- _.languages.DFS(o[i], callback, null, visited);
- }
- else if (_.util.type(o[i]) === 'Array' && !visited[_.util.objId(o[i])]) {
- visited[_.util.objId(o[i])] = true;
- _.languages.DFS(o[i], callback, i, visited);
- }
- }
- }
- }
- },
- plugins: {},
-
- highlightAll: function(async, callback) {
- var env = {
- callback: callback,
- selector: 'code[class*="language-"], [class*="language-"] code, code[class*="lang-"], [class*="lang-"] code'
- };
-
- _.hooks.run("before-highlightall", env);
-
- var elements = env.elements || document.querySelectorAll(env.selector);
-
- for (var i=0, element; element = elements[i++];) {
- _.highlightElement(element, async === true, env.callback);
- }
- },
-
- highlightElement: function(element, async, callback) {
- // Find language
- var language, grammar, parent = element;
-
- while (parent && !lang.test(parent.className)) {
- parent = parent.parentNode;
- }
-
- if (parent) {
- language = (parent.className.match(lang) || [,''])[1].toLowerCase();
- grammar = _.languages[language];
- }
-
- // Set language on the element, if not present
- element.className = element.className.replace(lang, '').replace(/\s+/g, ' ') + ' language-' + language;
-
- // Set language on the parent, for styling
- parent = element.parentNode;
-
- if (/pre/i.test(parent.nodeName)) {
- parent.className = parent.className.replace(lang, '').replace(/\s+/g, ' ') + ' language-' + language;
- }
-
- var code = element.textContent;
-
- var env = {
- element: element,
- language: language,
- grammar: grammar,
- code: code
- };
-
- _.hooks.run('before-sanity-check', env);
-
- if (!env.code || !env.grammar) {
- if (env.code) {
- env.element.textContent = env.code;
- }
- _.hooks.run('complete', env);
- return;
- }
-
- _.hooks.run('before-highlight', env);
-
- if (async && _self.Worker) {
- var worker = new Worker(_.filename);
-
- worker.onmessage = function(evt) {
- env.highlightedCode = evt.data;
-
- _.hooks.run('before-insert', env);
-
- env.element.innerHTML = env.highlightedCode;
-
- callback && callback.call(env.element);
- _.hooks.run('after-highlight', env);
- _.hooks.run('complete', env);
- };
-
- worker.postMessage(JSON.stringify({
- language: env.language,
- code: env.code,
- immediateClose: true
- }));
- }
- else {
- env.highlightedCode = _.highlight(env.code, env.grammar, env.language);
-
- _.hooks.run('before-insert', env);
-
- env.element.innerHTML = env.highlightedCode;
-
- callback && callback.call(element);
-
- _.hooks.run('after-highlight', env);
- _.hooks.run('complete', env);
- }
- },
-
- highlight: function (text, grammar, language) {
- var tokens = _.tokenize(text, grammar);
- return Token.stringify(_.util.encode(tokens), language);
- },
-
- tokenize: function(text, grammar, language) {
- var Token = _.Token;
-
- var strarr = [text];
-
- var rest = grammar.rest;
-
- if (rest) {
- for (var token in rest) {
- grammar[token] = rest[token];
- }
-
- delete grammar.rest;
- }
-
- tokenloop: for (var token in grammar) {
- if(!grammar.hasOwnProperty(token) || !grammar[token]) {
- continue;
- }
-
- var patterns = grammar[token];
- patterns = (_.util.type(patterns) === "Array") ? patterns : [patterns];
-
- for (var j = 0; j < patterns.length; ++j) {
- var pattern = patterns[j],
- inside = pattern.inside,
- lookbehind = !!pattern.lookbehind,
- greedy = !!pattern.greedy,
- lookbehindLength = 0,
- alias = pattern.alias;
-
- if (greedy && !pattern.pattern.global) {
- // Without the global flag, lastIndex won't work
- var flags = pattern.pattern.toString().match(/[imuy]*$/)[0];
- pattern.pattern = RegExp(pattern.pattern.source, flags + "g");
- }
-
- pattern = pattern.pattern || pattern;
-
- // Don’t cache length as it changes during the loop
- for (var i=0, pos = 0; i<strarr.length; pos += strarr[i].length, ++i) {
-
- var str = strarr[i];
-
- if (strarr.length > text.length) {
- // Something went terribly wrong, ABORT, ABORT!
- break tokenloop;
- }
-
- if (str instanceof Token) {
- continue;
- }
-
- pattern.lastIndex = 0;
-
- var match = pattern.exec(str),
- delNum = 1;
-
- // Greedy patterns can override/remove up to two previously matched tokens
- if (!match && greedy && i != strarr.length - 1) {
- pattern.lastIndex = pos;
- match = pattern.exec(text);
- if (!match) {
- break;
- }
-
- var from = match.index + (lookbehind ? match[1].length : 0),
- to = match.index + match[0].length,
- k = i,
- p = pos;
-
- for (var len = strarr.length; k < len && p < to; ++k) {
- p += strarr[k].length;
- // Move the index i to the element in strarr that is closest to from
- if (from >= p) {
- ++i;
- pos = p;
- }
- }
-
- /*
- * If strarr[i] is a Token, then the match starts inside another Token, which is invalid
- * If strarr[k - 1] is greedy we are in conflict with another greedy pattern
- */
- if (strarr[i] instanceof Token || strarr[k - 1].greedy) {
- continue;
- }
-
- // Number of tokens to delete and replace with the new match
- delNum = k - i;
- str = text.slice(pos, p);
- match.index -= pos;
- }
-
- if (!match) {
- continue;
- }
-
- if(lookbehind) {
- lookbehindLength = match[1].length;
- }
-
- var from = match.index + lookbehindLength,
- match = match[0].slice(lookbehindLength),
- to = from + match.length,
- before = str.slice(0, from),
- after = str.slice(to);
-
- var args = [i, delNum];
-
- if (before) {
- args.push(before);
- }
-
- var wrapped = new Token(token, inside? _.tokenize(match, inside) : match, alias, match, greedy);
-
- args.push(wrapped);
-
- if (after) {
- args.push(after);
- }
-
- Array.prototype.splice.apply(strarr, args);
- }
- }
- }
-
- return strarr;
- },
-
- hooks: {
- all: {},
-
- add: function (name, callback) {
- var hooks = _.hooks.all;
-
- hooks[name] = hooks[name] || [];
-
- hooks[name].push(callback);
- },
-
- run: function (name, env) {
- var callbacks = _.hooks.all[name];
-
- if (!callbacks || !callbacks.length) {
- return;
- }
-
- for (var i=0, callback; callback = callbacks[i++];) {
- callback(env);
- }
- }
- }
-};
-
-var Token = _.Token = function(type, content, alias, matchedStr, greedy) {
- this.type = type;
- this.content = content;
- this.alias = alias;
- // Copy of the full string this token was created from
- this.length = (matchedStr || "").length|0;
- this.greedy = !!greedy;
-};
-
-Token.stringify = function(o, language, parent) {
- if (typeof o == 'string') {
- return o;
- }
-
- if (_.util.type(o) === 'Array') {
- return o.map(function(element) {
- return Token.stringify(element, language, o);
- }).join('');
- }
-
- var env = {
- type: o.type,
- content: Token.stringify(o.content, language, parent),
- tag: 'span',
- classes: ['token', o.type],
- attributes: {},
- language: language,
- parent: parent
- };
-
- if (env.type == 'comment') {
- env.attributes['spellcheck'] = 'true';
- }
-
- if (o.alias) {
- var aliases = _.util.type(o.alias) === 'Array' ? o.alias : [o.alias];
- Array.prototype.push.apply(env.classes, aliases);
- }
-
- _.hooks.run('wrap', env);
-
- var attributes = Object.keys(env.attributes).map(function(name) {
- return name + '="' + (env.attributes[name] || '').replace(/"/g, '&quot;') + '"';
- }).join(' ');
-
- return '<' + env.tag + ' class="' + env.classes.join(' ') + '"' + (attributes ? ' ' + attributes : '') + '>' + env.content + '</' + env.tag + '>';
-
-};
-
-if (!_self.document) {
- if (!_self.addEventListener) {
- // in Node.js
- return _self.Prism;
- }
- // In worker
- _self.addEventListener('message', function(evt) {
- var message = JSON.parse(evt.data),
- lang = message.language,
- code = message.code,
- immediateClose = message.immediateClose;
-
- _self.postMessage(_.highlight(code, _.languages[lang], lang));
- if (immediateClose) {
- _self.close();
- }
- }, false);
-
- return _self.Prism;
-}
-
-//Get current script and highlight
-var script = document.currentScript || [].slice.call(document.getElementsByTagName("script")).pop();
-
-if (script) {
- _.filename = script.src;
-
- if (document.addEventListener && !script.hasAttribute('data-manual')) {
- if(document.readyState !== "loading") {
- if (window.requestAnimationFrame) {
- window.requestAnimationFrame(_.highlightAll);
- } else {
- window.setTimeout(_.highlightAll, 16);
- }
- }
- else {
- document.addEventListener('DOMContentLoaded', _.highlightAll);
- }
- }
-}
-
-return _self.Prism;
-
-})();
-
-if (typeof module !== 'undefined' && module.exports) {
- module.exports = Prism;
-}
-
-// hack for components to work correctly in node.js
-if (typeof global !== 'undefined') {
- global.Prism = Prism;
-}
-
-
-/* **********************************************
- Begin prism-markup.js
-********************************************** */
-
-Prism.languages.markup = {
- 'comment': /<!--[\w\W]*?-->/,
- 'prolog': /<\?[\w\W]+?\?>/,
- 'doctype': /<!DOCTYPE[\w\W]+?>/i,
- 'cdata': /<!\[CDATA\[[\w\W]*?]]>/i,
- 'tag': {
- pattern: /<\/?(?!\d)[^\s>\/=$<]+(?:\s+[^\s>\/=]+(?:=(?:("|')(?:\\\1|\\?(?!\1)[\w\W])*\1|[^\s'">=]+))?)*\s*\/?>/i,
- inside: {
- 'tag': {
- pattern: /^<\/?[^\s>\/]+/i,
- inside: {
- 'punctuation': /^<\/?/,
- 'namespace': /^[^\s>\/:]+:/
- }
- },
- 'attr-value': {
- pattern: /=(?:('|")[\w\W]*?(\1)|[^\s>]+)/i,
- inside: {
- 'punctuation': /[=>"']/
- }
- },
- 'punctuation': /\/?>/,
- 'attr-name': {
- pattern: /[^\s>\/]+/,
- inside: {
- 'namespace': /^[^\s>\/:]+:/
- }
- }
-
- }
- },
- 'entity': /&#?[\da-z]{1,8};/i
-};
-
-// Plugin to make entity title show the real entity, idea by Roman Komarov
-Prism.hooks.add('wrap', function(env) {
-
- if (env.type === 'entity') {
- env.attributes['title'] = env.content.replace(/&amp;/, '&');
- }
-});
-
-Prism.languages.xml = Prism.languages.markup;
-Prism.languages.html = Prism.languages.markup;
-Prism.languages.mathml = Prism.languages.markup;
-Prism.languages.svg = Prism.languages.markup;
-
-
-/* **********************************************
- Begin prism-css.js
-********************************************** */
-
-Prism.languages.css = {
- 'comment': /\/\*[\w\W]*?\*\//,
- 'atrule': {
- pattern: /@[\w-]+?.*?(;|(?=\s*\{))/i,
- inside: {
- 'rule': /@[\w-]+/
- // See rest below
- }
- },
- 'url': /url\((?:(["'])(\\(?:\r\n|[\w\W])|(?!\1)[^\\\r\n])*\1|.*?)\)/i,
- 'selector': /[^\{\}\s][^\{\};]*?(?=\s*\{)/,
- 'string': {
- pattern: /("|')(\\(?:\r\n|[\w\W])|(?!\1)[^\\\r\n])*\1/,
- greedy: true
- },
- 'property': /(\b|\B)[\w-]+(?=\s*:)/i,
- 'important': /\B!important\b/i,
- 'function': /[-a-z0-9]+(?=\()/i,
- 'punctuation': /[(){};:]/
-};
-
-Prism.languages.css['atrule'].inside.rest = Prism.util.clone(Prism.languages.css);
-
-if (Prism.languages.markup) {
- Prism.languages.insertBefore('markup', 'tag', {
- 'style': {
- pattern: /(<style[\w\W]*?>)[\w\W]*?(?=<\/style>)/i,
- lookbehind: true,
- inside: Prism.languages.css,
- alias: 'language-css'
- }
- });
-
- Prism.languages.insertBefore('inside', 'attr-value', {
- 'style-attr': {
- pattern: /\s*style=("|').*?\1/i,
- inside: {
- 'attr-name': {
- pattern: /^\s*style/i,
- inside: Prism.languages.markup.tag.inside
- },
- 'punctuation': /^\s*=\s*['"]|['"]\s*$/,
- 'attr-value': {
- pattern: /.+/i,
- inside: Prism.languages.css
- }
- },
- alias: 'language-css'
- }
- }, Prism.languages.markup.tag);
-}
-
-/* **********************************************
- Begin prism-clike.js
-********************************************** */
-
-Prism.languages.clike = {
- 'comment': [
- {
- pattern: /(^|[^\\])\/\*[\w\W]*?\*\//,
- lookbehind: true
- },
- {
- pattern: /(^|[^\\:])\/\/.*/,
- lookbehind: true
- }
- ],
- 'string': {
- pattern: /(["'])(\\(?:\r\n|[\s\S])|(?!\1)[^\\\r\n])*\1/,
- greedy: true
- },
- 'class-name': {
- pattern: /((?:\b(?:class|interface|extends|implements|trait|instanceof|new)\s+)|(?:catch\s+\())[a-z0-9_\.\\]+/i,
- lookbehind: true,
- inside: {
- punctuation: /(\.|\\)/
- }
- },
- 'keyword': /\b(if|else|while|do|for|return|in|instanceof|function|new|try|throw|catch|finally|null|break|continue)\b/,
- 'boolean': /\b(true|false)\b/,
- 'function': /[a-z0-9_]+(?=\()/i,
- 'number': /\b-?(?:0x[\da-f]+|\d*\.?\d+(?:e[+-]?\d+)?)\b/i,
- 'operator': /--?|\+\+?|!=?=?|<=?|>=?|==?=?|&&?|\|\|?|\?|\*|\/|~|\^|%/,
- 'punctuation': /[{}[\];(),.:]/
-};
-
-
-/* **********************************************
- Begin prism-javascript.js
-********************************************** */
-
-Prism.languages.javascript = Prism.languages.extend('clike', {
- 'keyword': /\b(as|async|await|break|case|catch|class|const|continue|debugger|default|delete|do|else|enum|export|extends|finally|for|from|function|get|if|implements|import|in|instanceof|interface|let|new|null|of|package|private|protected|public|return|set|static|super|switch|this|throw|try|typeof|var|void|while|with|yield)\b/,
- 'number': /\b-?(0x[\dA-Fa-f]+|0b[01]+|0o[0-7]+|\d*\.?\d+([Ee][+-]?\d+)?|NaN|Infinity)\b/,
- // Allow for all non-ASCII characters (See http://stackoverflow.com/a/2008444)
- 'function': /[_$a-zA-Z\xA0-\uFFFF][_$a-zA-Z0-9\xA0-\uFFFF]*(?=\()/i,
- 'operator': /--?|\+\+?|!=?=?|<=?|>=?|==?=?|&&?|\|\|?|\?|\*\*?|\/|~|\^|%|\.{3}/
-});
-
-Prism.languages.insertBefore('javascript', 'keyword', {
- 'regex': {
- pattern: /(^|[^/])\/(?!\/)(\[.+?]|\\.|[^/\\\r\n])+\/[gimyu]{0,5}(?=\s*($|[\r\n,.;})]))/,
- lookbehind: true,
- greedy: true
- }
-});
-
-Prism.languages.insertBefore('javascript', 'string', {
- 'template-string': {
- pattern: /`(?:\\\\|\\?[^\\])*?`/,
- greedy: true,
- inside: {
- 'interpolation': {
- pattern: /\$\{[^}]+\}/,
- inside: {
- 'interpolation-punctuation': {
- pattern: /^\$\{|\}$/,
- alias: 'punctuation'
- },
- rest: Prism.languages.javascript
- }
- },
- 'string': /[\s\S]+/
- }
- }
-});
-
-if (Prism.languages.markup) {
- Prism.languages.insertBefore('markup', 'tag', {
- 'script': {
- pattern: /(<script[\w\W]*?>)[\w\W]*?(?=<\/script>)/i,
- lookbehind: true,
- inside: Prism.languages.javascript,
- alias: 'language-javascript'
- }
- });
-}
-
-Prism.languages.js = Prism.languages.javascript;
-
-/* **********************************************
- Begin prism-file-highlight.js
-********************************************** */
-
-(function () {
- if (typeof self === 'undefined' || !self.Prism || !self.document || !document.querySelector) {
- return;
- }
-
- self.Prism.fileHighlight = function() {
-
- var Extensions = {
- 'js': 'javascript',
- 'py': 'python',
- 'rb': 'ruby',
- 'ps1': 'powershell',
- 'psm1': 'powershell',
- 'sh': 'bash',
- 'bat': 'batch',
- 'h': 'c',
- 'tex': 'latex'
- };
-
- if(Array.prototype.forEach) { // Check to prevent error in IE8
- Array.prototype.slice.call(document.querySelectorAll('pre[data-src]')).forEach(function (pre) {
- var src = pre.getAttribute('data-src');
-
- var language, parent = pre;
- var lang = /\blang(?:uage)?-(?!\*)(\w+)\b/i;
- while (parent && !lang.test(parent.className)) {
- parent = parent.parentNode;
- }
-
- if (parent) {
- language = (pre.className.match(lang) || [, ''])[1];
- }
-
- if (!language) {
- var extension = (src.match(/\.(\w+)$/) || [, ''])[1];
- language = Extensions[extension] || extension;
- }
-
- var code = document.createElement('code');
- code.className = 'language-' + language;
-
- pre.textContent = '';
-
- code.textContent = 'Loading…';
-
- pre.appendChild(code);
-
- var xhr = new XMLHttpRequest();
-
- xhr.open('GET', src, true);
-
- xhr.onreadystatechange = function () {
- if (xhr.readyState == 4) {
-
- if (xhr.status < 400 && xhr.responseText) {
- code.textContent = xhr.responseText;
-
- Prism.highlightElement(code);
- }
- else if (xhr.status >= 400) {
- code.textContent = '✖ Error ' + xhr.status + ' while fetching file: ' + xhr.statusText;
- }
- else {
- code.textContent = '✖ Error: File does not exist or is empty';
- }
- }
- };
-
- xhr.send(null);
- });
- }
-
- };
-
- document.addEventListener('DOMContentLoaded', self.Prism.fileHighlight);
-
-})();
-
-/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(4)))
-
-/***/ }),
-/* 29 */
-/***/ (function(module, exports, __webpack_require__) {
-
-
-/* styles */
-__webpack_require__(42)
-
-var Component = __webpack_require__(0)(
- /* script */
- __webpack_require__(7),
- /* template */
- __webpack_require__(36),
- /* scopeId */
- "data-v-3ac4c361",
- /* cssModules */
- null
-)
-
-module.exports = Component.exports
-
-
-/***/ }),
-/* 30 */
-/***/ (function(module, exports, __webpack_require__) {
-
-
-/* styles */
-__webpack_require__(45)
-
-var Component = __webpack_require__(0)(
- /* script */
- __webpack_require__(9),
- /* template */
- __webpack_require__(40),
- /* scopeId */
- null,
- /* cssModules */
- null
-)
-
-module.exports = Component.exports
-
-
-/***/ }),
-/* 31 */
-/***/ (function(module, exports, __webpack_require__) {
-
-var Component = __webpack_require__(0)(
- /* script */
- __webpack_require__(10),
- /* template */
- __webpack_require__(37),
- /* scopeId */
- null,
- /* cssModules */
- null
-)
-
-module.exports = Component.exports
-
-
-/***/ }),
-/* 32 */
-/***/ (function(module, exports, __webpack_require__) {
-
-var Component = __webpack_require__(0)(
- /* script */
- __webpack_require__(11),
- /* template */
- __webpack_require__(34),
- /* scopeId */
- null,
- /* cssModules */
- null
-)
-
-module.exports = Component.exports
-
-
-/***/ }),
-/* 33 */
-/***/ (function(module, exports, __webpack_require__) {
-
-var Component = __webpack_require__(0)(
- /* script */
- __webpack_require__(12),
- /* template */
- __webpack_require__(35),
- /* scopeId */
- null,
- /* cssModules */
- null
-)
-
-module.exports = Component.exports
-
-
-/***/ }),
-/* 34 */
-/***/ (function(module, exports) {
-
-module.exports={render:function (){var _vm=this;var _h=_vm.$createElement;var _c=_vm._self._c||_h;
- return _c('div', {
- staticClass: "output"
- }, [_c('prompt'), _vm._v(" "), _c('img', {
- attrs: {
- "src": 'data:' + _vm.outputType + ';base64,' + _vm.rawCode
- }
- })], 1)
-},staticRenderFns: []}
-
-/***/ }),
-/* 35 */
-/***/ (function(module, exports) {
-
-module.exports={render:function (){var _vm=this;var _h=_vm.$createElement;var _c=_vm._self._c||_h;
- return _c(_vm.componentName, {
- tag: "component",
- attrs: {
- "type": "output",
- "outputType": _vm.outputType,
- "count": _vm.count,
- "raw-code": _vm.rawCode,
- "code-css-class": _vm.codeCssClass
- }
- })
-},staticRenderFns: []}
-
-/***/ }),
-/* 36 */
-/***/ (function(module, exports) {
-
-module.exports={render:function (){var _vm=this;var _h=_vm.$createElement;var _c=_vm._self._c||_h;
- return _c('div', {
- staticClass: "cell"
- }, [_c('code-cell', {
- attrs: {
- "type": "input",
- "raw-code": _vm.rawInputCode,
- "count": _vm.cell.execution_count,
- "code-css-class": _vm.codeCssClass
- }
- }), _vm._v(" "), (_vm.hasOutput) ? _c('output-cell', {
- attrs: {
- "count": _vm.cell.execution_count,
- "output": _vm.output,
- "code-css-class": _vm.codeCssClass
- }
- }) : _vm._e()], 1)
-},staticRenderFns: []}
-
-/***/ }),
-/* 37 */
-/***/ (function(module, exports) {
-
-module.exports={render:function (){var _vm=this;var _h=_vm.$createElement;var _c=_vm._self._c||_h;
- return _c('div', {
- staticClass: "output"
- }, [_c('prompt'), _vm._v(" "), _c('div', {
- domProps: {
- "innerHTML": _vm._s(_vm.rawCode)
- }
- })], 1)
-},staticRenderFns: []}
-
-/***/ }),
-/* 38 */
-/***/ (function(module, exports) {
-
-module.exports={render:function (){var _vm=this;var _h=_vm.$createElement;var _c=_vm._self._c||_h;
- return (_vm.hasNotebook) ? _c('div', _vm._l((_vm.cells), function(cell, index) {
- return _c(_vm.cellType(cell.cell_type), {
- key: index,
- tag: "component",
- attrs: {
- "cell": cell,
- "code-css-class": _vm.codeCssClass
- }
- })
- })) : _vm._e()
-},staticRenderFns: []}
-
-/***/ }),
-/* 39 */
-/***/ (function(module, exports) {
-
-module.exports={render:function (){var _vm=this;var _h=_vm.$createElement;var _c=_vm._self._c||_h;
- return _c('div', {
- staticClass: "prompt"
- }, [(_vm.type && _vm.count) ? _c('span', [_vm._v("\n " + _vm._s(_vm.type) + " [" + _vm._s(_vm.count) + "]:\n ")]) : _vm._e()])
-},staticRenderFns: []}
-
-/***/ }),
-/* 40 */
-/***/ (function(module, exports) {
-
-module.exports={render:function (){var _vm=this;var _h=_vm.$createElement;var _c=_vm._self._c||_h;
- return _c('div', {
- staticClass: "cell text-cell"
- }, [_c('prompt'), _vm._v(" "), _c('div', {
- staticClass: "markdown",
- domProps: {
- "innerHTML": _vm._s(_vm.markdown)
- }
- })], 1)
-},staticRenderFns: []}
-
-/***/ }),
-/* 41 */
-/***/ (function(module, exports) {
-
-module.exports={render:function (){var _vm=this;var _h=_vm.$createElement;var _c=_vm._self._c||_h;
- return _c('div', {
- class: _vm.type
- }, [_c('prompt', {
- attrs: {
- "type": _vm.promptType,
- "count": _vm.count
- }
- }), _vm._v(" "), _c('pre', {
- ref: "code",
- staticClass: "language-python",
- class: _vm.codeCssClass,
- domProps: {
- "textContent": _vm._s(_vm.code)
- }
- }, [_vm._v("\n ")])], 1)
-},staticRenderFns: []}
-
-/***/ }),
-/* 42 */
-/***/ (function(module, exports, __webpack_require__) {
-
-// style-loader: Adds some css to the DOM by adding a <style> tag
-
-// load the styles
-var content = __webpack_require__(19);
-if(typeof content === 'string') content = [[module.i, content, '']];
-if(content.locals) module.exports = content.locals;
-// add the styles to the DOM
-var update = __webpack_require__(3)("74a276de", content, true);
-// Hot Module Replacement
-if(false) {
- // When the styles change, update the <style> tags
- if(!content.locals) {
- module.hot.accept("!!../../node_modules/css-loader/index.js?minimize!../../node_modules/vue-loader/lib/style-compiler/index.js?{\"id\":\"data-v-3ac4c361\",\"scoped\":true,\"hasInlineConfig\":false}!../../node_modules/vue-loader/lib/selector.js?type=styles&index=0!./code.vue", function() {
- var newContent = require("!!../../node_modules/css-loader/index.js?minimize!../../node_modules/vue-loader/lib/style-compiler/index.js?{\"id\":\"data-v-3ac4c361\",\"scoped\":true,\"hasInlineConfig\":false}!../../node_modules/vue-loader/lib/selector.js?type=styles&index=0!./code.vue");
- if(typeof newContent === 'string') newContent = [[module.id, newContent, '']];
- update(newContent);
- });
- }
- // When the module is disposed, remove the <style> tags
- module.hot.dispose(function() { update(); });
-}
-
-/***/ }),
-/* 43 */
-/***/ (function(module, exports, __webpack_require__) {
-
-// style-loader: Adds some css to the DOM by adding a <style> tag
-
-// load the styles
-var content = __webpack_require__(20);
-if(typeof content === 'string') content = [[module.i, content, '']];
-if(content.locals) module.exports = content.locals;
-// add the styles to the DOM
-var update = __webpack_require__(3)("55f9d67b", content, true);
-// Hot Module Replacement
-if(false) {
- // When the styles change, update the <style> tags
- if(!content.locals) {
- module.hot.accept("!!../node_modules/css-loader/index.js?minimize!../node_modules/vue-loader/lib/style-compiler/index.js?{\"id\":\"data-v-4cb2b168\",\"scoped\":false,\"hasInlineConfig\":false}!../node_modules/vue-loader/lib/selector.js?type=styles&index=0!./index.vue", function() {
- var newContent = require("!!../node_modules/css-loader/index.js?minimize!../node_modules/vue-loader/lib/style-compiler/index.js?{\"id\":\"data-v-4cb2b168\",\"scoped\":false,\"hasInlineConfig\":false}!../node_modules/vue-loader/lib/selector.js?type=styles&index=0!./index.vue");
- if(typeof newContent === 'string') newContent = [[module.id, newContent, '']];
- update(newContent);
- });
- }
- // When the module is disposed, remove the <style> tags
- module.hot.dispose(function() { update(); });
-}
-
-/***/ }),
-/* 44 */
-/***/ (function(module, exports, __webpack_require__) {
-
-// style-loader: Adds some css to the DOM by adding a <style> tag
-
-// load the styles
-var content = __webpack_require__(21);
-if(typeof content === 'string') content = [[module.i, content, '']];
-if(content.locals) module.exports = content.locals;
-// add the styles to the DOM
-var update = __webpack_require__(3)("1096aefc", content, true);
-// Hot Module Replacement
-if(false) {
- // When the styles change, update the <style> tags
- if(!content.locals) {
- module.hot.accept("!!../../node_modules/css-loader/index.js?minimize!../../node_modules/vue-loader/lib/style-compiler/index.js?{\"id\":\"data-v-4f6bf458\",\"scoped\":true,\"hasInlineConfig\":false}!../../node_modules/vue-loader/lib/selector.js?type=styles&index=0!./prompt.vue", function() {
- var newContent = require("!!../../node_modules/css-loader/index.js?minimize!../../node_modules/vue-loader/lib/style-compiler/index.js?{\"id\":\"data-v-4f6bf458\",\"scoped\":true,\"hasInlineConfig\":false}!../../node_modules/vue-loader/lib/selector.js?type=styles&index=0!./prompt.vue");
- if(typeof newContent === 'string') newContent = [[module.id, newContent, '']];
- update(newContent);
- });
- }
- // When the module is disposed, remove the <style> tags
- module.hot.dispose(function() { update(); });
-}
-
-/***/ }),
-/* 45 */
-/***/ (function(module, exports, __webpack_require__) {
-
-// style-loader: Adds some css to the DOM by adding a <style> tag
-
-// load the styles
-var content = __webpack_require__(22);
-if(typeof content === 'string') content = [[module.i, content, '']];
-if(content.locals) module.exports = content.locals;
-// add the styles to the DOM
-var update = __webpack_require__(3)("58a0689d", content, true);
-// Hot Module Replacement
-if(false) {
- // When the styles change, update the <style> tags
- if(!content.locals) {
- module.hot.accept("!!../../node_modules/css-loader/index.js?minimize!../../node_modules/vue-loader/lib/style-compiler/index.js?{\"id\":\"data-v-7342b363\",\"scoped\":false,\"hasInlineConfig\":false}!../../node_modules/vue-loader/lib/selector.js?type=styles&index=0!./markdown.vue", function() {
- var newContent = require("!!../../node_modules/css-loader/index.js?minimize!../../node_modules/vue-loader/lib/style-compiler/index.js?{\"id\":\"data-v-7342b363\",\"scoped\":false,\"hasInlineConfig\":false}!../../node_modules/vue-loader/lib/selector.js?type=styles&index=0!./markdown.vue");
- if(typeof newContent === 'string') newContent = [[module.id, newContent, '']];
- update(newContent);
- });
- }
- // When the module is disposed, remove the <style> tags
- module.hot.dispose(function() { update(); });
-}
-
-/***/ }),
-/* 46 */
-/***/ (function(module, exports) {
-
-/**
- * Translates the list format produced by css-loader into something
- * easier to manipulate.
- */
-module.exports = function listToStyles (parentId, list) {
- var styles = []
- var newStyles = {}
- for (var i = 0; i < list.length; i++) {
- var item = list[i]
- var id = item[0]
- var css = item[1]
- var media = item[2]
- var sourceMap = item[3]
- var part = {
- id: parentId + ':' + i,
- css: css,
- media: media,
- sourceMap: sourceMap
- }
- if (!newStyles[id]) {
- styles.push(newStyles[id] = { id: id, parts: [part] })
- } else {
- newStyles[id].parts.push(part)
- }
- }
- return styles
-}
-
-
-/***/ }),
-/* 47 */
-/***/ (function(module, exports, __webpack_require__) {
-
-"use strict";
-
-
-var Notebook = __webpack_require__(6);
-
-module.exports = {
- install: function install(_vue) {
- _vue.component('notebook-lab', Notebook);
- }
-};
-
-/***/ })
-/******/ ]);
-}); \ No newline at end of file
diff --git a/yarn.lock b/yarn.lock
index 90ba39a3251..8f38fb4a9a4 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -1119,6 +1119,14 @@ cli-width@^2.0.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-2.1.0.tgz#b234ca209b29ef66fc518d9b98d5847b00edf00a"
+clipboard@^1.5.5:
+ version "1.6.1"
+ resolved "https://registry.yarnpkg.com/clipboard/-/clipboard-1.6.1.tgz#65c5b654812466b0faab82dc6ba0f1d2f8e4be53"
+ dependencies:
+ good-listener "^1.2.0"
+ select "^1.1.2"
+ tiny-emitter "^1.0.0"
+
cliui@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/cliui/-/cliui-2.1.0.tgz#4b475760ff80264c762c3a1719032e91c7fea0d1"
@@ -1596,6 +1604,10 @@ delayed-stream@~1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619"
+delegate@^3.1.2:
+ version "3.1.2"
+ resolved "https://registry.yarnpkg.com/delegate/-/delegate-3.1.2.tgz#1e1bc6f5cadda6cb6cbf7e6d05d0bcdd5712aebe"
+
delegates@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a"
@@ -2497,6 +2509,12 @@ globby@^5.0.0:
pify "^2.0.0"
pinkie-promise "^2.0.0"
+good-listener@^1.2.0:
+ version "1.2.2"
+ resolved "https://registry.yarnpkg.com/good-listener/-/good-listener-1.2.2.tgz#d53b30cdf9313dffb7dc9a0d477096aa6d145c50"
+ dependencies:
+ delegate "^3.1.2"
+
got@^3.2.0:
version "3.3.1"
resolved "https://registry.yarnpkg.com/got/-/got-3.3.1.tgz#e5d0ed4af55fc3eef4d56007769d98192bcb2eca"
@@ -3554,6 +3572,10 @@ map-stream@~0.1.0:
version "0.1.0"
resolved "https://registry.yarnpkg.com/map-stream/-/map-stream-0.1.0.tgz#e56aa94c4c8055a16404a0674b78f215f7c8e194"
+marked@^0.3.6:
+ version "0.3.6"
+ resolved "https://registry.yarnpkg.com/marked/-/marked-0.3.6.tgz#b2c6c618fccece4ef86c4fc6cb8a7cbf5aeda8d7"
+
math-expression-evaluator@^1.2.14:
version "1.2.16"
resolved "https://registry.yarnpkg.com/math-expression-evaluator/-/math-expression-evaluator-1.2.16.tgz#b357fa1ca9faefb8e48d10c14ef2bcb2d9f0a7c9"
@@ -4415,6 +4437,12 @@ preserve@^0.2.0:
version "0.2.0"
resolved "https://registry.yarnpkg.com/preserve/-/preserve-0.2.0.tgz#815ed1f6ebc65926f865b310c0713bcb3315ce4b"
+prismjs@^1.6.0:
+ version "1.6.0"
+ resolved "https://registry.yarnpkg.com/prismjs/-/prismjs-1.6.0.tgz#118d95fb7a66dba2272e343b345f5236659db365"
+ optionalDependencies:
+ clipboard "^1.5.5"
+
private@^0.1.6:
version "0.1.7"
resolved "https://registry.yarnpkg.com/private/-/private-0.1.7.tgz#68ce5e8a1ef0a23bb570cc28537b5332aba63ef1"
@@ -4873,6 +4901,10 @@ select2@3.5.2-browserify:
version "3.5.2-browserify"
resolved "https://registry.yarnpkg.com/select2/-/select2-3.5.2-browserify.tgz#dc4dafda38d67a734e8a97a46f0d3529ae05391d"
+select@^1.1.2:
+ version "1.1.2"
+ resolved "https://registry.yarnpkg.com/select/-/select-1.1.2.tgz#0e7350acdec80b1108528786ec1d4418d11b396d"
+
semver-diff@^2.0.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/semver-diff/-/semver-diff-2.1.0.tgz#4bbb8437c8d37e4b0cf1a68fd726ec6d645d6d36"
@@ -5368,6 +5400,10 @@ timers-browserify@^2.0.2:
dependencies:
setimmediate "^1.0.4"
+tiny-emitter@^1.0.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/tiny-emitter/-/tiny-emitter-1.1.0.tgz#ab405a21ffed814a76c19739648093d70654fecb"
+
tmp@0.0.28, tmp@0.0.x:
version "0.0.28"
resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.28.tgz#172735b7f614ea7af39664fa84cf0de4e515d120"