summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitlab-ci.yml8
-rw-r--r--.gitlab/issue_templates/Bug.md2
-rw-r--r--.ruby-version2
-rw-r--r--.scss-lint.yml2
-rw-r--r--CHANGELOG.md14
-rw-r--r--Gemfile4
-rw-r--r--Gemfile.lock13
-rw-r--r--app/assets/fonts/OFL.txt93
-rw-r--r--app/assets/fonts/SourceSansPro-Black.ttf.woffbin113800 -> 0 bytes
-rw-r--r--app/assets/fonts/SourceSansPro-Black.ttf.woff2bin82052 -> 0 bytes
-rw-r--r--app/assets/fonts/SourceSansPro-BlackIt.ttf.woffbin49704 -> 0 bytes
-rw-r--r--app/assets/fonts/SourceSansPro-BlackIt.ttf.woff2bin34812 -> 0 bytes
-rw-r--r--app/assets/fonts/SourceSansPro-Bold.ttf.woffbin117872 -> 0 bytes
-rw-r--r--app/assets/fonts/SourceSansPro-Bold.ttf.woff2bin85604 -> 0 bytes
-rw-r--r--app/assets/fonts/SourceSansPro-BoldIt.ttf.woffbin50608 -> 0 bytes
-rw-r--r--app/assets/fonts/SourceSansPro-BoldIt.ttf.woff2bin35864 -> 0 bytes
-rw-r--r--app/assets/fonts/SourceSansPro-ExtraLight.ttf.woffbin114336 -> 0 bytes
-rw-r--r--app/assets/fonts/SourceSansPro-ExtraLight.ttf.woff2bin82808 -> 0 bytes
-rw-r--r--app/assets/fonts/SourceSansPro-ExtraLightIt.ttf.woffbin49684 -> 0 bytes
-rw-r--r--app/assets/fonts/SourceSansPro-ExtraLightIt.ttf.woff2bin34560 -> 0 bytes
-rw-r--r--app/assets/fonts/SourceSansPro-It.ttf.woffbin51012 -> 0 bytes
-rw-r--r--app/assets/fonts/SourceSansPro-It.ttf.woff2bin36016 -> 0 bytes
-rw-r--r--app/assets/fonts/SourceSansPro-Light.ttf.woffbin118284 -> 0 bytes
-rw-r--r--app/assets/fonts/SourceSansPro-Light.ttf.woff2bin86336 -> 0 bytes
-rw-r--r--app/assets/fonts/SourceSansPro-LightIt.ttf.woffbin50992 -> 0 bytes
-rw-r--r--app/assets/fonts/SourceSansPro-LightIt.ttf.woff2bin35952 -> 0 bytes
-rw-r--r--app/assets/fonts/SourceSansPro-Regular.ttf.woffbin119064 -> 0 bytes
-rw-r--r--app/assets/fonts/SourceSansPro-Regular.ttf.woff2bin86844 -> 0 bytes
-rw-r--r--app/assets/fonts/SourceSansPro-Semibold.ttf.woffbin118412 -> 0 bytes
-rw-r--r--app/assets/fonts/SourceSansPro-Semibold.ttf.woff2bin86196 -> 0 bytes
-rw-r--r--app/assets/fonts/SourceSansPro-SemiboldIt.ttf.woffbin50924 -> 0 bytes
-rw-r--r--app/assets/fonts/SourceSansPro-SemiboldIt.ttf.woff2bin35984 -> 0 bytes
-rw-r--r--app/assets/javascripts/application.js18
-rw-r--r--app/assets/javascripts/diff.js73
-rw-r--r--app/assets/javascripts/diff.js.es6109
-rw-r--r--app/assets/javascripts/dispatcher.js.es610
-rw-r--r--app/assets/javascripts/environments/components/environment_item.js.es62
-rw-r--r--app/assets/javascripts/gfm_auto_complete.js.es618
-rw-r--r--app/assets/javascripts/lib/utils/common_utils.js55
-rw-r--r--app/assets/javascripts/merge_request.js2
-rw-r--r--app/assets/javascripts/merge_request_tabs.js442
-rw-r--r--app/assets/javascripts/merge_request_tabs.js.es6389
-rw-r--r--app/assets/javascripts/single_file_diff.js5
-rw-r--r--app/assets/javascripts/vue_common_component/commit.js.es614
-rw-r--r--app/assets/stylesheets/framework.scss4
-rw-r--r--app/assets/stylesheets/framework/avatar.scss2
-rw-r--r--app/assets/stylesheets/framework/awards.scss (renamed from app/assets/stylesheets/pages/awards.scss)4
-rw-r--r--app/assets/stylesheets/framework/blank.scss4
-rw-r--r--app/assets/stylesheets/framework/blocks.scss13
-rw-r--r--app/assets/stylesheets/framework/broadcast-messages.scss21
-rw-r--r--app/assets/stylesheets/framework/buttons.scss22
-rw-r--r--app/assets/stylesheets/framework/calendar.scss4
-rw-r--r--app/assets/stylesheets/framework/callout.scss24
-rw-r--r--app/assets/stylesheets/framework/common.scss78
-rw-r--r--app/assets/stylesheets/framework/dropdowns.scss10
-rw-r--r--app/assets/stylesheets/framework/files.scss20
-rw-r--r--app/assets/stylesheets/framework/fonts.scss45
-rw-r--r--app/assets/stylesheets/framework/forms.scss12
-rw-r--r--app/assets/stylesheets/framework/gitlab-theme.scss32
-rw-r--r--app/assets/stylesheets/framework/header.scss8
-rw-r--r--app/assets/stylesheets/framework/images.scss (renamed from app/assets/stylesheets/pages/appearances.scss)0
-rw-r--r--app/assets/stylesheets/framework/issue_box.scss6
-rw-r--r--app/assets/stylesheets/framework/jquery.scss16
-rw-r--r--app/assets/stylesheets/framework/layout.scss2
-rw-r--r--app/assets/stylesheets/framework/lists.scss51
-rw-r--r--app/assets/stylesheets/framework/markdown_area.scss10
-rw-r--r--app/assets/stylesheets/framework/mixins.scss6
-rw-r--r--app/assets/stylesheets/framework/mobile.scss6
-rw-r--r--app/assets/stylesheets/framework/nav.scss14
-rw-r--r--app/assets/stylesheets/framework/selects.scss16
-rw-r--r--app/assets/stylesheets/framework/sidebar.scss2
-rw-r--r--app/assets/stylesheets/framework/tables.scss21
-rw-r--r--app/assets/stylesheets/framework/tw_bootstrap.scss8
-rw-r--r--app/assets/stylesheets/framework/tw_bootstrap_variables.scss18
-rw-r--r--app/assets/stylesheets/framework/typography.scss20
-rw-r--r--app/assets/stylesheets/framework/variables.scss282
-rw-r--r--app/assets/stylesheets/framework/wells.scss13
-rw-r--r--app/assets/stylesheets/framework/zen.scss6
-rw-r--r--app/assets/stylesheets/highlight/dark.scss230
-rw-r--r--app/assets/stylesheets/highlight/monokai.scss225
-rw-r--r--app/assets/stylesheets/highlight/solarized_dark.scss243
-rw-r--r--app/assets/stylesheets/highlight/solarized_light.scss243
-rw-r--r--app/assets/stylesheets/highlight/white.scss181
-rw-r--r--app/assets/stylesheets/mailers/devise.scss4
-rw-r--r--app/assets/stylesheets/mailers/highlighted_diff_email.scss174
-rw-r--r--app/assets/stylesheets/notify.scss10
-rw-r--r--app/assets/stylesheets/pages/admin.scss168
-rw-r--r--app/assets/stylesheets/pages/boards.scss6
-rw-r--r--app/assets/stylesheets/pages/builds.scss5
-rw-r--r--app/assets/stylesheets/pages/ci_projects.scss2
-rw-r--r--app/assets/stylesheets/pages/commit.scss8
-rw-r--r--app/assets/stylesheets/pages/commits.scss12
-rw-r--r--app/assets/stylesheets/pages/confirmation.scss32
-rw-r--r--app/assets/stylesheets/pages/cycle_analytics.scss6
-rw-r--r--app/assets/stylesheets/pages/dashboard.scss43
-rw-r--r--app/assets/stylesheets/pages/detail_page.scss6
-rw-r--r--app/assets/stylesheets/pages/diff.scss32
-rw-r--r--app/assets/stylesheets/pages/editor.scss4
-rw-r--r--app/assets/stylesheets/pages/errors.scss16
-rw-r--r--app/assets/stylesheets/pages/events.scss9
-rw-r--r--app/assets/stylesheets/pages/graph.scss13
-rw-r--r--app/assets/stylesheets/pages/help.scss8
-rw-r--r--app/assets/stylesheets/pages/issuable.scss6
-rw-r--r--app/assets/stylesheets/pages/issues.scss8
-rw-r--r--app/assets/stylesheets/pages/labels.scss2
-rw-r--r--app/assets/stylesheets/pages/lint.scss8
-rw-r--r--app/assets/stylesheets/pages/login.scss7
-rw-r--r--app/assets/stylesheets/pages/merge_conflicts.scss8
-rw-r--r--app/assets/stylesheets/pages/merge_requests.scss11
-rw-r--r--app/assets/stylesheets/pages/note_form.scss4
-rw-r--r--app/assets/stylesheets/pages/notes.scss12
-rw-r--r--app/assets/stylesheets/pages/pipelines.scss6
-rw-r--r--app/assets/stylesheets/pages/projects.scss34
-rw-r--r--app/assets/stylesheets/pages/runners.scss12
-rw-r--r--app/assets/stylesheets/pages/stat_graph.scss14
-rw-r--r--app/assets/stylesheets/pages/status.scss2
-rw-r--r--app/assets/stylesheets/pages/tags.scss7
-rw-r--r--app/assets/stylesheets/pages/todos.scss10
-rw-r--r--app/assets/stylesheets/pages/ui_dev_kit.scss4
-rw-r--r--app/assets/stylesheets/pages/votes.scss4
-rw-r--r--app/assets/stylesheets/pages/xterm.scss772
-rw-r--r--app/controllers/concerns/merge_requests_action.rb7
-rw-r--r--app/controllers/projects/discussions_controller.rb4
-rw-r--r--app/controllers/projects/issues_controller.rb15
-rw-r--r--app/controllers/projects/merge_requests_controller.rb14
-rw-r--r--app/finders/issuable_finder.rb19
-rw-r--r--app/finders/merge_requests_finder.rb1
-rw-r--r--app/helpers/ci_status_helper.rb25
-rw-r--r--app/helpers/gitlab_markdown_helper.rb2
-rw-r--r--app/helpers/labels_helper.rb9
-rw-r--r--app/helpers/projects_helper.rb16
-rw-r--r--app/models/ci/pipeline.rb4
-rw-r--r--app/models/commit.rb22
-rw-r--r--app/models/commit_range.rb17
-rw-r--r--app/models/concerns/referable.rb13
-rw-r--r--app/models/discussion.rb4
-rw-r--r--app/models/issue.rb6
-rw-r--r--app/models/label.rb15
-rw-r--r--app/models/member.rb1
-rw-r--r--app/models/merge_request.rb14
-rw-r--r--app/models/milestone.rb13
-rw-r--r--app/models/note.rb2
-rw-r--r--app/models/project.rb33
-rw-r--r--app/models/repository.rb14
-rw-r--r--app/models/snippet.rb8
-rw-r--r--app/models/user.rb2
-rw-r--r--app/policies/ci/build_policy.rb2
-rw-r--r--app/policies/project_policy.rb8
-rw-r--r--app/services/discussions/base_service.rb4
-rw-r--r--app/services/discussions/resolve_service.rb24
-rw-r--r--app/services/issuable_base_service.rb5
-rw-r--r--app/services/issues/base_service.rb8
-rw-r--r--app/services/issues/build_service.rb50
-rw-r--r--app/services/issues/create_service.rb14
-rw-r--r--app/services/merge_requests/merge_when_pipeline_succeeds_service.rb (renamed from app/services/merge_requests/merge_when_build_succeeds_service.rb)2
-rw-r--r--app/services/system_note_service.rb14
-rw-r--r--app/views/admin/abuse_reports/index.html.haml10
-rw-r--r--app/views/admin/dashboard/index.html.haml12
-rw-r--r--app/views/admin/users/_user.html.haml8
-rw-r--r--app/views/admin/users/index.html.haml2
-rw-r--r--app/views/admin/users/projects.html.haml2
-rw-r--r--app/views/devise/confirmations/almost_there.haml7
-rw-r--r--app/views/layouts/nav/_group.html.haml2
-rw-r--r--app/views/projects/_readme.html.haml2
-rw-r--r--app/views/projects/blame/show.html.haml2
-rw-r--r--app/views/projects/buttons/_download.html.haml79
-rw-r--r--app/views/projects/ci/pipelines/_pipeline.html.haml7
-rw-r--r--app/views/projects/commits/_commit.html.haml2
-rw-r--r--app/views/projects/empty.html.haml2
-rw-r--r--app/views/projects/merge_requests/widget/_heading.html.haml3
-rw-r--r--app/views/projects/merge_requests/widget/open/_accept.html.haml4
-rw-r--r--app/views/projects/merge_requests/widget/open/_merge_when_build_succeeds.html.haml2
-rw-r--r--app/views/projects/merge_requests/widget/open/_unresolved_discussions.html.haml6
-rw-r--r--app/views/projects/pipelines/_info.html.haml2
-rw-r--r--app/views/projects/pipelines_settings/_badge.html.haml2
-rw-r--r--app/views/projects/pipelines_settings/show.html.haml3
-rw-r--r--app/views/projects/tags/show.html.haml21
-rw-r--r--app/views/shared/issuable/_form.html.haml15
-rw-r--r--app/views/shared/issuable/_nav.html.haml10
-rw-r--r--app/workers/pipeline_success_worker.rb2
-rw-r--r--changelogs/unreleased/23500-enable-colorvariable.yml4
-rw-r--r--changelogs/unreleased/23589-open-issue-for-mr.yml5
-rw-r--r--changelogs/unreleased/23696-fix-diff-view-highlighting.yml4
-rw-r--r--changelogs/unreleased/24669-merge-request-dashboard-page-takes-over-a-minute-to-load.yml4
-rw-r--r--changelogs/unreleased/24733-archived-project-merge-request-count.yml4
-rw-r--r--changelogs/unreleased/24921-hide-prompt-to-add-ssh-key-if-ssh-protocol-is-disabled.yml4
-rw-r--r--changelogs/unreleased/25098-header-margins-on-pipeline-settings.yml5
-rw-r--r--changelogs/unreleased/25199-fix-broken-urls-in-help-page.yml4
-rw-r--r--changelogs/unreleased/25202-fix-mr-widget-content-wrapping.yml5
-rw-r--r--changelogs/unreleased/25221-fix-build-status-overflow-mobile.yml4
-rw-r--r--changelogs/unreleased/25251-actionview-template-error-undefined-method-text-for-nil-nilclass.yml5
-rw-r--r--changelogs/unreleased/25264-ref-commit.yml4
-rw-r--r--changelogs/unreleased/api-expose-commiter-details.yml4
-rw-r--r--changelogs/unreleased/cleanup-common_utils-js.yml4
-rw-r--r--changelogs/unreleased/feature-admin-user-groups-link.yml4
-rw-r--r--changelogs/unreleased/fix-authorize-users-into-imported-gitlab-project.yml4
-rw-r--r--changelogs/unreleased/fix-compatibility-with-ie11-for-merge-requests.yml4
-rw-r--r--changelogs/unreleased/fix-github-branch-formatter.yml4
-rw-r--r--changelogs/unreleased/fix-rename-mwbs-to-merge-when-pipeline-succeeds.yml4
-rw-r--r--changelogs/unreleased/glm-shorthand-reference.yml4
-rw-r--r--changelogs/unreleased/issues-1608-text.yml4
-rw-r--r--changelogs/unreleased/mr-origin-7855.yml4
-rw-r--r--changelogs/unreleased/process-commit-worker-improvements.yml4
-rw-r--r--changelogs/unreleased/refactor-create-service-spec.yml4
-rw-r--r--changelogs/unreleased/remove-has-visible-content-caching.yml4
-rw-r--r--changelogs/unreleased/validate-state-param-when-filtering-issuables.yml4
-rw-r--r--changelogs/unreleased/zj-guest-reads-public-builds.yml4
-rw-r--r--changelogs/unreleased/zj-issue-new-over-issue-create.yml4
-rw-r--r--changelogs/unreleased/zj-use-ruby-2-3-3.yml4
-rw-r--r--config/routes/group.rb22
-rw-r--r--doc/administration/custom_hooks.md20
-rw-r--r--doc/api/commits.md8
-rw-r--r--doc/api/issues.md3
-rw-r--r--doc/api/merge_requests.md2
-rw-r--r--doc/api/projects.md48
-rw-r--r--doc/ci/README.md7
-rw-r--r--doc/ci/examples/php.md2
-rw-r--r--doc/ci/variables/README.md258
-rw-r--r--doc/ci/yaml/README.md16
-rw-r--r--doc/development/code_review.md4
-rw-r--r--doc/development/ux_guide/basics.md50
-rw-r--r--doc/development/ux_guide/components.md21
-rw-r--r--doc/development/ux_guide/img/button-close--active.pngbin0 -> 1385 bytes
-rw-r--r--doc/development/ux_guide/img/button-close--hover.pngbin0 -> 1015 bytes
-rw-r--r--doc/development/ux_guide/img/button-close--resting.pngbin0 -> 1271 bytes
-rw-r--r--doc/development/ux_guide/img/button-danger--active.pngbin0 -> 1450 bytes
-rw-r--r--doc/development/ux_guide/img/button-danger--hover.pngbin0 -> 1095 bytes
-rw-r--r--doc/development/ux_guide/img/button-danger--resting.pngbin0 -> 1376 bytes
-rw-r--r--doc/development/ux_guide/img/button-info--active.pngbin0 -> 1442 bytes
-rw-r--r--doc/development/ux_guide/img/button-info--hover.pngbin0 -> 1079 bytes
-rw-r--r--doc/development/ux_guide/img/button-info--resting.pngbin0 -> 1296 bytes
-rw-r--r--doc/development/ux_guide/img/button-spam--active.pngbin0 -> 1435 bytes
-rw-r--r--doc/development/ux_guide/img/button-spam--hover.pngbin0 -> 1108 bytes
-rw-r--r--doc/development/ux_guide/img/button-spam--resting.pngbin0 -> 1377 bytes
-rw-r--r--doc/development/ux_guide/img/button-success--active.pngbin0 -> 1510 bytes
-rw-r--r--doc/development/ux_guide/img/button-success--hover.pngbin0 -> 1151 bytes
-rw-r--r--doc/development/ux_guide/img/button-success--resting.pngbin0 -> 1447 bytes
-rw-r--r--doc/development/ux_guide/img/button-success-secondary--active.pngbin0 -> 1466 bytes
-rw-r--r--doc/development/ux_guide/img/button-success-secondary--hover.pngbin0 -> 1091 bytes
-rw-r--r--doc/development/ux_guide/img/button-success-secondary--resting.pngbin0 -> 1394 bytes
-rw-r--r--doc/development/ux_guide/img/button-warning--active.pngbin0 -> 1388 bytes
-rw-r--r--doc/development/ux_guide/img/button-warning--hover.pngbin0 -> 1040 bytes
-rw-r--r--doc/development/ux_guide/img/button-warning--resting.pngbin0 -> 1296 bytes
-rw-r--r--doc/development/ux_guide/img/color-blue.pngbin2725 -> 3555 bytes
-rw-r--r--doc/development/ux_guide/img/color-green.pngbin3008 -> 3852 bytes
-rw-r--r--doc/development/ux_guide/img/color-grey.pngbin2384 -> 3523 bytes
-rw-r--r--doc/development/ux_guide/img/color-orange.pngbin3470 -> 4480 bytes
-rw-r--r--doc/development/ux_guide/img/color-red.pngbin2628 -> 3550 bytes
-rw-r--r--doc/development/ux_guide/img/icon-add.pngbin155 -> 317 bytes
-rw-r--r--doc/development/ux_guide/img/icon-close.pngbin225 -> 501 bytes
-rw-r--r--doc/development/ux_guide/img/icon-edit.pngbin231 -> 546 bytes
-rw-r--r--doc/development/ux_guide/img/icon-notification.pngbin259 -> 543 bytes
-rw-r--r--doc/development/ux_guide/img/icon-rss.pngbin307 -> 834 bytes
-rw-r--r--doc/development/ux_guide/img/icon-subscribe.pngbin348 -> 760 bytes
-rw-r--r--doc/development/ux_guide/img/icon-trash.pngbin380 -> 398 bytes
-rw-r--r--doc/install/installation.md6
-rw-r--r--doc/integration/shibboleth.md2
-rw-r--r--doc/intro/README.md2
-rw-r--r--doc/update/patch_versions.md7
-rw-r--r--doc/user/markdown.md16
-rw-r--r--doc/user/project/merge_requests.md10
-rw-r--r--doc/user/project/merge_requests/img/preview_issue_for_discussions.pngbin0 -> 178361 bytes
-rw-r--r--doc/user/project/merge_requests/merge_request_discussion_resolution.md21
-rw-r--r--doc/user/project/merge_requests/merge_when_build_succeeds.md47
-rw-r--r--doc/user/project/merge_requests/merge_when_pipeline_succeeds.md46
-rw-r--r--doc/workflow/README.md4
-rw-r--r--doc/workflow/merge_when_build_succeeds.md2
-rw-r--r--features/steps/shared/project.rb2
-rw-r--r--lib/api/access_requests.rb5
-rw-r--r--lib/api/award_emoji.rb5
-rw-r--r--lib/api/builds.rb7
-rw-r--r--lib/api/commit_statuses.rb4
-rw-r--r--lib/api/entities.rb1
-rw-r--r--lib/api/groups.rb12
-rw-r--r--lib/api/issues.rb29
-rw-r--r--lib/api/members.rb6
-rw-r--r--lib/api/merge_requests.rb27
-rw-r--r--lib/api/milestones.rb5
-rw-r--r--lib/api/namespaces.rb4
-rw-r--r--lib/api/notes.rb4
-rw-r--r--lib/api/project_hooks.rb12
-rw-r--r--lib/api/project_snippets.rb6
-rw-r--r--lib/api/runners.rb5
-rw-r--r--lib/api/todos.rb10
-rw-r--r--lib/api/triggers.rb5
-rw-r--r--lib/api/users.rb5
-rw-r--r--lib/banzai/filter/abstract_reference_filter.rb23
-rw-r--r--lib/banzai/filter/commit_range_reference_filter.rb2
-rw-r--r--lib/banzai/filter/commit_reference_filter.rb2
-rw-r--r--lib/banzai/filter/label_reference_filter.rb54
-rw-r--r--lib/banzai/filter/milestone_reference_filter.rb20
-rw-r--r--lib/gitlab/chat_commands/issue_create.rb4
-rw-r--r--lib/gitlab/ci/status/canceled.rb19
-rw-r--r--lib/gitlab/ci/status/core.rb58
-rw-r--r--lib/gitlab/ci/status/created.rb19
-rw-r--r--lib/gitlab/ci/status/extended.rb11
-rw-r--r--lib/gitlab/ci/status/failed.rb19
-rw-r--r--lib/gitlab/ci/status/pending.rb19
-rw-r--r--lib/gitlab/ci/status/pipeline/common.rb23
-rw-r--r--lib/gitlab/ci/status/pipeline/factory.rb39
-rw-r--r--lib/gitlab/ci/status/pipeline/success_with_warnings.rb31
-rw-r--r--lib/gitlab/ci/status/running.rb19
-rw-r--r--lib/gitlab/ci/status/skipped.rb19
-rw-r--r--lib/gitlab/ci/status/success.rb19
-rw-r--r--lib/gitlab/diff/file_collection/merge_request_diff.rb2
-rwxr-xr-xscripts/lint-doc.sh2
-rw-r--r--spec/controllers/projects/issues_controller_spec.rb60
-rw-r--r--spec/controllers/projects/merge_requests_controller_spec.rb4
-rw-r--r--spec/features/admin/admin_users_spec.rb28
-rw-r--r--spec/features/commits_spec.rb19
-rw-r--r--spec/features/groups/labels/edit_spec.rb21
-rw-r--r--spec/features/groups/merge_requests_spec.rb30
-rw-r--r--spec/features/issues/create_issue_for_discussions_in_merge_request_spec.rb76
-rw-r--r--spec/features/issues/move_spec.rb2
-rw-r--r--spec/features/merge_requests/conflicts_spec.rb2
-rw-r--r--spec/features/merge_requests/create_new_mr_spec.rb2
-rw-r--r--spec/features/merge_requests/deleted_source_branch_spec.rb3
-rw-r--r--spec/features/merge_requests/merge_when_pipeline_succeeds_spec.rb (renamed from spec/features/merge_requests/merge_when_build_succeeds_spec.rb)31
-rw-r--r--spec/features/merge_requests/only_allow_merge_if_build_succeeds_spec.rb4
-rw-r--r--spec/features/projects/guest_navigation_menu_spec.rb4
-rw-r--r--spec/features/security/project/private_access_spec.rb55
-rw-r--r--spec/finders/issues_finder_spec.rb37
-rw-r--r--spec/finders/merge_requests_finder_spec.rb11
-rw-r--r--spec/helpers/labels_helper_spec.rb4
-rw-r--r--spec/javascripts/application_spec.js37
-rw-r--r--spec/javascripts/bootstrap_linked_tabs_spec.js.es64
-rw-r--r--spec/javascripts/extensions/element_spec.js.es638
-rw-r--r--spec/javascripts/fixtures/application.html.haml2
-rw-r--r--spec/javascripts/lib/utils/common_utils_spec.js.es632
-rw-r--r--spec/javascripts/merge_request_tabs_spec.js120
-rw-r--r--spec/javascripts/vue_common_components/commit_spec.js.es610
-rw-r--r--spec/lib/banzai/filter/abstract_link_filter_spec.rb4
-rw-r--r--spec/lib/banzai/filter/commit_range_reference_filter_spec.rb99
-rw-r--r--spec/lib/banzai/filter/commit_reference_filter_spec.rb78
-rw-r--r--spec/lib/banzai/filter/issue_reference_filter_spec.rb108
-rw-r--r--spec/lib/banzai/filter/label_reference_filter_spec.rb291
-rw-r--r--spec/lib/banzai/filter/merge_request_reference_filter_spec.rb92
-rw-r--r--spec/lib/banzai/filter/milestone_reference_filter_spec.rb108
-rw-r--r--spec/lib/banzai/filter/snippet_reference_filter_spec.rb85
-rw-r--r--spec/lib/gitlab/chat_commands/issue_create_spec.rb7
-rw-r--r--spec/lib/gitlab/ci/status/canceled_spec.rb21
-rw-r--r--spec/lib/gitlab/ci/status/created_spec.rb21
-rw-r--r--spec/lib/gitlab/ci/status/extended_spec.rb12
-rw-r--r--spec/lib/gitlab/ci/status/failed_spec.rb21
-rw-r--r--spec/lib/gitlab/ci/status/pending_spec.rb21
-rw-r--r--spec/lib/gitlab/ci/status/pipeline/common_spec.rb23
-rw-r--r--spec/lib/gitlab/ci/status/pipeline/factory_spec.rb52
-rw-r--r--spec/lib/gitlab/ci/status/pipeline/success_with_warnings_spec.rb65
-rw-r--r--spec/lib/gitlab/ci/status/running_spec.rb21
-rw-r--r--spec/lib/gitlab/ci/status/skipped_spec.rb21
-rw-r--r--spec/lib/gitlab/ci/status/success_spec.rb21
-rw-r--r--spec/lib/gitlab/cycle_analytics/permissions_spec.rb2
-rw-r--r--spec/lib/gitlab/diff/file_collection/merge_request_diff_spec.rb8
-rw-r--r--spec/lib/gitlab/gfm/reference_rewriter_spec.rb4
-rw-r--r--spec/lib/gitlab/import_export/members_mapper_spec.rb11
-rw-r--r--spec/models/ci/pipeline_spec.rb70
-rw-r--r--spec/models/commit_range_spec.rb8
-rw-r--r--spec/models/commit_spec.rb14
-rw-r--r--spec/models/discussion_spec.rb9
-rw-r--r--spec/models/group_label_spec.rb10
-rw-r--r--spec/models/issue_spec.rb10
-rw-r--r--spec/models/merge_request_spec.rb51
-rw-r--r--spec/models/milestone_spec.rb14
-rw-r--r--spec/models/project_label_spec.rb4
-rw-r--r--spec/models/project_spec.rb66
-rw-r--r--spec/models/repository_spec.rb31
-rw-r--r--spec/models/snippet_spec.rb29
-rw-r--r--spec/models/user_spec.rb17
-rw-r--r--spec/policies/project_policy_spec.rb24
-rw-r--r--spec/requests/api/builds_spec.rb2
-rw-r--r--spec/requests/api/commits_spec.rb9
-rw-r--r--spec/requests/api/issues_spec.rb26
-rw-r--r--spec/requests/api/merge_requests_spec.rb2
-rw-r--r--spec/requests/projects/cycle_analytics_events_spec.rb2
-rw-r--r--spec/services/discussions/resolve_service_spec.rb52
-rw-r--r--spec/services/issues/build_service_spec.rb130
-rw-r--r--spec/services/issues/create_service_spec.rb43
-rw-r--r--spec/services/issues/move_service_spec.rb4
-rw-r--r--spec/services/merge_requests/merge_when_pipeline_succeeds_service_spec.rb (renamed from spec/services/merge_requests/merge_when_build_succeeds_service_spec.rb)16
-rw-r--r--spec/services/projects/create_service_spec.rb212
-rw-r--r--spec/services/system_note_service_spec.rb36
-rw-r--r--spec/workers/pipeline_notification_worker_spec.rb2
-rw-r--r--spec/workers/pipeline_success_worker_spec.rb2
383 files changed, 6395 insertions, 2938 deletions
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index c7528029c89..8de7ca897ad 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -1,7 +1,7 @@
-image: "dev.gitlab.org:5005/gitlab/gitlab-build-images:ruby-2.3-git-2.7-phantomjs-2.1"
+image: "dev.gitlab.org:5005/gitlab/gitlab-build-images:ruby-2.3.3-git-2.7-phantomjs-2.1-node-7.1"
cache:
- key: "ruby-231"
+ key: "ruby-233"
paths:
- vendor/ruby
@@ -235,7 +235,7 @@ rake ee_compat_check:
- /^[\d-]+-stable(-ee)?$/
allow_failure: yes
cache:
- key: "ruby231-ee_compat_check_repo"
+ key: "ruby233-ee_compat_check_repo"
paths:
- ee_compat_check/repo/
- vendor/ruby
@@ -277,8 +277,6 @@ teaspoon:
stage: test
<<: *use-db
script:
- - curl --silent --location https://deb.nodesource.com/setup_6.x | bash -
- - apt-get install --assume-yes nodejs
- npm install
- npm link istanbul
- rake teaspoon
diff --git a/.gitlab/issue_templates/Bug.md b/.gitlab/issue_templates/Bug.md
index ac38f0c9521..6d7d88c6791 100644
--- a/.gitlab/issue_templates/Bug.md
+++ b/.gitlab/issue_templates/Bug.md
@@ -21,6 +21,8 @@ logs, and code as it's very hard to read otherwise.)
### Output of checks
+(If you are reporting a bug on GitLab.com, write: This bug happens on GitLab.com)
+
#### Results of GitLab application Check
(For installations with omnibus-gitlab package run and paste the output of:
diff --git a/.ruby-version b/.ruby-version
index 2bf1c1ccf36..0bee604df76 100644
--- a/.ruby-version
+++ b/.ruby-version
@@ -1 +1 @@
-2.3.1
+2.3.3
diff --git a/.scss-lint.yml b/.scss-lint.yml
index aae8d9b6dbe..83c68309fa8 100644
--- a/.scss-lint.yml
+++ b/.scss-lint.yml
@@ -30,7 +30,7 @@ linters:
# variable declarations. They should be referred to via variables everywhere
# else.
ColorVariable:
- enabled: false
+ enabled: true
# Which form of comments to prefer in CSS.
Comment:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 86b30d2832d..e03123111c3 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,6 +2,15 @@
documentation](doc/development/changelog.md) for instructions on adding your own
entry.
+## 8.14.3 (2016-12-02)
+
+- Pass commit data to ProcessCommitWorker to reduce Git overhead. !7744
+- Speed up issuable dashboards.
+- Don't change relative URLs to absolute URLs in the Help page.
+- Fixes "ActionView::Template::Error: undefined method `text?` for nil:NilClass" on MR pages.
+- Fix branch validation for GitHub PR where repo/fork was renamed/deleted.
+- Validate state param when filtering issuables.
+
## 8.14.2 (2016-12-01)
- Remove caching of events data. !6578
@@ -242,6 +251,11 @@ entry.
- Fix "Without projects" filter. !6611 (Ben Bodenmiller)
- Fix 404 when visit /projects page
+## 8.13.8 (2016-12-02)
+
+- Pass tag SHA to post-receive hook when tag is created via UI. !7700
+- Validate state param when filtering issuables.
+
## 8.13.7 (2016-11-28)
- fixes 500 error on project show when user is not logged in and project is still empty. !7376
diff --git a/Gemfile b/Gemfile
index 83edf420798..f49ef0386e7 100644
--- a/Gemfile
+++ b/Gemfile
@@ -264,7 +264,7 @@ group :development do
end
group :development, :test do
- gem 'byebug', '~> 8.2.1', platform: :mri
+ gem 'pry-byebug', '~> 3.4.1', platform: :mri
gem 'pry-rails', '~> 0.3.4'
gem 'awesome_print', '~> 1.2.0', require: false
@@ -338,7 +338,7 @@ gem 'ruby-prof', '~> 0.16.2'
gem 'oauth2', '~> 1.2.0'
# Soft deletion
-gem 'paranoia', '~> 2.0'
+gem 'paranoia', '~> 2.2'
# Health check
gem 'health_check', '~> 2.2.0'
diff --git a/Gemfile.lock b/Gemfile.lock
index 5a14ed6fede..7a024e81ad2 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -91,7 +91,7 @@ GEM
bundler-audit (0.5.0)
bundler (~> 1.2)
thor (~> 0.18)
- byebug (8.2.1)
+ byebug (9.0.6)
capybara (2.6.2)
addressable
mime-types (>= 1.16)
@@ -460,8 +460,8 @@ GEM
org-ruby (0.9.12)
rubypants (~> 0.2)
orm_adapter (0.5.0)
- paranoia (2.1.4)
- activerecord (~> 4.0)
+ paranoia (2.2.0)
+ activerecord (>= 4.0, < 5.1)
parser (2.3.1.4)
ast (~> 2.2)
pg (0.18.4)
@@ -483,6 +483,9 @@ GEM
coderay (~> 1.1.0)
method_source (~> 0.8.1)
slop (~> 3.4)
+ pry-byebug (3.4.1)
+ byebug (~> 9.0)
+ pry (~> 0.10)
pry-rails (0.3.4)
pry (>= 0.9.10)
pyu-ruby-sasl (0.0.3.3)
@@ -796,7 +799,6 @@ DEPENDENCIES
browser (~> 2.2)
bullet (~> 5.2.0)
bundler-audit (~> 0.5.0)
- byebug (~> 8.2.1)
capybara (~> 2.6.2)
capybara-screenshot (~> 1.0.0)
carrierwave (~> 0.10.0)
@@ -887,10 +889,11 @@ DEPENDENCIES
omniauth-twitter (~> 1.2.0)
omniauth_crowd (~> 2.2.0)
org-ruby (~> 0.9.12)
- paranoia (~> 2.0)
+ paranoia (~> 2.2)
pg (~> 0.18.2)
poltergeist (~> 1.9.0)
premailer-rails (~> 1.9.0)
+ pry-byebug (~> 3.4.1)
pry-rails (~> 0.3.4)
rack-attack (~> 4.4.1)
rack-cors (~> 0.4.0)
diff --git a/app/assets/fonts/OFL.txt b/app/assets/fonts/OFL.txt
deleted file mode 100644
index df187637e18..00000000000
--- a/app/assets/fonts/OFL.txt
+++ /dev/null
@@ -1,93 +0,0 @@
-Copyright 2010, 2012, 2014 Adobe Systems Incorporated (http://www.adobe.com/), with Reserved Font Name 'Source'. All Rights Reserved. Source is a trademark of Adobe Systems Incorporated in the United States and/or other countries.
-
-This Font Software is licensed under the SIL Open Font License, Version 1.1.
-
-This license is copied below, and is also available with a FAQ at: http://scripts.sil.org/OFL
-
-
------------------------------------------------------------
-SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
------------------------------------------------------------
-
-PREAMBLE
-The goals of the Open Font License (OFL) are to stimulate worldwide
-development of collaborative font projects, to support the font creation
-efforts of academic and linguistic communities, and to provide a free and
-open framework in which fonts may be shared and improved in partnership
-with others.
-
-The OFL allows the licensed fonts to be used, studied, modified and
-redistributed freely as long as they are not sold by themselves. The
-fonts, including any derivative works, can be bundled, embedded,
-redistributed and/or sold with any software provided that any reserved
-names are not used by derivative works. The fonts and derivatives,
-however, cannot be released under any other type of license. The
-requirement for fonts to remain under this license does not apply
-to any document created using the fonts or their derivatives.
-
-DEFINITIONS
-"Font Software" refers to the set of files released by the Copyright
-Holder(s) under this license and clearly marked as such. This may
-include source files, build scripts and documentation.
-
-"Reserved Font Name" refers to any names specified as such after the
-copyright statement(s).
-
-"Original Version" refers to the collection of Font Software components as
-distributed by the Copyright Holder(s).
-
-"Modified Version" refers to any derivative made by adding to, deleting,
-or substituting -- in part or in whole -- any of the components of the
-Original Version, by changing formats or by porting the Font Software to a
-new environment.
-
-"Author" refers to any designer, engineer, programmer, technical
-writer or other person who contributed to the Font Software.
-
-PERMISSION & CONDITIONS
-Permission is hereby granted, free of charge, to any person obtaining
-a copy of the Font Software, to use, study, copy, merge, embed, modify,
-redistribute, and sell modified and unmodified copies of the Font
-Software, subject to the following conditions:
-
-1) Neither the Font Software nor any of its individual components,
-in Original or Modified Versions, may be sold by itself.
-
-2) Original or Modified Versions of the Font Software may be bundled,
-redistributed and/or sold with any software, provided that each copy
-contains the above copyright notice and this license. These can be
-included either as stand-alone text files, human-readable headers or
-in the appropriate machine-readable metadata fields within text or
-binary files as long as those fields can be easily viewed by the user.
-
-3) No Modified Version of the Font Software may use the Reserved Font
-Name(s) unless explicit written permission is granted by the corresponding
-Copyright Holder. This restriction only applies to the primary font name as
-presented to the users.
-
-4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
-Software shall not be used to promote, endorse or advertise any
-Modified Version, except to acknowledge the contribution(s) of the
-Copyright Holder(s) and the Author(s) or with their explicit written
-permission.
-
-5) The Font Software, modified or unmodified, in part or in whole,
-must be distributed entirely under this license, and must not be
-distributed under any other license. The requirement for fonts to
-remain under this license does not apply to any document created
-using the Font Software.
-
-TERMINATION
-This license becomes null and void if any of the above conditions are
-not met.
-
-DISCLAIMER
-THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
-MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
-OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
-COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
-INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
-DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
-OTHER DEALINGS IN THE FONT SOFTWARE.
diff --git a/app/assets/fonts/SourceSansPro-Black.ttf.woff b/app/assets/fonts/SourceSansPro-Black.ttf.woff
deleted file mode 100644
index b7e86200927..00000000000
--- a/app/assets/fonts/SourceSansPro-Black.ttf.woff
+++ /dev/null
Binary files differ
diff --git a/app/assets/fonts/SourceSansPro-Black.ttf.woff2 b/app/assets/fonts/SourceSansPro-Black.ttf.woff2
deleted file mode 100644
index c90d078406c..00000000000
--- a/app/assets/fonts/SourceSansPro-Black.ttf.woff2
+++ /dev/null
Binary files differ
diff --git a/app/assets/fonts/SourceSansPro-BlackIt.ttf.woff b/app/assets/fonts/SourceSansPro-BlackIt.ttf.woff
deleted file mode 100644
index c3314b1ef06..00000000000
--- a/app/assets/fonts/SourceSansPro-BlackIt.ttf.woff
+++ /dev/null
Binary files differ
diff --git a/app/assets/fonts/SourceSansPro-BlackIt.ttf.woff2 b/app/assets/fonts/SourceSansPro-BlackIt.ttf.woff2
deleted file mode 100644
index b87e22c41b5..00000000000
--- a/app/assets/fonts/SourceSansPro-BlackIt.ttf.woff2
+++ /dev/null
Binary files differ
diff --git a/app/assets/fonts/SourceSansPro-Bold.ttf.woff b/app/assets/fonts/SourceSansPro-Bold.ttf.woff
deleted file mode 100644
index d1d40f840f8..00000000000
--- a/app/assets/fonts/SourceSansPro-Bold.ttf.woff
+++ /dev/null
Binary files differ
diff --git a/app/assets/fonts/SourceSansPro-Bold.ttf.woff2 b/app/assets/fonts/SourceSansPro-Bold.ttf.woff2
deleted file mode 100644
index 0f46f3e833a..00000000000
--- a/app/assets/fonts/SourceSansPro-Bold.ttf.woff2
+++ /dev/null
Binary files differ
diff --git a/app/assets/fonts/SourceSansPro-BoldIt.ttf.woff b/app/assets/fonts/SourceSansPro-BoldIt.ttf.woff
deleted file mode 100644
index ef6ff514d3a..00000000000
--- a/app/assets/fonts/SourceSansPro-BoldIt.ttf.woff
+++ /dev/null
Binary files differ
diff --git a/app/assets/fonts/SourceSansPro-BoldIt.ttf.woff2 b/app/assets/fonts/SourceSansPro-BoldIt.ttf.woff2
deleted file mode 100644
index 8007df6df32..00000000000
--- a/app/assets/fonts/SourceSansPro-BoldIt.ttf.woff2
+++ /dev/null
Binary files differ
diff --git a/app/assets/fonts/SourceSansPro-ExtraLight.ttf.woff b/app/assets/fonts/SourceSansPro-ExtraLight.ttf.woff
deleted file mode 100644
index 1e6c94d9eb3..00000000000
--- a/app/assets/fonts/SourceSansPro-ExtraLight.ttf.woff
+++ /dev/null
Binary files differ
diff --git a/app/assets/fonts/SourceSansPro-ExtraLight.ttf.woff2 b/app/assets/fonts/SourceSansPro-ExtraLight.ttf.woff2
deleted file mode 100644
index b715f274082..00000000000
--- a/app/assets/fonts/SourceSansPro-ExtraLight.ttf.woff2
+++ /dev/null
Binary files differ
diff --git a/app/assets/fonts/SourceSansPro-ExtraLightIt.ttf.woff b/app/assets/fonts/SourceSansPro-ExtraLightIt.ttf.woff
deleted file mode 100644
index 7a408b1ec73..00000000000
--- a/app/assets/fonts/SourceSansPro-ExtraLightIt.ttf.woff
+++ /dev/null
Binary files differ
diff --git a/app/assets/fonts/SourceSansPro-ExtraLightIt.ttf.woff2 b/app/assets/fonts/SourceSansPro-ExtraLightIt.ttf.woff2
deleted file mode 100644
index d8f9d29d4aa..00000000000
--- a/app/assets/fonts/SourceSansPro-ExtraLightIt.ttf.woff2
+++ /dev/null
Binary files differ
diff --git a/app/assets/fonts/SourceSansPro-It.ttf.woff b/app/assets/fonts/SourceSansPro-It.ttf.woff
deleted file mode 100644
index 4d54bc95718..00000000000
--- a/app/assets/fonts/SourceSansPro-It.ttf.woff
+++ /dev/null
Binary files differ
diff --git a/app/assets/fonts/SourceSansPro-It.ttf.woff2 b/app/assets/fonts/SourceSansPro-It.ttf.woff2
deleted file mode 100644
index a00852641f8..00000000000
--- a/app/assets/fonts/SourceSansPro-It.ttf.woff2
+++ /dev/null
Binary files differ
diff --git a/app/assets/fonts/SourceSansPro-Light.ttf.woff b/app/assets/fonts/SourceSansPro-Light.ttf.woff
deleted file mode 100644
index 1706d57d3c5..00000000000
--- a/app/assets/fonts/SourceSansPro-Light.ttf.woff
+++ /dev/null
Binary files differ
diff --git a/app/assets/fonts/SourceSansPro-Light.ttf.woff2 b/app/assets/fonts/SourceSansPro-Light.ttf.woff2
deleted file mode 100644
index d8b610ad76e..00000000000
--- a/app/assets/fonts/SourceSansPro-Light.ttf.woff2
+++ /dev/null
Binary files differ
diff --git a/app/assets/fonts/SourceSansPro-LightIt.ttf.woff b/app/assets/fonts/SourceSansPro-LightIt.ttf.woff
deleted file mode 100644
index 87378d6c609..00000000000
--- a/app/assets/fonts/SourceSansPro-LightIt.ttf.woff
+++ /dev/null
Binary files differ
diff --git a/app/assets/fonts/SourceSansPro-LightIt.ttf.woff2 b/app/assets/fonts/SourceSansPro-LightIt.ttf.woff2
deleted file mode 100644
index e0eebac8273..00000000000
--- a/app/assets/fonts/SourceSansPro-LightIt.ttf.woff2
+++ /dev/null
Binary files differ
diff --git a/app/assets/fonts/SourceSansPro-Regular.ttf.woff b/app/assets/fonts/SourceSansPro-Regular.ttf.woff
deleted file mode 100644
index 460ab12a638..00000000000
--- a/app/assets/fonts/SourceSansPro-Regular.ttf.woff
+++ /dev/null
Binary files differ
diff --git a/app/assets/fonts/SourceSansPro-Regular.ttf.woff2 b/app/assets/fonts/SourceSansPro-Regular.ttf.woff2
deleted file mode 100644
index 0dd3464c74b..00000000000
--- a/app/assets/fonts/SourceSansPro-Regular.ttf.woff2
+++ /dev/null
Binary files differ
diff --git a/app/assets/fonts/SourceSansPro-Semibold.ttf.woff b/app/assets/fonts/SourceSansPro-Semibold.ttf.woff
deleted file mode 100644
index 43379631b2d..00000000000
--- a/app/assets/fonts/SourceSansPro-Semibold.ttf.woff
+++ /dev/null
Binary files differ
diff --git a/app/assets/fonts/SourceSansPro-Semibold.ttf.woff2 b/app/assets/fonts/SourceSansPro-Semibold.ttf.woff2
deleted file mode 100644
index 2526d2e1b60..00000000000
--- a/app/assets/fonts/SourceSansPro-Semibold.ttf.woff2
+++ /dev/null
Binary files differ
diff --git a/app/assets/fonts/SourceSansPro-SemiboldIt.ttf.woff b/app/assets/fonts/SourceSansPro-SemiboldIt.ttf.woff
deleted file mode 100644
index 232c2048ae7..00000000000
--- a/app/assets/fonts/SourceSansPro-SemiboldIt.ttf.woff
+++ /dev/null
Binary files differ
diff --git a/app/assets/fonts/SourceSansPro-SemiboldIt.ttf.woff2 b/app/assets/fonts/SourceSansPro-SemiboldIt.ttf.woff2
deleted file mode 100644
index 606935af089..00000000000
--- a/app/assets/fonts/SourceSansPro-SemiboldIt.ttf.woff2
+++ /dev/null
Binary files differ
diff --git a/app/assets/javascripts/application.js b/app/assets/javascripts/application.js
index cfab4721f4b..b7c4673c8e3 100644
--- a/app/assets/javascripts/application.js
+++ b/app/assets/javascripts/application.js
@@ -56,7 +56,13 @@
/*= require es6-promise.auto */
(function () {
- document.addEventListener('page:fetch', gl.utils.cleanupBeforeFetch);
+ document.addEventListener('page:fetch', function () {
+ // Unbind scroll events
+ $(document).off('scroll');
+ // Close any open tooltips
+ $('.has-tooltip, [data-toggle="tooltip"]').tooltip('destroy');
+ });
+
window.addEventListener('hashchange', gl.utils.handleLocationHash);
window.addEventListener('load', function onLoad() {
window.removeEventListener('load', onLoad, false);
@@ -76,7 +82,15 @@
// Set the default path for all cookies to GitLab's root directory
Cookies.defaults.path = gon.relative_url_root || '/';
- gl.utils.preventDisabledButtons();
+ // prevent default action for disabled buttons
+ $('.btn').click(function(e) {
+ if ($(this).hasClass('disabled')) {
+ e.preventDefault();
+ e.stopImmediatePropagation();
+ return false;
+ }
+ });
+
$('.nav-sidebar').niceScroll({
cursoropacitymax: '0.4',
cursorcolor: '#FFF',
diff --git a/app/assets/javascripts/diff.js b/app/assets/javascripts/diff.js
deleted file mode 100644
index 00da5f17f9f..00000000000
--- a/app/assets/javascripts/diff.js
+++ /dev/null
@@ -1,73 +0,0 @@
-/* eslint-disable func-names, space-before-function-paren, wrap-iife, no-var, max-len, one-var, camelcase, one-var-declaration-per-line, no-unused-vars, no-unused-expressions, no-sequences, object-shorthand, comma-dangle, prefer-arrow-callback, semi, radix, padded-blocks, max-len */
-(function() {
- this.Diff = (function() {
- var UNFOLD_COUNT;
-
- UNFOLD_COUNT = 20;
-
- function Diff() {
- $('.files .diff-file').singleFileDiff();
- this.filesCommentButton = $('.files .diff-file').filesCommentButton();
- if (this.diffViewType() === 'parallel') {
- $('.content-wrapper .container-fluid').removeClass('container-limited');
- }
- $(document).off('click', '.js-unfold');
- $(document).on('click', '.js-unfold', (function(_this) {
- return function(event) {
- var line_number, link, file, offset, old_line, params, prev_new_line, prev_old_line, ref, ref1, since, target, to, unfold, unfoldBottom;
- target = $(event.target);
- unfoldBottom = target.hasClass('js-unfold-bottom');
- unfold = true;
- ref = _this.lineNumbers(target.parent()), old_line = ref[0], line_number = ref[1];
- offset = line_number - old_line;
- if (unfoldBottom) {
- line_number += 1;
- since = line_number;
- to = line_number + UNFOLD_COUNT;
- } else {
- ref1 = _this.lineNumbers(target.parent().prev()), prev_old_line = ref1[0], prev_new_line = ref1[1];
- line_number -= 1;
- to = line_number;
- if (line_number - UNFOLD_COUNT > prev_new_line + 1) {
- since = line_number - UNFOLD_COUNT;
- } else {
- since = prev_new_line + 1;
- unfold = false;
- }
- }
- file = target.parents('.diff-file');
- link = file.data('blob-diff-path');
- params = {
- since: since,
- to: to,
- bottom: unfoldBottom,
- offset: offset,
- unfold: unfold,
- view: file.data('view')
- };
- return $.get(link, params, function(response) {
- return target.parent().replaceWith(response);
- });
- };
- })(this));
- }
-
- Diff.prototype.diffViewType = function() {
- return $('.inline-parallel-buttons a.active').data('view-type');
- }
-
- Diff.prototype.lineNumbers = function(line) {
- if (!line.children().length) {
- return [0, 0];
- }
-
- return line.find('.diff-line-num').map(function() {
- return parseInt($(this).data('linenumber'));
- });
- };
-
- return Diff;
-
- })();
-
-}).call(this);
diff --git a/app/assets/javascripts/diff.js.es6 b/app/assets/javascripts/diff.js.es6
new file mode 100644
index 00000000000..ecf9d1de81c
--- /dev/null
+++ b/app/assets/javascripts/diff.js.es6
@@ -0,0 +1,109 @@
+/* eslint-disable class-methods-use-this */
+
+(() => {
+ const UNFOLD_COUNT = 20;
+
+ class Diff {
+ constructor() {
+ $('.files .diff-file').singleFileDiff();
+ $('.files .diff-file').filesCommentButton();
+
+ if (this.diffViewType() === 'parallel') {
+ $('.content-wrapper .container-fluid').removeClass('container-limited');
+ }
+
+ $(document)
+ .off('click', '.js-unfold, .diff-line-num a')
+ .on('click', '.js-unfold', this.handleClickUnfold.bind(this))
+ .on('click', '.diff-line-num a', this.handleClickLineNum.bind(this));
+
+ this.highlighSelectedLine();
+ }
+
+ handleClickUnfold(e) {
+ const $target = $(e.target);
+ // current babel config relies on iterators implementation, so we cannot simply do:
+ // const [oldLineNumber, newLineNumber] = this.lineNumbers($target.parent());
+ const ref = this.lineNumbers($target.parent());
+ const oldLineNumber = ref[0];
+ const newLineNumber = ref[1];
+ const offset = newLineNumber - oldLineNumber;
+ const bottom = $target.hasClass('js-unfold-bottom');
+ let since;
+ let to;
+ let unfold = true;
+
+ if (bottom) {
+ const lineNumber = newLineNumber + 1;
+ since = lineNumber;
+ to = lineNumber + UNFOLD_COUNT;
+ } else {
+ const lineNumber = newLineNumber - 1;
+ since = lineNumber - UNFOLD_COUNT;
+ to = lineNumber;
+
+ // make sure we aren't loading more than we need
+ const prevNewLine = this.lineNumbers($target.parent().prev())[1];
+ if (since <= prevNewLine + 1) {
+ since = prevNewLine + 1;
+ unfold = false;
+ }
+ }
+
+ const file = $target.parents('.diff-file');
+ const link = file.data('blob-diff-path');
+ const view = file.data('view');
+
+ const params = { since, to, bottom, offset, unfold, view };
+ $.get(link, params, response => $target.parent().replaceWith(response));
+ }
+
+ openAnchoredDiff(anchoredDiff, cb) {
+ const diffTitle = $(`#file-path-${anchoredDiff}`);
+ const diffFile = diffTitle.closest('.diff-file');
+ const nothingHereBlock = $('.nothing-here-block:visible', diffFile);
+ if (nothingHereBlock.length) {
+ diffFile.singleFileDiff(true, cb);
+ } else {
+ cb();
+ }
+ }
+
+ handleClickLineNum(e) {
+ const hash = $(e.currentTarget).attr('href');
+ e.preventDefault();
+ if (window.history.pushState) {
+ window.history.pushState(null, null, hash);
+ } else {
+ window.location.hash = hash;
+ }
+ this.highlighSelectedLine();
+ }
+
+ diffViewType() {
+ return $('.inline-parallel-buttons a.active').data('view-type');
+ }
+
+ lineNumbers(line) {
+ if (!line.children().length) {
+ return [0, 0];
+ }
+ return line.find('.diff-line-num').map((i, elm) => parseInt($(elm).data('linenumber'), 10));
+ }
+
+ highlighSelectedLine() {
+ const $diffFiles = $('.diff-file');
+ $diffFiles.find('.hll').removeClass('hll');
+
+ if (window.location.hash !== '') {
+ const hash = window.location.hash.replace('#', '');
+ $diffFiles
+ .find(`tr#${hash}:not(.match) td, td#${hash}, td[data-line-code="${hash}"]`)
+ .addClass('hll');
+ }
+ }
+ }
+
+ window.gl = window.gl || {};
+ window.gl.Diff = Diff;
+})();
diff --git a/app/assets/javascripts/dispatcher.js.es6 b/app/assets/javascripts/dispatcher.js.es6
index ab521c6c1fc..3a7c5ff3681 100644
--- a/app/assets/javascripts/dispatcher.js.es6
+++ b/app/assets/javascripts/dispatcher.js.es6
@@ -61,7 +61,7 @@
new ZenMode();
break;
case 'projects:compare:show':
- new Diff();
+ new gl.Diff();
break;
case 'projects:issues:new':
case 'projects:issues:edit':
@@ -74,7 +74,7 @@
break;
case 'projects:merge_requests:new':
case 'projects:merge_requests:edit':
- new Diff();
+ new gl.Diff();
shortcut_handler = new ShortcutsNavigation();
new GLForm($('.merge-request-form'));
new IssuableForm($('.merge-request-form'));
@@ -91,7 +91,7 @@
new GLForm($('.release-form'));
break;
case 'projects:merge_requests:show':
- new Diff();
+ new gl.Diff();
shortcut_handler = new ShortcutsIssuable(true);
new ZenMode();
new MergedButtons();
@@ -101,7 +101,7 @@
new MergedButtons();
break;
case "projects:merge_requests:diffs":
- new Diff();
+ new gl.Diff();
new ZenMode();
new MergedButtons();
break;
@@ -117,7 +117,7 @@
break;
case 'projects:commit:show':
new Commit();
- new Diff();
+ new gl.Diff();
new ZenMode();
shortcut_handler = new ShortcutsNavigation();
break;
diff --git a/app/assets/javascripts/environments/components/environment_item.js.es6 b/app/assets/javascripts/environments/components/environment_item.js.es6
index 7ead8a18c2a..6ed14261fc3 100644
--- a/app/assets/javascripts/environments/components/environment_item.js.es6
+++ b/app/assets/javascripts/environments/components/environment_item.js.es6
@@ -451,7 +451,7 @@
<div v-if="!isFolder && hasLastDeploymentKey" class="js-commit-component">
<commit-component
:tag="commitTag"
- :ref="commitRef"
+ :commit_ref="commitRef"
:commit_url="commitUrl"
:short_sha="commitShortSha"
:title="commitTitle"
diff --git a/app/assets/javascripts/gfm_auto_complete.js.es6 b/app/assets/javascripts/gfm_auto_complete.js.es6
index 10769b7fd4f..6f9d6283071 100644
--- a/app/assets/javascripts/gfm_auto_complete.js.es6
+++ b/app/assets/javascripts/gfm_auto_complete.js.es6
@@ -5,6 +5,10 @@
window.GitLab = {};
}
+ function sanitize(str) {
+ return str.replace(/<(?:.|\n)*?>/gm, '');
+ }
+
GitLab.GfmAutoComplete = {
dataLoading: false,
dataLoaded: false,
@@ -160,8 +164,8 @@
return {
username: m.username,
avatarTag: autoCompleteAvatar.length === 1 ? txtAvatar : imgAvatar,
- title: gl.utils.sanitize(title),
- search: gl.utils.sanitize(m.username + " " + m.name)
+ title: sanitize(title),
+ search: sanitize(m.username + " " + m.name)
};
});
}
@@ -195,7 +199,7 @@
}
return {
id: i.iid,
- title: gl.utils.sanitize(i.title),
+ title: sanitize(i.title),
search: i.iid + " " + i.title
};
});
@@ -228,7 +232,7 @@
}
return {
id: m.iid,
- title: gl.utils.sanitize(m.title),
+ title: sanitize(m.title),
search: "" + m.title
};
});
@@ -263,7 +267,7 @@
}
return {
id: m.iid,
- title: gl.utils.sanitize(m.title),
+ title: sanitize(m.title),
search: m.iid + " " + m.title
};
});
@@ -284,9 +288,9 @@
var sanitizeLabelTitle;
sanitizeLabelTitle = function(title) {
if (/[\w\?&]+\s+[\w\?&]+/g.test(title)) {
- return "\"" + (gl.utils.sanitize(title)) + "\"";
+ return "\"" + (sanitize(title)) + "\"";
} else {
- return gl.utils.sanitize(title);
+ return sanitize(title);
}
};
return $.map(merges, function(m) {
diff --git a/app/assets/javascripts/lib/utils/common_utils.js b/app/assets/javascripts/lib/utils/common_utils.js
index c5846068b07..8fa80502d92 100644
--- a/app/assets/javascripts/lib/utils/common_utils.js
+++ b/app/assets/javascripts/lib/utils/common_utils.js
@@ -33,10 +33,6 @@
});
};
- w.gl.utils.split = function(val) {
- return val.split(/,\s*/);
- };
-
w.gl.utils.extractLast = function(term) {
return this.split(term).pop();
};
@@ -67,33 +63,6 @@
});
};
- w.gl.utils.disableButtonIfAnyEmptyField = function(form, form_selector, button_selector) {
- var closest_submit, updateButtons;
- closest_submit = form.find(button_selector);
- updateButtons = function() {
- var filled;
- filled = true;
- form.find('input').filter(form_selector).each(function() {
- return filled = this.rstrip($(this).val()) !== "" || !$(this).attr('required');
- });
- if (filled) {
- return closest_submit.enable();
- } else {
- return closest_submit.disable();
- }
- };
- updateButtons();
- return form.keyup(updateButtons);
- };
-
- w.gl.utils.sanitize = function(str) {
- return str.replace(/<(?:.|\n)*?>/gm, '');
- };
-
- w.gl.utils.unbindEvents = function() {
- return $(document).off('scroll');
- };
-
// automatically adjust scroll position for hash urls taking the height of the navbar into account
// https://github.com/twitter/bootstrap/issues/1768
w.gl.utils.handleLocationHash = function() {
@@ -124,31 +93,21 @@
}
};
- gl.utils.updateTooltipTitle = function($tooltipEl, newTitle) {
- return $tooltipEl.tooltip('destroy').attr('title', newTitle).tooltip('fixTitle');
- };
- gl.utils.preventDisabledButtons = function() {
- return $('.btn').click(function(e) {
- if ($(this).hasClass('disabled')) {
- e.preventDefault();
- e.stopImmediatePropagation();
- return false;
- }
- });
- };
gl.utils.getPagePath = function() {
return $('body').data('page').split(':')[0];
};
+
gl.utils.parseUrl = function (url) {
var parser = document.createElement('a');
parser.href = url;
return parser;
};
- gl.utils.cleanupBeforeFetch = function() {
- // Unbind scroll events
- $(document).off('scroll');
- // Close any open tooltips
- $('.has-tooltip, [data-toggle="tooltip"]').tooltip('destroy');
+
+ gl.utils.parseUrlPathname = function (url) {
+ var parsedUrl = gl.utils.parseUrl(url);
+ // parsedUrl.pathname will return an absolute path for Firefox and a relative path for IE11
+ // We have to make sure we always have an absolute path.
+ return parsedUrl.pathname.charAt(0) === '/' ? parsedUrl.pathname : '/' + parsedUrl.pathname;
};
gl.utils.isMetaKey = function(e) {
diff --git a/app/assets/javascripts/merge_request.js b/app/assets/javascripts/merge_request.js
index a4b4db14db8..88c3636be6c 100644
--- a/app/assets/javascripts/merge_request.js
+++ b/app/assets/javascripts/merge_request.js
@@ -40,7 +40,7 @@
if (window.mrTabs) {
window.mrTabs.unbindEvents();
}
- window.mrTabs = new MergeRequestTabs(this.opts);
+ window.mrTabs = new gl.MergeRequestTabs(this.opts);
};
MergeRequest.prototype.showAllCommits = function() {
diff --git a/app/assets/javascripts/merge_request_tabs.js b/app/assets/javascripts/merge_request_tabs.js
deleted file mode 100644
index b1928f8d279..00000000000
--- a/app/assets/javascripts/merge_request_tabs.js
+++ /dev/null
@@ -1,442 +0,0 @@
-/* eslint-disable max-len, func-names, space-before-function-paren, no-var, space-before-blocks, prefer-rest-params, wrap-iife, no-use-before-define, no-underscore-dangle, no-undef, one-var, one-var-declaration-per-line, quotes, comma-dangle, consistent-return, prefer-template, no-param-reassign, camelcase, vars-on-top, space-in-parens, curly, prefer-arrow-callback, no-unused-vars, no-return-assign, semi, object-shorthand, operator-assignment, padded-blocks, max-len */
-// MergeRequestTabs
-//
-// Handles persisting and restoring the current tab selection and lazily-loading
-// content on the MergeRequests#show page.
-//
-/*= require js.cookie */
-
-//
-// ### Example Markup
-//
-// <ul class="nav-links merge-request-tabs">
-// <li class="notes-tab active">
-// <a data-action="notes" data-target="#notes" data-toggle="tab" href="/foo/bar/merge_requests/1">
-// Discussion
-// </a>
-// </li>
-// <li class="commits-tab">
-// <a data-action="commits" data-target="#commits" data-toggle="tab" href="/foo/bar/merge_requests/1/commits">
-// Commits
-// </a>
-// </li>
-// <li class="diffs-tab">
-// <a data-action="diffs" data-target="#diffs" data-toggle="tab" href="/foo/bar/merge_requests/1/diffs">
-// Diffs
-// </a>
-// </li>
-// </ul>
-//
-// <div class="tab-content">
-// <div class="notes tab-pane active" id="notes">
-// Notes Content
-// </div>
-// <div class="commits tab-pane" id="commits">
-// Commits Content
-// </div>
-// <div class="diffs tab-pane" id="diffs">
-// Diffs Content
-// </div>
-// </div>
-//
-// <div class="mr-loading-status">
-// <div class="loading">
-// Loading Animation
-// </div>
-// </div>
-//
-(function() {
- var bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; };
-
- this.MergeRequestTabs = (function() {
- MergeRequestTabs.prototype.diffsLoaded = false;
-
- MergeRequestTabs.prototype.buildsLoaded = false;
-
- MergeRequestTabs.prototype.pipelinesLoaded = false;
-
- MergeRequestTabs.prototype.commitsLoaded = false;
-
- MergeRequestTabs.prototype.fixedLayoutPref = null;
-
- function MergeRequestTabs(opts) {
- this.opts = opts != null ? opts : {};
- this.opts.setUrl = this.opts.setUrl !== undefined ? this.opts.setUrl : true;
-
- this.buildsLoaded = this.opts.buildsLoaded || false;
-
- this.setCurrentAction = bind(this.setCurrentAction, this);
- this.tabShown = bind(this.tabShown, this);
- this.showTab = bind(this.showTab, this);
- // Store the `location` object, allowing for easier stubbing in tests
- this._location = location;
- this.bindEvents();
- this.activateTab(this.opts.action);
- this.initAffix();
- }
-
- MergeRequestTabs.prototype.bindEvents = function() {
- $(document).on('shown.bs.tab', '.merge-request-tabs a[data-toggle="tab"]', this.tabShown);
- $(document).on('click', '.js-show-tab', this.showTab);
- };
-
- MergeRequestTabs.prototype.unbindEvents = function() {
- $(document).off('shown.bs.tab', '.merge-request-tabs a[data-toggle="tab"]', this.tabShown);
- $(document).off('click', '.js-show-tab', this.showTab);
- };
-
- MergeRequestTabs.prototype.showTab = function(event) {
- event.preventDefault();
- return this.activateTab($(event.target).data('action'));
- };
-
- MergeRequestTabs.prototype.tabShown = function(event) {
- var $target, action, navBarHeight;
- $target = $(event.target);
- action = $target.data('action');
- if (action === 'commits') {
- this.loadCommits($target.attr('href'));
- this.expandView();
- this.resetViewContainer();
- } else if (this.isDiffAction(action)) {
- this.loadDiff($target.attr('href'));
- if ((typeof bp !== "undefined" && bp !== null) && bp.getBreakpointSize() !== 'lg') {
- this.shrinkView();
- }
- if (this.diffViewType() === 'parallel') {
- this.expandViewContainer();
- }
- navBarHeight = $('.navbar-gitlab').outerHeight();
- $.scrollTo(".merge-request-details .merge-request-tabs", {
- offset: -navBarHeight
- });
- } else if (action === 'builds') {
- this.loadBuilds($target.attr('href'));
- this.expandView();
- this.resetViewContainer();
- } else if (action === 'pipelines') {
- this.loadPipelines($target.attr('href'));
- this.expandView();
- this.resetViewContainer();
- } else {
- this.expandView();
- this.resetViewContainer();
- }
- if (this.opts.setUrl) {
- this.setCurrentAction(action);
- }
- };
-
- MergeRequestTabs.prototype.scrollToElement = function(container) {
- var $el, navBarHeight;
- if (window.location.hash) {
- navBarHeight = $('.navbar-gitlab').outerHeight() + $('.layout-nav').outerHeight() + document.querySelector('.js-tabs-affix').offsetHeight;
- $el = $(container + " " + window.location.hash + ":not(.match)");
- if ($el.length) {
- return $.scrollTo(container + " " + window.location.hash + ":not(.match)", {
- offset: -navBarHeight
- });
- }
- }
- };
-
- // Activate a tab based on the current action
- MergeRequestTabs.prototype.activateTab = function(action) {
- if (action === 'show') {
- action = 'notes';
- }
- // important note: the .tab('show') method triggers 'shown.bs.tab' event itself
- $(".merge-request-tabs a[data-action='" + action + "']").tab('show');
- };
-
- // Replaces the current Merge Request-specific action in the URL with a new one
- //
- // If the action is "notes", the URL is reset to the standard
- // `MergeRequests#show` route.
- //
- // Examples:
- //
- // location.pathname # => "/namespace/project/merge_requests/1"
- // setCurrentAction('diffs')
- // location.pathname # => "/namespace/project/merge_requests/1/diffs"
- //
- // location.pathname # => "/namespace/project/merge_requests/1/diffs"
- // setCurrentAction('notes')
- // location.pathname # => "/namespace/project/merge_requests/1"
- //
- // location.pathname # => "/namespace/project/merge_requests/1/diffs"
- // setCurrentAction('commits')
- // location.pathname # => "/namespace/project/merge_requests/1/commits"
- //
- // Returns the new URL String
- MergeRequestTabs.prototype.setCurrentAction = function(action) {
- var new_state;
- // Normalize action, just to be safe
- if (action === 'show') {
- action = 'notes';
- }
- this.currentAction = action;
- // Remove a trailing '/commits' '/diffs' '/builds' '/pipelines' '/new' '/new/diffs'
- new_state = this._location.pathname.replace(/\/(commits|diffs|builds|pipelines|new|new\/diffs)(\.html)?\/?$/, '');
-
- // Append the new action if we're on a tab other than 'notes'
- if (action !== 'notes') {
- new_state += "/" + action;
- }
- // Ensure parameters and hash come along for the ride
- new_state += this._location.search + this._location.hash;
- history.replaceState({
- turbolinks: true,
- url: new_state
- // Replace the current history state with the new one without breaking
- // Turbolinks' history.
- //
- // See https://github.com/rails/turbolinks/issues/363
- }, document.title, new_state);
- return new_state;
- };
-
- MergeRequestTabs.prototype.loadCommits = function(source) {
- if (this.commitsLoaded) {
- return;
- }
- return this._get({
- url: source + ".json",
- success: (function(_this) {
- return function(data) {
- document.querySelector("div#commits").innerHTML = data.html;
- gl.utils.localTimeAgo($('.js-timeago', 'div#commits'));
- _this.commitsLoaded = true;
- return _this.scrollToElement("#commits");
- };
- })(this)
- });
- };
-
- MergeRequestTabs.prototype.loadDiff = function(source) {
- if (this.diffsLoaded) {
- return;
- }
-
- // We extract pathname for the current Changes tab anchor href
- // some pages like MergeRequestsController#new has query parameters on that anchor
- var url = gl.utils.parseUrl(source);
-
- return this._get({
- url: (url.pathname + ".json") + this._location.search,
- success: (function(_this) {
- return function(data) {
- $('#diffs').html(data.html);
-
- if (typeof gl.diffNotesCompileComponents !== 'undefined') {
- gl.diffNotesCompileComponents();
- }
-
- gl.utils.localTimeAgo($('.js-timeago', 'div#diffs'));
- $('#diffs .js-syntax-highlight').syntaxHighlight();
- $('#diffs .diff-file').singleFileDiff();
- if (_this.diffViewType() === 'parallel' && (_this.isDiffAction(_this.currentAction)) ) {
- _this.expandViewContainer();
- }
- _this.diffsLoaded = true;
- var anchoredDiff = gl.utils.getLocationHash();
- if (anchoredDiff) _this.openAnchoredDiff(anchoredDiff, function() {
- _this.scrollToElement("#diffs");
- _this.highlighSelectedLine();
- });
- _this.filesCommentButton = $('.files .diff-file').filesCommentButton();
- return $(document).off('click', '.diff-line-num a').on('click', '.diff-line-num a', function(e) {
- e.preventDefault();
- window.location.hash = $(e.currentTarget).attr('href');
- _this.highlighSelectedLine();
- return _this.scrollToElement("#diffs");
- });
- };
- })(this)
- });
- };
-
- MergeRequestTabs.prototype.openAnchoredDiff = function(anchoredDiff, cb) {
- var diffTitle = $('#file-path-' + anchoredDiff);
- var diffFile = diffTitle.closest('.diff-file');
- var nothingHereBlock = $('.nothing-here-block:visible', diffFile);
- if (nothingHereBlock.length) {
- diffFile.singleFileDiff(true, cb);
- } else {
- cb();
- }
- };
-
- MergeRequestTabs.prototype.highlighSelectedLine = function() {
- var $diffLine, diffLineTop, hashClassString, locationHash, navBarHeight;
- $('.hll').removeClass('hll');
- locationHash = window.location.hash;
- if (locationHash !== '') {
- dataLineString = '[data-line-code="' + locationHash.replace('#', '') + '"]';
- $diffLine = $(locationHash + ":not(.match)", $('#diffs'));
- if (!$diffLine.is('tr')) {
- $diffLine = $('#diffs').find("td" + locationHash + ", td" + dataLineString);
- } else {
- $diffLine = $diffLine.find('td');
- }
- if ($diffLine.length) {
- $diffLine.addClass('hll');
- diffLineTop = $diffLine.offset().top;
- return navBarHeight = $('.navbar-gitlab').outerHeight();
- }
- }
- };
-
- MergeRequestTabs.prototype.loadBuilds = function(source) {
- if (this.buildsLoaded) {
- return;
- }
- return this._get({
- url: source + ".json",
- success: (function(_this) {
- return function(data) {
- document.querySelector("div#builds").innerHTML = data.html;
- gl.utils.localTimeAgo($('.js-timeago', 'div#builds'));
- _this.buildsLoaded = true;
- if (!this.pipelines) this.pipelines = new gl.Pipelines();
- return _this.scrollToElement("#builds");
- };
- })(this)
- });
- };
-
- MergeRequestTabs.prototype.loadPipelines = function(source) {
- if (this.pipelinesLoaded) {
- return;
- }
- return this._get({
- url: source + ".json",
- success: function(data) {
- $('#pipelines').html(data.html);
- gl.utils.localTimeAgo($('.js-timeago', '#pipelines'));
- this.pipelinesLoaded = true;
- return this.scrollToElement("#pipelines");
- }.bind(this)
- });
- };
-
- // Show or hide the loading spinner
- //
- // status - Boolean, true to show, false to hide
- MergeRequestTabs.prototype.toggleLoading = function(status) {
- return $('.mr-loading-status .loading').toggle(status);
- };
-
- MergeRequestTabs.prototype._get = function(options) {
- var defaults;
- defaults = {
- beforeSend: (function(_this) {
- return function() {
- return _this.toggleLoading(true);
- };
- })(this),
- complete: (function(_this) {
- return function() {
- return _this.toggleLoading(false);
- };
- })(this),
- dataType: 'json',
- type: 'GET'
- };
- options = $.extend({}, defaults, options);
- return $.ajax(options);
- };
-
- MergeRequestTabs.prototype.diffViewType = function() {
- return $('.inline-parallel-buttons a.active').data('view-type');
- };
-
- MergeRequestTabs.prototype.isDiffAction = function(action) {
- return action === 'diffs' || action === 'new/diffs'
- };
-
- MergeRequestTabs.prototype.expandViewContainer = function() {
- var $wrapper = $('.content-wrapper .container-fluid');
- if (this.fixedLayoutPref === null) {
- this.fixedLayoutPref = $wrapper.hasClass('container-limited');
- }
- $wrapper.removeClass('container-limited');
- };
-
- MergeRequestTabs.prototype.resetViewContainer = function() {
- if (this.fixedLayoutPref !== null) {
- $('.content-wrapper .container-fluid')
- .toggleClass('container-limited', this.fixedLayoutPref);
- }
- };
-
- MergeRequestTabs.prototype.shrinkView = function() {
- var $gutterIcon;
- $gutterIcon = $('.js-sidebar-toggle i:visible');
- return setTimeout(function() {
- if ($gutterIcon.is('.fa-angle-double-right')) {
- return $gutterIcon.closest('a').trigger('click', [true]);
- }
- // Wait until listeners are set
- // Only when sidebar is expanded
- }, 0);
- };
-
- MergeRequestTabs.prototype.expandView = function() {
- var $gutterIcon;
- if (Cookies.get('collapsed_gutter') === 'true') {
- return;
- }
- $gutterIcon = $('.js-sidebar-toggle i:visible');
- return setTimeout(function() {
- if ($gutterIcon.is('.fa-angle-double-left')) {
- return $gutterIcon.closest('a').trigger('click', [true]);
- }
- }, 0);
- // Expand the issuable sidebar unless the user explicitly collapsed it
- // Wait until listeners are set
- // Only when sidebar is collapsed
- };
-
- MergeRequestTabs.prototype.initAffix = function () {
- var $tabs = $('.js-tabs-affix');
-
- // Screen space on small screens is usually very sparse
- // So we dont affix the tabs on these
- if (Breakpoints.get().getBreakpointSize() === 'xs' || !$tabs.length) return;
-
- var $diffTabs = $('#diff-notes-app'),
- $fixedNav = $('.navbar-fixed-top'),
- $layoutNav = $('.layout-nav');
-
- $tabs.off('affix.bs.affix affix-top.bs.affix')
- .affix({
- offset: {
- top: function () {
- var tabsTop = $diffTabs.offset().top - $tabs.height();
- tabsTop = tabsTop - ($fixedNav.height() + $layoutNav.height());
-
- return tabsTop;
- }
- }
- }).on('affix.bs.affix', function () {
- $diffTabs.css({
- marginTop: $tabs.height()
- });
- }).on('affix-top.bs.affix', function () {
- $diffTabs.css({
- marginTop: ''
- });
- });
-
- // Fix bug when reloading the page already scrolling
- if ($tabs.hasClass('affix')) {
- $tabs.trigger('affix.bs.affix');
- }
- };
-
- return MergeRequestTabs;
-
- })();
-
-}).call(this);
diff --git a/app/assets/javascripts/merge_request_tabs.js.es6 b/app/assets/javascripts/merge_request_tabs.js.es6
new file mode 100644
index 00000000000..3ec0f1fd613
--- /dev/null
+++ b/app/assets/javascripts/merge_request_tabs.js.es6
@@ -0,0 +1,389 @@
+/* eslint-disable no-new, class-methods-use-this */
+/* global Breakpoints */
+/* global Cookies */
+/* global DiffNotesApp */
+/* global Flash */
+
+/*= require js.cookie */
+/*= require breakpoints */
+
+/* eslint-disable max-len */
+// MergeRequestTabs
+//
+// Handles persisting and restoring the current tab selection and lazily-loading
+// content on the MergeRequests#show page.
+//
+// ### Example Markup
+//
+// <ul class="nav-links merge-request-tabs">
+// <li class="notes-tab active">
+// <a data-action="notes" data-target="#notes" data-toggle="tab" href="/foo/bar/merge_requests/1">
+// Discussion
+// </a>
+// </li>
+// <li class="commits-tab">
+// <a data-action="commits" data-target="#commits" data-toggle="tab" href="/foo/bar/merge_requests/1/commits">
+// Commits
+// </a>
+// </li>
+// <li class="diffs-tab">
+// <a data-action="diffs" data-target="#diffs" data-toggle="tab" href="/foo/bar/merge_requests/1/diffs">
+// Diffs
+// </a>
+// </li>
+// </ul>
+//
+// <div class="tab-content">
+// <div class="notes tab-pane active" id="notes">
+// Notes Content
+// </div>
+// <div class="commits tab-pane" id="commits">
+// Commits Content
+// </div>
+// <div class="diffs tab-pane" id="diffs">
+// Diffs Content
+// </div>
+// </div>
+//
+// <div class="mr-loading-status">
+// <div class="loading">
+// Loading Animation
+// </div>
+// </div>
+//
+/* eslint-enable max-len */
+
+(() => {
+ // Store the `location` object, allowing for easier stubbing in tests
+ let location = window.location;
+
+ class MergeRequestTabs {
+
+ constructor({ action, setUrl, buildsLoaded, stubLocation } = {}) {
+ this.diffsLoaded = false;
+ this.buildsLoaded = false;
+ this.pipelinesLoaded = false;
+ this.commitsLoaded = false;
+ this.fixedLayoutPref = null;
+
+ this.setUrl = setUrl !== undefined ? setUrl : true;
+ this.buildsLoaded = buildsLoaded || false;
+
+ this.setCurrentAction = this.setCurrentAction.bind(this);
+ this.tabShown = this.tabShown.bind(this);
+ this.showTab = this.showTab.bind(this);
+
+ if (stubLocation) {
+ location = stubLocation;
+ }
+
+ this.bindEvents();
+ this.activateTab(action);
+ this.initAffix();
+ }
+
+ bindEvents() {
+ $(document)
+ .on('shown.bs.tab', '.merge-request-tabs a[data-toggle="tab"]', this.tabShown)
+ .on('click', '.js-show-tab', this.showTab);
+ }
+
+ unbindEvents() {
+ $(document)
+ .off('shown.bs.tab', '.merge-request-tabs a[data-toggle="tab"]', this.tabShown)
+ .off('click', '.js-show-tab', this.showTab);
+ }
+
+ showTab(e) {
+ e.preventDefault();
+ this.activateTab($(e.target).data('action'));
+ }
+
+ tabShown(e) {
+ const $target = $(e.target);
+ const action = $target.data('action');
+
+ if (action === 'commits') {
+ this.loadCommits($target.attr('href'));
+ this.expandView();
+ this.resetViewContainer();
+ } else if (this.isDiffAction(action)) {
+ this.loadDiff($target.attr('href'));
+ if (Breakpoints.get().getBreakpointSize() !== 'lg') {
+ this.shrinkView();
+ }
+ if (this.diffViewType() === 'parallel') {
+ this.expandViewContainer();
+ }
+ const navBarHeight = $('.navbar-gitlab').outerHeight();
+ $.scrollTo('.merge-request-details .merge-request-tabs', {
+ offset: -navBarHeight,
+ });
+ } else if (action === 'builds') {
+ this.loadBuilds($target.attr('href'));
+ this.expandView();
+ this.resetViewContainer();
+ } else if (action === 'pipelines') {
+ this.loadPipelines($target.attr('href'));
+ this.expandView();
+ this.resetViewContainer();
+ } else {
+ this.expandView();
+ this.resetViewContainer();
+ }
+ if (this.setUrl) {
+ this.setCurrentAction(action);
+ }
+ }
+
+ scrollToElement(container) {
+ if (location.hash) {
+ const offset = 0 - (
+ $('.navbar-gitlab').outerHeight() +
+ $('.layout-nav').outerHeight() +
+ $('.js-tabs-affix').outerHeight()
+ );
+ const $el = $(`${container} ${location.hash}:not(.match)`);
+ if ($el.length) {
+ $.scrollTo($el[0], { offset });
+ }
+ }
+ }
+
+ // Activate a tab based on the current action
+ activateTab(action) {
+ const activate = action === 'show' ? 'notes' : action;
+ // important note: the .tab('show') method triggers 'shown.bs.tab' event itself
+ $(`.merge-request-tabs a[data-action='${activate}']`).tab('show');
+ }
+
+ // Replaces the current Merge Request-specific action in the URL with a new one
+ //
+ // If the action is "notes", the URL is reset to the standard
+ // `MergeRequests#show` route.
+ //
+ // Examples:
+ //
+ // location.pathname # => "/namespace/project/merge_requests/1"
+ // setCurrentAction('diffs')
+ // location.pathname # => "/namespace/project/merge_requests/1/diffs"
+ //
+ // location.pathname # => "/namespace/project/merge_requests/1/diffs"
+ // setCurrentAction('notes')
+ // location.pathname # => "/namespace/project/merge_requests/1"
+ //
+ // location.pathname # => "/namespace/project/merge_requests/1/diffs"
+ // setCurrentAction('commits')
+ // location.pathname # => "/namespace/project/merge_requests/1/commits"
+ //
+ // Returns the new URL String
+ setCurrentAction(action) {
+ this.currentAction = action === 'show' ? 'notes' : action;
+
+ // Remove a trailing '/commits' '/diffs' '/builds' '/pipelines' '/new' '/new/diffs'
+ let newState = location.pathname.replace(/\/(commits|diffs|builds|pipelines|new|new\/diffs)(\.html)?\/?$/, '');
+
+ // Append the new action if we're on a tab other than 'notes'
+ if (this.currentAction !== 'notes') {
+ newState += `/${this.currentAction}`;
+ }
+
+ // Ensure parameters and hash come along for the ride
+ newState += location.search + location.hash;
+
+ // Replace the current history state with the new one without breaking
+ // Turbolinks' history.
+ //
+ // See https://github.com/rails/turbolinks/issues/363
+ window.history.replaceState({
+ turbolinks: true,
+ url: newState,
+ }, document.title, newState);
+
+ return newState;
+ }
+
+ loadCommits(source) {
+ if (this.commitsLoaded) {
+ return;
+ }
+ this.ajaxGet({
+ url: `${source}.json`,
+ success: (data) => {
+ document.querySelector('div#commits').innerHTML = data.html;
+ gl.utils.localTimeAgo($('.js-timeago', 'div#commits'));
+ this.commitsLoaded = true;
+ this.scrollToElement('#commits');
+ },
+ });
+ }
+
+ loadDiff(source) {
+ if (this.diffsLoaded) {
+ return;
+ }
+
+ // We extract pathname for the current Changes tab anchor href
+ // some pages like MergeRequestsController#new has query parameters on that anchor
+ const urlPathname = gl.utils.parseUrlPathname(source);
+
+ this.ajaxGet({
+ url: `${urlPathname}.json${location.search}`,
+ success: (data) => {
+ $('#diffs').html(data.html);
+
+ if (typeof gl.diffNotesCompileComponents !== 'undefined') {
+ gl.diffNotesCompileComponents();
+ }
+
+ gl.utils.localTimeAgo($('.js-timeago', 'div#diffs'));
+ $('#diffs .js-syntax-highlight').syntaxHighlight();
+
+ if (this.diffViewType() === 'parallel' && this.isDiffAction(this.currentAction)) {
+ this.expandViewContainer();
+ }
+ this.diffsLoaded = true;
+
+ const diffPage = new gl.Diff();
+
+ const locationHash = gl.utils.getLocationHash();
+ const anchoredDiff = locationHash && locationHash.split('_')[0];
+ if (anchoredDiff) {
+ diffPage.openAnchoredDiff(anchoredDiff, () => this.scrollToElement('#diffs'));
+ }
+ },
+ });
+ }
+
+ loadBuilds(source) {
+ if (this.buildsLoaded) {
+ return;
+ }
+ this.ajaxGet({
+ url: `${source}.json`,
+ success: (data) => {
+ document.querySelector('div#builds').innerHTML = data.html;
+ gl.utils.localTimeAgo($('.js-timeago', 'div#builds'));
+ this.buildsLoaded = true;
+ new gl.Pipelines();
+ this.scrollToElement('#builds');
+ },
+ });
+ }
+
+ loadPipelines(source) {
+ if (this.pipelinesLoaded) {
+ return;
+ }
+ this.ajaxGet({
+ url: `${source}.json`,
+ success: (data) => {
+ $('#pipelines').html(data.html);
+ gl.utils.localTimeAgo($('.js-timeago', '#pipelines'));
+ this.pipelinesLoaded = true;
+ this.scrollToElement('#pipelines');
+ },
+ });
+ }
+
+ // Show or hide the loading spinner
+ //
+ // status - Boolean, true to show, false to hide
+ toggleLoading(status) {
+ $('.mr-loading-status .loading').toggle(status);
+ }
+
+ ajaxGet(options) {
+ const defaults = {
+ beforeSend: () => this.toggleLoading(true),
+ error: () => new Flash('An error occurred while fetching this tab.', 'alert'),
+ complete: () => this.toggleLoading(false),
+ dataType: 'json',
+ type: 'GET',
+ };
+ $.ajax($.extend({}, defaults, options));
+ }
+
+ diffViewType() {
+ return $('.inline-parallel-buttons a.active').data('view-type');
+ }
+
+ isDiffAction(action) {
+ return action === 'diffs' || action === 'new/diffs';
+ }
+
+ expandViewContainer() {
+ const $wrapper = $('.content-wrapper .container-fluid');
+ if (this.fixedLayoutPref === null) {
+ this.fixedLayoutPref = $wrapper.hasClass('container-limited');
+ }
+ $wrapper.removeClass('container-limited');
+ }
+
+ resetViewContainer() {
+ if (this.fixedLayoutPref !== null) {
+ $('.content-wrapper .container-fluid')
+ .toggleClass('container-limited', this.fixedLayoutPref);
+ }
+ }
+
+ shrinkView() {
+ const $gutterIcon = $('.js-sidebar-toggle i:visible');
+
+ // Wait until listeners are set
+ setTimeout(() => {
+ // Only when sidebar is expanded
+ if ($gutterIcon.is('.fa-angle-double-right')) {
+ $gutterIcon.closest('a').trigger('click', [true]);
+ }
+ }, 0);
+ }
+
+ // Expand the issuable sidebar unless the user explicitly collapsed it
+ expandView() {
+ if (Cookies.get('collapsed_gutter') === 'true') {
+ return;
+ }
+ const $gutterIcon = $('.js-sidebar-toggle i:visible');
+
+ // Wait until listeners are set
+ setTimeout(() => {
+ // Only when sidebar is collapsed
+ if ($gutterIcon.is('.fa-angle-double-left')) {
+ $gutterIcon.closest('a').trigger('click', [true]);
+ }
+ }, 0);
+ }
+
+ initAffix() {
+ const $tabs = $('.js-tabs-affix');
+
+ // Screen space on small screens is usually very sparse
+ // So we dont affix the tabs on these
+ if (Breakpoints.get().getBreakpointSize() === 'xs' || !$tabs.length) return;
+
+ const $diffTabs = $('#diff-notes-app');
+ const $fixedNav = $('.navbar-fixed-top');
+ const $layoutNav = $('.layout-nav');
+
+ $tabs.off('affix.bs.affix affix-top.bs.affix')
+ .affix({
+ offset: {
+ top: () => (
+ $diffTabs.offset().top - $tabs.height() - $fixedNav.height() - $layoutNav.height()
+ ),
+ },
+ })
+ .on('affix.bs.affix', () => $diffTabs.css({ marginTop: $tabs.height() }))
+ .on('affix-top.bs.affix', () => $diffTabs.css({ marginTop: '' }));
+
+ // Fix bug when reloading the page already scrolling
+ if ($tabs.hasClass('affix')) {
+ $tabs.trigger('affix.bs.affix');
+ }
+ }
+ }
+
+ window.gl = window.gl || {};
+ window.gl.MergeRequestTabs = MergeRequestTabs;
+})();
diff --git a/app/assets/javascripts/single_file_diff.js b/app/assets/javascripts/single_file_diff.js
index 2767849e673..0d48e69cce9 100644
--- a/app/assets/javascripts/single_file_diff.js
+++ b/app/assets/javascripts/single_file_diff.js
@@ -14,6 +14,7 @@
COLLAPSED_HTML = '<div class="nothing-here-block diff-collapsed">This diff is collapsed. <a class="click-to-expand">Click to expand it.</a></div>';
function SingleFileDiff(file, forceLoad, cb) {
+ var clickTarget;
this.file = file;
this.toggleDiff = bind(this.toggleDiff, this);
this.content = $('.diff-content', this.file);
@@ -31,9 +32,9 @@
this.content.after(this.collapsedContent);
this.$toggleIcon.addClass('fa-caret-down');
}
- $('.file-title, .click-to-expand', this.file).on('click', this.toggleDiff);
+ clickTarget = $('.file-title, .click-to-expand', this.file).on('click', this.toggleDiff);
if (forceLoad) {
- this.toggleDiff(null, cb);
+ this.toggleDiff({ target: clickTarget }, cb);
}
}
diff --git a/app/assets/javascripts/vue_common_component/commit.js.es6 b/app/assets/javascripts/vue_common_component/commit.js.es6
index 1bc68c1ba2f..2ef2959cbf4 100644
--- a/app/assets/javascripts/vue_common_component/commit.js.es6
+++ b/app/assets/javascripts/vue_common_component/commit.js.es6
@@ -23,7 +23,7 @@
* name
* ref_url
*/
- ref: {
+ commit_ref: {
type: Object,
required: false,
default: () => ({}),
@@ -79,8 +79,8 @@
*
* @returns {Boolean}
*/
- hasRef() {
- return this.ref && this.ref.name && this.ref.ref_url;
+ hasCommitRef() {
+ return this.commit_ref && this.commit_ref.name && this.commit_ref.ref_url;
},
/**
@@ -131,15 +131,15 @@
template: `
<div class="branch-commit">
- <div v-if="hasRef" class="icon-container">
+ <div v-if="hasCommitRef" class="icon-container">
<i v-if="tag" class="fa fa-tag"></i>
<i v-if="!tag" class="fa fa-code-fork"></i>
</div>
- <a v-if="hasRef"
+ <a v-if="hasCommitRef"
class="monospace branch-name"
- :href="ref.ref_url">
- {{ref.name}}
+ :href="commit_ref.ref_url">
+ {{commit_ref.name}}
</a>
<div class="icon-container commit-icon commit-icon-container"></div>
diff --git a/app/assets/stylesheets/framework.scss b/app/assets/stylesheets/framework.scss
index 7c7f991dd87..4d4835568ed 100644
--- a/app/assets/stylesheets/framework.scss
+++ b/app/assets/stylesheets/framework.scss
@@ -1,4 +1,3 @@
-@import "framework/fonts";
@import "framework/variables";
@import "framework/mixins";
@import 'framework/tw_bootstrap_variables';
@@ -41,3 +40,6 @@
@import "framework/blank";
@import "framework/wells.scss";
@import "framework/page-header.scss";
+@import "framework/awards.scss";
+@import "framework/images.scss";
+@import "framework/broadcast-messages";
diff --git a/app/assets/stylesheets/framework/avatar.scss b/app/assets/stylesheets/framework/avatar.scss
index c0dd1cb3667..000e591e09c 100644
--- a/app/assets/stylesheets/framework/avatar.scss
+++ b/app/assets/stylesheets/framework/avatar.scss
@@ -8,7 +8,7 @@
float: left;
margin-right: 15px;
border-radius: $avatar_radius;
- border: 1px solid rgba(0, 0, 0, .1);
+ border: 1px solid $avatar-border;
&.s16 { @include avatar-size(16px, 6px); }
&.s20 { @include avatar-size(20px, 7px); }
&.s24 { @include avatar-size(24px, 8px); }
diff --git a/app/assets/stylesheets/pages/awards.scss b/app/assets/stylesheets/framework/awards.scss
index 486ad16ea26..c13cb4a02b2 100644
--- a/app/assets/stylesheets/pages/awards.scss
+++ b/app/assets/stylesheets/framework/awards.scss
@@ -15,7 +15,7 @@
background-color: $award-emoji-menu-bg;
border: 1px solid $award-emoji-menu-border;
border-radius: $border-radius-base;
- box-shadow: 0 6px 12px rgba(0,0,0,.175);
+ box-shadow: 0 6px 12px $award-emoji-menu-shadow;
pointer-events: none;
opacity: 0;
transform: scale(.2);
@@ -127,7 +127,7 @@
.award-control-icon {
float: left;
margin-right: 5px;
- font-size: 19px;
+ font-size: 18px;
}
.award-control-icon-loading {
diff --git a/app/assets/stylesheets/framework/blank.scss b/app/assets/stylesheets/framework/blank.scss
index 540718197e0..a2fa2e7769b 100644
--- a/app/assets/stylesheets/framework/blank.scss
+++ b/app/assets/stylesheets/framework/blank.scss
@@ -32,14 +32,14 @@
.blank-state-title {
margin-top: 0;
margin-bottom: 5px;
- font-size: 19px;
+ font-size: 18px;
font-weight: normal;
}
.blank-state-text {
margin-top: 0;
margin-bottom: $gl-padding;
- font-size: 15px;
+ font-size: 14px;
> strong {
font-weight: 600;
diff --git a/app/assets/stylesheets/framework/blocks.scss b/app/assets/stylesheets/framework/blocks.scss
index 77ae9e9a6e7..95c02499271 100644
--- a/app/assets/stylesheets/framework/blocks.scss
+++ b/app/assets/stylesheets/framework/blocks.scss
@@ -1,8 +1,3 @@
-.light-well {
- background-color: $background-color;
- padding: 15px;
-}
-
.centered-light-block {
text-align: center;
color: $gl-gray;
@@ -41,7 +36,7 @@
}
&.white {
- background-color: white;
+ background-color: $white-light;
}
&.top-block {
@@ -158,7 +153,7 @@
p {
padding: 0 $gl-padding;
- color: #5c5d5e;
+ color: $gl-text-color-dark;
}
}
@@ -274,6 +269,10 @@
}
}
+ .emoji-icon {
+ display: inline-block;
+ }
+
@media(max-width: $screen-xs-max) {
margin-top: 50px;
text-align: center;
diff --git a/app/assets/stylesheets/framework/broadcast-messages.scss b/app/assets/stylesheets/framework/broadcast-messages.scss
new file mode 100644
index 00000000000..9b54fb94cdc
--- /dev/null
+++ b/app/assets/stylesheets/framework/broadcast-messages.scss
@@ -0,0 +1,21 @@
+.broadcast-message {
+ @extend .alert-warning;
+ padding: 10px;
+ text-align: center;
+
+ div,
+ p {
+ display: inline;
+ margin: 0;
+
+ a {
+ color: inherit;
+ text-decoration: underline;
+ }
+ }
+}
+
+.broadcast-message-preview {
+ @extend .broadcast-message;
+ margin-bottom: 20px;
+}
diff --git a/app/assets/stylesheets/framework/buttons.scss b/app/assets/stylesheets/framework/buttons.scss
index 36f530af685..8da3da2ad08 100644
--- a/app/assets/stylesheets/framework/buttons.scss
+++ b/app/assets/stylesheets/framework/buttons.scss
@@ -68,23 +68,23 @@
}
@mixin btn-green {
- @include btn-color($green-light, $border-green-light, $green-normal, $border-green-normal, $green-dark, $border-green-dark, #fff);
+ @include btn-color($green-light, $border-green-light, $green-normal, $border-green-normal, $green-dark, $border-green-dark, $white-light);
}
@mixin btn-blue {
- @include btn-color($blue-light, $border-blue-light, $blue-normal, $border-blue-normal, $blue-dark, $border-blue-dark, #fff);
+ @include btn-color($blue-light, $border-blue-light, $blue-normal, $border-blue-normal, $blue-dark, $border-blue-dark, $white-light);
}
@mixin btn-blue-medium {
- @include btn-color($blue-medium-light, $border-blue-light, $blue-medium, $border-blue-normal, $blue-medium-dark, $border-blue-dark, #fff);
+ @include btn-color($blue-medium-light, $border-blue-light, $blue-medium, $border-blue-normal, $blue-medium-dark, $border-blue-dark, $white-light);
}
@mixin btn-orange {
- @include btn-color($orange-light, $border-orange-light, $orange-normal, $border-orange-normal, $orange-dark, $border-orange-dark, #fff);
+ @include btn-color($orange-light, $border-orange-light, $orange-normal, $border-orange-normal, $orange-dark, $border-orange-dark, $white-light);
}
@mixin btn-red {
- @include btn-color($red-light, $border-red-light, $red-normal, $border-red-normal, $red-dark, $border-red-dark, #fff);
+ @include btn-color($red-light, $border-red-light, $red-normal, $border-red-normal, $red-dark, $border-red-dark, $white-light);
}
@mixin btn-gray {
@@ -289,8 +289,8 @@
.active {
box-shadow: $gl-btn-active-background;
- border: 1px solid #c6cacf !important;
- background-color: #e4e7ed !important;
+ border: 1px solid $border-white-dark !important;
+ background-color: $btn-active-gray-light !important;
}
}
@@ -345,13 +345,13 @@
.btn-static {
background-color: $background-color !important;
- border: 1px solid lightgrey;
+ border: 1px solid $border-gray-light;
cursor: default;
&:active {
- -moz-box-shadow: inset 0 0 0 white;
- -webkit-box-shadow: inset 0 0 0 white;
- box-shadow: inset 0 0 0 white;
+ -moz-box-shadow: inset 0 0 0 $white-light;
+ -webkit-box-shadow: inset 0 0 0 $white-light;
+ box-shadow: inset 0 0 0 $white-light;
}
}
diff --git a/app/assets/stylesheets/framework/calendar.scss b/app/assets/stylesheets/framework/calendar.scss
index 81852158b94..ef921a8c6a9 100644
--- a/app/assets/stylesheets/framework/calendar.scss
+++ b/app/assets/stylesheets/framework/calendar.scss
@@ -28,13 +28,13 @@
.user-contrib-cell {
&:hover {
cursor: pointer;
- stroke: #000;
+ stroke: $black;
}
}
.user-contrib-text {
font-size: 12px;
- fill: #959494;
+ fill: $calendar-user-contrib-text;
}
.calendar-hint {
diff --git a/app/assets/stylesheets/framework/callout.scss b/app/assets/stylesheets/framework/callout.scss
index f3b6ad88ad6..2a100980aca 100644
--- a/app/assets/stylesheets/framework/callout.scss
+++ b/app/assets/stylesheets/framework/callout.scss
@@ -25,25 +25,25 @@
/* Variations */
.bs-callout-danger {
- background-color: #fdf7f7;
- border-color: #eed3d7;
- color: #b94a48;
+ background-color: $callout-danger-bg;
+ border-color: $callout-danger-border;
+ color: $callout-danger-color;
}
.bs-callout-warning {
- background-color: #faf8f0;
- border-color: #faebcc;
- color: #8a6d3b;
+ background-color: $callout-warning-bg;
+ border-color: $callout-warning-border;
+ color: $callout-warning-color;
}
.bs-callout-info {
- background-color: #f4f8fa;
- border-color: #bce8f1;
- color: #34789a;
+ background-color: $callout-info-bg;
+ border-color: $callout-info-border;
+ color: $callout-info-color;
}
.bs-callout-success {
- background-color: #dff0d8;
- border-color: #5ca64d;
- color: #3c763d;
+ background-color: $callout-success-bg;
+ border-color: $callout-success-border;
+ color: $callout-success-color;
}
diff --git a/app/assets/stylesheets/framework/common.scss b/app/assets/stylesheets/framework/common.scss
index b24fce6f0c2..600bf17259b 100644
--- a/app/assets/stylesheets/framework/common.scss
+++ b/app/assets/stylesheets/framework/common.scss
@@ -1,9 +1,9 @@
/** COLORS **/
-.cgray { color: $gl-gray; }
-.clgray { color: #bbb; }
-.cred { color: $gl-text-red; }
-.cgreen { color: $gl-text-green; }
-.cdark { color: #444; }
+.cgray { color: $common-gray; }
+.clgray { color: $common-gray-light; }
+.cred { color: $common-red; }
+.cgreen { color: $common-green; }
+.cdark { color: $common-gray-dark; }
/** COMMON CLASSES **/
.prepend-top-0 { margin-top: 0; }
@@ -28,12 +28,12 @@
.center { text-align: center; }
.underlined-link { text-decoration: underline; }
-.hint { font-style: italic; color: #999; }
-.light { color: $gl-gray; }
+.hint { font-style: italic; color: $hint-color; }
+.light { color: $common-gray; }
.slead {
- color: $gl-gray;
- font-size: 15px;
+ color: $common-gray;
+ font-size: 14px;
margin-bottom: 12px;
font-weight: normal;
line-height: 24px;
@@ -52,10 +52,10 @@ pre {
}
&.well-pre {
- border: 1px solid #eee;
+ border: 1px solid $well-pre-bg;
background: $gray-light;
border-radius: 0;
- color: #555;
+ color: $well-pre-color;
}
}
@@ -87,14 +87,14 @@ table a code {
.loading {
margin: 20px auto;
height: 40px;
- color: #555;
+ color: $loading-color;
font-size: 32px;
text-align: center;
}
span.update-author {
display: block;
- color: #999;
+ color: $update-author-color;
font-weight: normal;
font-style: italic;
@@ -105,7 +105,7 @@ span.update-author {
}
.user-mention {
- color: #2fa0bb;
+ color: $user-mention-color;
font-weight: bold;
}
@@ -114,7 +114,7 @@ span.update-author {
}
p.time {
- color: #999;
+ color: $time-color;
font-size: 90%;
margin: 30px 3px 3px 2px;
}
@@ -150,7 +150,7 @@ li.note {
.project_member_show {
td:first-child {
- color: #aaa;
+ color: $project-member-show-color;
}
}
@@ -176,7 +176,7 @@ li.note {
margin-top: 40px;
pre {
- background: white;
+ background: $white-light;
border: none;
font-size: 12px;
}
@@ -184,12 +184,12 @@ li.note {
.error-message {
padding: 10px;
- background: #c67;
+ background: $error-bg;
margin: 0;
- color: #fff;
+ color: $white-light;
a {
- color: #fff;
+ color: $white-light;
text-decoration: underline;
}
}
@@ -197,22 +197,22 @@ li.note {
.browser-alert {
padding: 10px;
text-align: center;
- background: #c67;
- color: #fff;
+ background: $error-bg;
+ color: $white-light;
font-weight: bold;
a {
- color: #fff;
+ color: $white-light;
text-decoration: underline;
}
}
.warning_message {
- border-left: 4px solid #ed9;
- color: #b90;
+ border-left: 4px solid $warning-message-border;
+ color: $warning-message-color;
padding: 10px;
margin-bottom: 10px;
- background: #ffffe6;
+ background: $warning-message-bg;
padding-left: 20px;
&.centered {
@@ -222,7 +222,7 @@ li.note {
.gitlab-promo {
a {
- color: #aaa;
+ color: $gl-promo-color;
margin-right: 30px;
}
}
@@ -245,7 +245,7 @@ li.note {
position: relative;
top: 2px;
left: 5px;
- color: #666;
+ color: $control-group-descr-color;
}
}
}
@@ -270,7 +270,7 @@ img.emoji {
table {
td.permission-x {
- background: #d9edf7 !important;
+ background: $table-permission-x-bg !important;
text-align: center;
}
}
@@ -323,13 +323,13 @@ table {
.username {
font-size: 18px;
- color: #666;
+ color: $username-color;
margin-top: 8px;
}
.description {
font-size: $gl-font-size;
- color: #666;
+ color: $description-color;
margin-top: 8px;
}
}
@@ -339,7 +339,7 @@ table {
.profiler-button,
.profiler-controls {
- border-color: #eee !important;
+ border-color: $profiler-border !important;
}
}
@@ -379,7 +379,9 @@ table {
border-top: 1px solid $border-color;
}
-.hide-bottom-border { border-bottom: none !important; }
+.hide-bottom-border {
+ border-bottom: none !important;
+}
.gl-accessibility {
&:focus {
@@ -396,3 +398,13 @@ table {
z-index: 1;
}
}
+
+.str-truncated {
+ &-60 {
+ @include str-truncated(60%);
+ }
+
+ &-100 {
+ @include str-truncated(100%);
+ }
+}
diff --git a/app/assets/stylesheets/framework/dropdowns.scss b/app/assets/stylesheets/framework/dropdowns.scss
index 6d77aadd753..33de652c06f 100644
--- a/app/assets/stylesheets/framework/dropdowns.scss
+++ b/app/assets/stylesheets/framework/dropdowns.scss
@@ -36,7 +36,7 @@
padding: 6px 8px 6px 10px;
background-color: $dropdown-toggle-bg;
color: $dropdown-toggle-color;
- font-size: 15px;
+ font-size: 14px;
text-align: left;
border: 1px solid $border-color;
border-radius: $border-radius-base;
@@ -123,7 +123,7 @@
width: 240px;
margin-top: 2px;
margin-bottom: 0;
- font-size: 15px;
+ font-size: 14px;
font-weight: normal;
padding: 8px 0;
background-color: $dropdown-bg;
@@ -376,7 +376,7 @@
position: absolute;
top: 10px;
right: 20px;
- color: #c7c7c7;
+ color: $dropdown-input-fa-color;
font-size: 12px;
pointer-events: none;
}
@@ -529,7 +529,7 @@
.ui-datepicker-calendar {
.ui-state-hover,
.ui-state-active {
- color: #fff;
+ color: $white-light;
border: 0;
}
}
@@ -589,7 +589,7 @@
.ui-datepicker-title {
color: $gl-gray;
- font-size: 15px;
+ font-size: 14px;
line-height: 1;
font-weight: normal;
}
diff --git a/app/assets/stylesheets/framework/files.scss b/app/assets/stylesheets/framework/files.scss
index f49d7b92a00..ab0b81f77f7 100644
--- a/app/assets/stylesheets/framework/files.scss
+++ b/app/assets/stylesheets/framework/files.scss
@@ -59,10 +59,10 @@
}
.file-content {
- background: #fff;
+ background: $white-light;
&.image_file {
- background: #eee;
+ background: $file-image-bg;
text-align: center;
img {
@@ -84,8 +84,8 @@
}
&.blob-no-preview {
- background: #eee;
- text-shadow: 0 1px 2px #fff;
+ background: $blob-bg;
+ text-shadow: 0 1px 2px $white-light;
padding: 100px 0;
}
@@ -99,7 +99,7 @@
}
tr {
- border-bottom: 1px solid #eee;
+ border-bottom: 1px solid $blame-border;
}
td {
@@ -120,7 +120,7 @@
td.line-numbers {
float: none;
- border-left: 1px solid #ddd;
+ border-left: 1px solid $blame-line-numbers-border;
i {
float: none;
@@ -134,7 +134,7 @@
}
&.logs {
- background: #eee;
+ background: $logs-bg;
max-height: 700px;
overflow-y: auto;
@@ -143,14 +143,14 @@
padding: 10px 0;
border-left: 1px solid $border-color;
margin-bottom: 0;
- background: white;
+ background: $white-light;
li {
- color: #888;
+ color: $logs-li-color;
p {
margin: 0;
- color: #333;
+ color: $logs-p-color;
line-height: 24px;
padding-left: 10px;
}
diff --git a/app/assets/stylesheets/framework/fonts.scss b/app/assets/stylesheets/framework/fonts.scss
deleted file mode 100644
index 5f9685bc71a..00000000000
--- a/app/assets/stylesheets/framework/fonts.scss
+++ /dev/null
@@ -1,45 +0,0 @@
-// Disabling "SpaceAfterPropertyColon" linter because the linter doesn't like
-// the way the `src` property is formatted in this file.
-// scss-lint:disable SpaceAfterPropertyColon
-
-/* latin-ext */
-@font-face {
- font-family: 'Source Sans Pro';
- font-style: normal;
- font-weight: 300;
- src:
- local('Source Sans Pro Light'),
- local('SourceSansPro-Light'),
- font-url('SourceSansPro-Light.ttf.woff2') format('woff2'),
- font-url('SourceSansPro-Light.ttf.woff') format('woff');
-}
-@font-face {
- font-family: 'Source Sans Pro';
- font-style: normal;
- font-weight: 400;
- src:
- local('Source Sans Pro'),
- local('SourceSansPro-Regular'),
- font-url('SourceSansPro-Regular.ttf.woff2') format('woff2'),
- font-url('SourceSansPro-Regular.ttf.woff') format('woff');
-}
-@font-face {
- font-family: 'Source Sans Pro';
- font-style: normal;
- font-weight: 600;
- src:
- local('Source Sans Pro Semibold'),
- local('SourceSansPro-Semibold'),
- font-url('SourceSansPro-Semibold.ttf.woff2') format('woff2'),
- font-url('SourceSansPro-Semibold.ttf.woff') format('woff');
-}
-@font-face {
- font-family: 'Source Sans Pro';
- font-style: normal;
- font-weight: 700;
- src:
- local('Source Sans Pro Bold'),
- local('SourceSansPro-Bold'),
- font-url('SourceSansPro-Bold.ttf.woff2') format('woff2'),
- font-url('SourceSansPro-Bold.ttf.woff') format('woff');
-}
diff --git a/app/assets/stylesheets/framework/forms.scss b/app/assets/stylesheets/framework/forms.scss
index a01899ccbd2..25a2b38baaa 100644
--- a/app/assets/stylesheets/framework/forms.scss
+++ b/app/assets/stylesheets/framework/forms.scss
@@ -7,9 +7,9 @@ input {
}
input[type='text'].danger {
- background: #f2dede!important;
- border-color: #d66;
- text-shadow: 0 1px 1px #fff;
+ background: $input-danger-bg !important;
+ border-color: $input-danger-border;
+ text-shadow: 0 1px 1px $white-light;
}
.datetime-controls {
@@ -159,7 +159,7 @@ label {
}
.input-group-addon {
- background-color: #f7f8fa;
+ background-color: $input-group-addon-bg;
}
.input-group-addon:not(:first-child):not(:last-child) {
@@ -181,7 +181,7 @@ label {
border: 1px solid $green-normal;
&:focus {
- box-shadow: 0 0 0 1px $green-normal inset, 0 1px 1px rgba(0, 0, 0, 0.075) inset, 0 0 4px 0 $green-normal;
+ box-shadow: 0 0 0 1px $green-normal inset, 0 1px 1px $gl-field-focus-shadow inset, 0 0 4px 0 $green-normal;
border: 0 none;
}
}
@@ -190,7 +190,7 @@ label {
border: 1px solid $red-normal;
&:focus {
- box-shadow: 0 0 0 1px $red-normal inset, 0 1px 1px rgba(0, 0, 0, 0.075) inset, 0 0 4px 0 rgba(210, 40, 82, 0.6);
+ box-shadow: 0 0 0 1px $red-normal inset, 0 1px 1px $gl-field-focus-shadow inset, 0 0 4px 0 $gl-field-focus-shadow-error;
border: 0 none;
}
}
diff --git a/app/assets/stylesheets/framework/gitlab-theme.scss b/app/assets/stylesheets/framework/gitlab-theme.scss
index c5e5dad574d..5cd242af91d 100644
--- a/app/assets/stylesheets/framework/gitlab-theme.scss
+++ b/app/assets/stylesheets/framework/gitlab-theme.scss
@@ -85,37 +85,57 @@
}
$theme-charcoal: #3d454d;
+$theme-charcoal-light: #485157;
$theme-charcoal-dark: #383f45;
$theme-charcoal-text: #b9bbbe;
+$theme-blue-light: #becde9;
$theme-blue: #2980b9;
+$theme-blue-dark: #1970a9;
+$theme-blue-darker: #096099;
+
+$theme-graphite-lighter: #ccc;
+$theme-graphite-light: #777;
$theme-graphite: #666;
+$theme-graphite-dark: #555;
+
+$theme-gray-light: #979797;
$theme-gray: #373737;
+$theme-gray-dark: #272727;
+$theme-gray-darker: #222;
+
+$theme-green-light: #adc;
$theme-green: #019875;
+$theme-green-dark: #018865;
+$theme-green-darker: #017855;
+
+$theme-violet-light: #98c;
$theme-violet: #548;
+$theme-violet-dark: #436;
+$theme-violet-darker: #325;
body {
&.ui_blue {
- @include gitlab-theme(#becde9, $theme-blue, #1970a9, #096099);
+ @include gitlab-theme($theme-blue-light, $theme-blue, $theme-blue-dark, $theme-blue-darker);
}
&.ui_charcoal {
- @include gitlab-theme($theme-charcoal-text, #485157, $theme-charcoal, $theme-charcoal-dark);
+ @include gitlab-theme($theme-charcoal-text, $theme-charcoal-light, $theme-charcoal, $theme-charcoal-dark);
}
&.ui_graphite {
- @include gitlab-theme(#ccc, #777, $theme-graphite, #555);
+ @include gitlab-theme($theme-graphite-lighter, $theme-graphite-light, $theme-graphite, $theme-graphite-dark);
}
&.ui_gray {
- @include gitlab-theme(#979797, $theme-gray, #272727, #222);
+ @include gitlab-theme($theme-gray-light, $theme-gray, $theme-gray-dark, $theme-gray-darker);
}
&.ui_green {
- @include gitlab-theme(#adc, $theme-green, #018865, #017855);
+ @include gitlab-theme($theme-green-light, $theme-green, $theme-green-dark, $theme-green-darker);
}
&.ui_violet {
- @include gitlab-theme(#98c, $theme-violet, #436, #325);
+ @include gitlab-theme($theme-violet-light, $theme-violet, $theme-violet-dark, $theme-violet-darker);
}
}
diff --git a/app/assets/stylesheets/framework/header.scss b/app/assets/stylesheets/framework/header.scss
index f9bcbbf2ca5..cc2286038c0 100644
--- a/app/assets/stylesheets/framework/header.scss
+++ b/app/assets/stylesheets/framework/header.scss
@@ -8,7 +8,7 @@ header {
&.navbar-empty {
height: $header-height;
- background: #fff;
+ background: $white-light;
border-bottom: 1px solid $btn-gray-hover;
.center-logo {
@@ -71,12 +71,12 @@ header {
}
.fa-caret-down {
- font-size: 15px;
+ font-size: 14px;
}
}
.navbar-toggle {
- color: #666;
+ color: $nav-toggle-gray;
margin: 6px 0;
border-radius: 0;
position: absolute;
@@ -156,7 +156,7 @@ header {
position: relative;
padding-right: 20px;
margin: 0;
- font-size: 19px;
+ font-size: 18px;
max-width: 385px;
display: inline-block;
line-height: $header-height;
diff --git a/app/assets/stylesheets/pages/appearances.scss b/app/assets/stylesheets/framework/images.scss
index 878f44116ba..878f44116ba 100644
--- a/app/assets/stylesheets/pages/appearances.scss
+++ b/app/assets/stylesheets/framework/images.scss
diff --git a/app/assets/stylesheets/framework/issue_box.scss b/app/assets/stylesheets/framework/issue_box.scss
index ff6f316d576..44834a84234 100644
--- a/app/assets/stylesheets/framework/issue_box.scss
+++ b/app/assets/stylesheets/framework/issue_box.scss
@@ -20,7 +20,7 @@
display: block;
float: left;
margin-right: 10px;
- color: #fff;
+ color: $white-light;
font-size: $gl-font-size;
line-height: 25px;
@@ -37,10 +37,10 @@
}
&.status-box-expired {
- background: #cea61b;
+ background-color: $issue-status-expired;
}
&.status-box-upcoming {
- background: #8f8f8f;
+ background: $issue-box-upcoming-bg;
}
}
diff --git a/app/assets/stylesheets/framework/jquery.scss b/app/assets/stylesheets/framework/jquery.scss
index 30a5b837d69..18f2f316f02 100644
--- a/app/assets/stylesheets/framework/jquery.scss
+++ b/app/assets/stylesheets/framework/jquery.scss
@@ -4,13 +4,13 @@
&.ui-datepicker,
&.ui-datepicker-inline {
- border: 1px solid #ddd;
+ border: 1px solid $jq-ui-border;
padding: 10px;
width: 270px;
.ui-datepicker-header {
- background: #fff;
- border-color: #ddd;
+ background: $white-light;
+ border-color: $jq-ui-border;
.ui-datepicker-prev,
.ui-datepicker-next {
@@ -39,7 +39,7 @@
}
&.ui-autocomplete {
- border-color: #ddd;
+ border-color: $jq-ui-border;
padding: 0;
margin-top: 2px;
z-index: 1001;
@@ -50,9 +50,9 @@
}
.ui-state-default {
- border: 1px solid #fff;
- background: #fff;
- color: #777;
+ border: 1px solid $white-light;
+ background: $white-light;
+ color: $jq-ui-default-color;
}
.ui-state-highlight {
@@ -66,7 +66,7 @@
.ui-state-focus {
border: 1px solid $gl-primary;
background: $gl-primary;
- color: #fff;
+ color: $white-light;
}
}
}
diff --git a/app/assets/stylesheets/framework/layout.scss b/app/assets/stylesheets/framework/layout.scss
index 7baa4296abf..dfaf2f7f1d3 100644
--- a/app/assets/stylesheets/framework/layout.scss
+++ b/app/assets/stylesheets/framework/layout.scss
@@ -6,7 +6,7 @@ html {
body {
&.navless {
- background-color: white !important;
+ background-color: $white-light !important;
}
}
diff --git a/app/assets/stylesheets/framework/lists.scss b/app/assets/stylesheets/framework/lists.scss
index bc0610cc417..ed4b60faf92 100644
--- a/app/assets/stylesheets/framework/lists.scss
+++ b/app/assets/stylesheets/framework/lists.scss
@@ -11,8 +11,8 @@
> li {
padding: 10px 15px;
min-height: 20px;
- border-bottom: 1px solid #eee;
- border-bottom: 1px solid rgba(0, 0, 0, 0.05);
+ border-bottom: 1px solid $list-border-light;
+ border-bottom: 1px solid $list-border;
&::after {
content: " ";
@@ -21,7 +21,7 @@
}
&.disabled {
- color: #888;
+ color: $list-text-disabled-color;
}
&.unstyled {
@@ -31,9 +31,9 @@
}
&.warning-row {
- background-color: #fcf8e3;
- border-color: #faebcc;
- color: #8a6d3b;
+ background-color: $list-warning-row-bg;
+ border-color: $list-warning-row-border;
+ color: $list-warning-row-color;
}
&.smoke { background-color: $background-color; }
@@ -106,13 +106,13 @@ ul.task-list {
}
}
+// Generic content list
ul.content-list {
@include basic-list;
-
margin: 0;
padding: 0;
- > li {
+ li {
border-color: $table-border-color;
font-size: $list-font-size;
color: $list-text-color;
@@ -193,6 +193,41 @@ ul.content-list {
}
}
+// Content list using flexbox
+.flex-list {
+ .flex-row {
+ display: -webkit-flex;
+ display: -ms-flexbox;
+ display: flex;
+ white-space: nowrap;
+ }
+
+ .row-main-content {
+ flex: 1 1 auto;
+ overflow: hidden;
+ padding-right: 8px;
+ }
+
+ .row-title {
+ font-weight: 600;
+ }
+
+ .row-second-line {
+ display: block;
+ }
+
+ .dropdown {
+ .btn-block {
+ margin-bottom: 0;
+ line-height: inherit;
+ }
+ }
+
+ .label-default {
+ color: $btn-transparent-color;
+ }
+}
+
.panel > .content-list > li {
padding: $gl-padding-top $gl-padding;
diff --git a/app/assets/stylesheets/framework/markdown_area.scss b/app/assets/stylesheets/framework/markdown_area.scss
index 4bd7ff8fefd..59a30d31ac7 100644
--- a/app/assets/stylesheets/framework/markdown_area.scss
+++ b/app/assets/stylesheets/framework/markdown_area.scss
@@ -73,7 +73,7 @@
}
.referenced-users {
- color: #4c4e54;
+ color: $gl-header-color;
padding-top: 10px;
}
@@ -85,8 +85,8 @@
.markdown-area {
border-radius: 0;
- background: #fff;
- border: 1px solid #ddd;
+ background: $white-light;
+ border: 1px solid $md-area-border;
min-height: 140px;
max-height: 500px;
padding: 5px;
@@ -108,7 +108,7 @@
hr {
// Darken 'whitesmoke' a bit to make it more visible in note bodies
- border-color: darken(#f5f5f5, 8%);
+ border-color: darken($gray-normal, 8%);
margin: 10px 0;
}
@@ -135,7 +135,7 @@
.toolbar-btn {
float: left;
padding: 0 5px;
- color: #959494;
+ color: $note-toolbar-color;
background: transparent;
border: 0;
outline: 0;
diff --git a/app/assets/stylesheets/framework/mixins.scss b/app/assets/stylesheets/framework/mixins.scss
index f84ca36d10f..4f2ac77f228 100644
--- a/app/assets/stylesheets/framework/mixins.scss
+++ b/app/assets/stylesheets/framework/mixins.scss
@@ -24,7 +24,7 @@
@include clearfix;
padding: 10px 0;
- border-bottom: 1px solid #eee;
+ border-bottom: 1px solid $list-border-light;
display: block;
margin: 0;
@@ -67,8 +67,8 @@
}
@mixin dark-diff-match-line {
- color: rgba(255, 255, 255, 0.3);
- background: rgba(255, 255, 255, 0.1);
+ color: $dark-diff-match-bg;
+ background: $dark-diff-match-color;
}
@mixin webkit-prefix($property, $value) {
diff --git a/app/assets/stylesheets/framework/mobile.scss b/app/assets/stylesheets/framework/mobile.scss
index 9391661a595..abfdd7a759d 100644
--- a/app/assets/stylesheets/framework/mobile.scss
+++ b/app/assets/stylesheets/framework/mobile.scss
@@ -133,9 +133,9 @@
right: 0;
top: 30%;
padding: 5px 15px;
- background: #eee;
+ background: $show-aside-bg;
font-size: 20px;
- color: #777;
+ color: $show-aside-color;
z-index: 100;
- box-shadow: 0 1px 2px #ddd;
+ box-shadow: 0 1px 2px $show-aside-shadow;
}
diff --git a/app/assets/stylesheets/framework/nav.scss b/app/assets/stylesheets/framework/nav.scss
index 98f72e58c23..69da520f21f 100644
--- a/app/assets/stylesheets/framework/nav.scss
+++ b/app/assets/stylesheets/framework/nav.scss
@@ -49,7 +49,7 @@
padding: $gl-btn-padding;
padding-bottom: 11px;
margin-bottom: -1px;
- font-size: 15px;
+ font-size: 14px;
line-height: 28px;
color: $note-toolbar-color;
border-bottom: 2px solid transparent;
@@ -75,7 +75,7 @@
.badge {
font-weight: normal;
- background-color: #eee;
+ background-color: $nav-badge-bg;
color: $btn-transparent-color;
vertical-align: baseline;
}
@@ -268,6 +268,16 @@
width: auto;
}
}
+
+ &.multi-line {
+ .nav-text {
+ line-height: 20px;
+ }
+
+ .nav-controls {
+ padding: 17px 0;
+ }
+ }
}
.layout-nav {
diff --git a/app/assets/stylesheets/framework/selects.scss b/app/assets/stylesheets/framework/selects.scss
index 920ce249b9a..fde1431b13e 100644
--- a/app/assets/stylesheets/framework/selects.scss
+++ b/app/assets/stylesheets/framework/selects.scss
@@ -6,7 +6,7 @@
.select2-container,
.select2-container.select2-drop-above {
.select2-choice {
- background: #fff;
+ background: $white-light;
border-color: $input-border;
height: 35px;
padding: $gl-vert-padding $gl-input-padding;
@@ -47,7 +47,7 @@
}
.select2-drop {
- box-shadow: rgba(76, 86, 103, 0.247059) 0 0 1px 0, rgba(31, 37, 50, 0.317647) 0 2px 18px 0;
+ box-shadow: $select2-drop-shadow1 0 0 1px 0, $select2-drop-shadow2 0 2px 18px 0;
border-radius: $border-radius-default;
border: none;
min-width: 175px;
@@ -59,7 +59,7 @@
}
.select2-drop {
- color: #7f8fa4;
+ color: $gl-grayish-blue;
}
.select2-highlighted {
@@ -156,7 +156,7 @@
.select2-search input {
padding: 2px 25px 2px 5px;
- background: #fff image-url('select2.png');
+ background: $white-light image-url('select2.png');
background-repeat: no-repeat;
background-position: right 0 bottom 6px;
border: 1px solid $input-border;
@@ -169,7 +169,7 @@
}
.select2-search input.select2-active {
- background-color: #fff;
+ background-color: $white-light;
background-image: image-url('select2-spinner.gif') !important;
background-repeat: no-repeat;
background-position: right 5px center !important;
@@ -206,7 +206,7 @@
.select2-highlighted {
.group-result {
.group-path {
- color: #fff;
+ color: $white-light;
}
}
}
@@ -221,7 +221,7 @@
}
.group-path {
- color: #999;
+ color: $group-path-color;
}
}
@@ -241,7 +241,7 @@
.namespace-result {
.namespace-kind {
- color: #aaa;
+ color: $namespace-kind-color;
font-weight: normal;
}
diff --git a/app/assets/stylesheets/framework/sidebar.scss b/app/assets/stylesheets/framework/sidebar.scss
index 4269d365578..0aa609b8dd5 100644
--- a/app/assets/stylesheets/framework/sidebar.scss
+++ b/app/assets/stylesheets/framework/sidebar.scss
@@ -36,7 +36,7 @@
transition: padding $sidebar-transition-duration;
.container-fluid {
- background: #fff;
+ background: $white-light;
padding: 0 $gl-padding;
&.container-blank {
diff --git a/app/assets/stylesheets/framework/tables.scss b/app/assets/stylesheets/framework/tables.scss
index 9a90d3794fd..5d0ca63ea08 100644
--- a/app/assets/stylesheets/framework/tables.scss
+++ b/app/assets/stylesheets/framework/tables.scss
@@ -14,11 +14,11 @@ table {
.warning,
.danger,
.info {
- color: #fff;
+ color: $white-light;
a:not(.btn) {
text-decoration: underline;
- color: #fff;
+ color: $white-light;
}
}
@@ -34,6 +34,10 @@ table {
background-color: $background-color;
font-weight: normal;
border-bottom: none;
+
+ &.wide {
+ width: 55%;
+ }
}
td {
@@ -42,3 +46,16 @@ table {
}
}
}
+
+.responsive-table {
+ @media (max-width: $screen-sm-max) {
+ th {
+ width: 100%;
+ }
+
+ td {
+ width: 100%;
+ float: left;
+ }
+ }
+}
diff --git a/app/assets/stylesheets/framework/tw_bootstrap.scss b/app/assets/stylesheets/framework/tw_bootstrap.scss
index 59f4594bb83..55bc325b858 100644
--- a/app/assets/stylesheets/framework/tw_bootstrap.scss
+++ b/app/assets/stylesheets/framework/tw_bootstrap.scss
@@ -97,13 +97,13 @@
display: inline-block;
&.label-gray {
- background-color: #f8fafc;
+ background-color: $label-gray-bg;
color: $gl-gray;
text-shadow: none;
}
&.label-inverse {
- background-color: #333;
+ background-color: $label-inverse-bg;
}
}
@@ -158,7 +158,7 @@
font-weight: normal;
a {
- color: #777;
+ color: $panel-heading-link-color;
}
}
}
@@ -172,7 +172,7 @@
.alert {
a:not(.btn) {
@extend .alert-link;
- color: #fff;
+ color: $white-light;
text-decoration: underline;
}
}
diff --git a/app/assets/stylesheets/framework/tw_bootstrap_variables.scss b/app/assets/stylesheets/framework/tw_bootstrap_variables.scss
index 44fe37d3a4a..c731a8f222f 100644
--- a/app/assets/stylesheets/framework/tw_bootstrap_variables.scss
+++ b/app/assets/stylesheets/framework/tw_bootstrap_variables.scss
@@ -48,7 +48,7 @@ $font-size-base: $gl-font-size;
$padding-base-vertical: $gl-vert-padding;
$padding-base-horizontal: $gl-padding;
-$component-active-color: #fff;
+$component-active-color: $white-light;
$component-active-bg: $brand-info;
//== Forms
@@ -66,7 +66,7 @@ $legend-color: $text-color;
//##
$pagination-color: $gl-gray;
-$pagination-bg: #fff;
+$pagination-bg: $white-light;
$pagination-border: $border-color;
$pagination-hover-color: $gl-gray;
@@ -74,7 +74,7 @@ $pagination-hover-bg: $row-hover;
$pagination-hover-border: $border-color;
$pagination-active-color: $blue-dark;
-$pagination-active-bg: #fff;
+$pagination-active-bg: $white-light;
$pagination-active-border: $border-color;
$pagination-disabled-color: #cdcdcd;
@@ -86,19 +86,19 @@ $pagination-disabled-border: $border-color;
//
//## Define colors for form feedback states and, by default, alerts.
-$state-success-text: #fff;
+$state-success-text: $white-light;
$state-success-bg: $brand-success;
$state-success-border: $brand-success;
-$state-info-text: #fff;
+$state-info-text: $white-light;
$state-info-bg: $brand-info;
$state-info-border: $brand-info;
-$state-warning-text: #fff;
+$state-warning-text: $white-light;
$state-warning-bg: $brand-warning;
$state-warning-border: $brand-warning;
-$state-danger-text: #fff;
+$state-danger-text: $white-light;
$state-danger-bg: $brand-danger;
$state-danger-border: $brand-danger;
@@ -135,14 +135,14 @@ $well-border: #eee;
$code-color: #c7254e;
$code-bg: #f9f2f4;
-$kbd-color: #fff;
+$kbd-color: $white-light;
$kbd-bg: #333;
//== Buttons
//
//##
$btn-default-color: $gl-text-color;
-$btn-default-bg: #fff;
+$btn-default-bg: $white-light;
$btn-default-border: #e7e9ed;
//== Nav
diff --git a/app/assets/stylesheets/framework/typography.scss b/app/assets/stylesheets/framework/typography.scss
index aa604b1cd19..d906d26bba9 100644
--- a/app/assets/stylesheets/framework/typography.scss
+++ b/app/assets/stylesheets/framework/typography.scss
@@ -33,15 +33,15 @@
padding: 3px 5px;
font-size: 11px;
line-height: 10px;
- color: #555;
+ color: $kdb-color;
vertical-align: middle;
- background-color: #fcfcfc;
+ background-color: $kdb-bg;
border-width: 1px;
border-style: solid;
- border-color: #ccc #ccc #bbb;
+ border-color: $kdb-border $kdb-border $kdb-border-bottom;
border-image: none;
border-radius: 3px;
- box-shadow: 0 -1px 0 #bbb inset;
+ box-shadow: 0 -1px 0 $kdb-shadow inset;
}
h1 {
@@ -81,7 +81,7 @@
}
blockquote {
- color: #7f8fa4;
+ color: $gl-grayish-blue;
font-size: inherit;
padding: 8px 21px;
margin: 12px 0;
@@ -94,13 +94,13 @@
}
blockquote p {
- color: #7f8fa4 !important;
+ color: $gl-grayish-blue !important;
font-size: inherit;
line-height: 1.5;
}
p {
- color: #5c5d5e;
+ color: $gl-text-color-dark;
margin: 6px 0 0;
}
@@ -108,10 +108,10 @@
@extend .table;
@extend .table-bordered;
margin: 12px 0;
- color: #5c5d5e;
+ color: $gl-text-color-dark;
th {
- background: #f8fafc;
+ background: $label-gray-bg;
}
}
@@ -202,7 +202,7 @@
*
*/
body {
- -webkit-text-shadow: rgba(255,255,255,0.01) 0 0 1px;
+ -webkit-text-shadow: $body-text-shadow 0 0 1px;
}
.page-title {
diff --git a/app/assets/stylesheets/framework/variables.scss b/app/assets/stylesheets/framework/variables.scss
index 8a9c279d124..18716813c48 100644
--- a/app/assets/stylesheets/framework/variables.scss
+++ b/app/assets/stylesheets/framework/variables.scss
@@ -96,18 +96,22 @@ $dark-background-color: #f5f5f5;
$table-text-gray: #8f8f8f;
$well-expand-item: #e8f2f7;
$well-inner-border: #eef0f2;
+$well-light-border: #f1f1f1;
+$well-light-text-color: #5b6169;
/*
* Text
*/
-$gl-font-size: 15px;
+$gl-font-size: 14px;
$gl-title-color: #333;
$gl-text-color: #5c5c5c;
+$gl-text-color-dark: #5c5d5e;
$gl-text-color-light: #8c8c8c;
$gl-text-green: #4a2;
$gl-text-red: #d12f19;
$gl-text-orange: #d90;
$gl-link-color: #3777b0;
+$gl-diff-text-color: #555;
$gl-dark-link-color: #333;
$gl-placeholder-color: #8f8f8f;
$gl-icon-color: $gl-placeholder-color;
@@ -123,13 +127,20 @@ $gl-header-color: #4c4e54;
$list-font-size: $gl-font-size;
$list-title-color: $gl-title-color;
$list-text-color: $gl-text-color;
+$list-text-disabled-color: #888;
+$list-border-light: #eee;
+$list-border: rgba(0, 0, 0, 0.05);
$list-text-height: 42px;
+$list-warning-row-bg: #fcf8e3;
+$list-warning-row-border: #faebcc;
+$list-warning-row-color: #8a6d3b;
/*
* Markdown
*/
$md-text-color: $gl-text-color;
$md-link-color: $gl-link-color;
+$md-area-border: #ddd;
/*
* Code
@@ -153,10 +164,8 @@ $gl-sidebar-padding: 22px;
$row-hover: #f7faff;
$row-hover-border: #b2d7ff;
$progress-color: #c0392b;
-$avatar_radius: 50%;
$header-height: 50px;
$fixed-layout-width: 1280px;
-$gl-avatar-size: 40px;
$error-exclamation-point: #e62958;
$border-radius-default: 2px;
$btn-transparent-color: #8f8f8f;
@@ -166,10 +175,47 @@ $provider-btn-not-active-color: #4688f1;
$link-underline-blue: #4a8bee;
$active-item-blue: #4a8bee;
$layout-link-gray: #7e7c7c;
-$todo-alert-blue: #428bca;
$btn-side-margin: 10px;
$btn-sm-side-margin: 7px;
$btn-xs-side-margin: 5px;
+$issue-status-expired: #cea61b;
+$issuable-sidebar-color: #999;
+$issuable-avatar-hover-border: #999;
+$issuable-clipboard-color: #999;
+$show-aside-bg: #eee;
+$show-aside-color: #777;
+$show-aside-shadow: #ddd;
+$group-path-color: #999;
+$namespace-kind-color: #aaa;
+$panel-heading-link-color: #777;
+$graph-author-email-color: #777;
+$count-arrow-border: #dce0e5;
+$save-project-loader-color: #555;
+$divergence-graph-bar-bg: #ccc;
+$divergence-graph-separator-bg: #ccc;
+$issue-box-upcoming-bg: #8f8f8f;
+
+/*
+* Common component specific colors
+*/
+$hint-color: #999;
+$well-pre-bg: #eee;
+$well-pre-color: #555;
+$loading-color: #555;
+$update-author-color: #999;
+$user-mention-color: #2fa0bb;
+$time-color: #999;
+$project-member-show-color: #aaa;
+$gl-promo-color: #aaa;
+$error-bg: #c67;
+$warning-message-bg: #ffffe6;
+$warning-message-border: #ed9;
+$warning-message-color: #b90;
+$control-group-descr-color: #666;
+$table-permission-x-bg: #d9edf7;
+$username-color: #666;
+$description-color: #666;
+$profiler-border: #eee;
/* tanuki logo colors */
$tanuki-red: #e24329;
@@ -205,12 +251,22 @@ $table-border-gray: #f0f0f0;
$line-target-blue: #f6faff;
$line-select-yellow: #fcf8e7;
$line-select-yellow-dark: #f0e2bd;
+$dark-diff-match-bg: rgba(255, 255, 255, 0.3);
+$dark-diff-match-color: rgba(255, 255, 255, 0.1);
+$file-mode-changed: #777;
+$file-mode-changed: #777;
+$diff-image-bg: #ddd;
+$diff-image-info-color: grey;
+$diff-image-img-bg: #e5e5e5;
+$diff-swipe-border: #999;
+$diff-view-modes-color: grey;
+$diff-view-modes-border: #c1c1c1;
/*
* Fonts
*/
$monospace_font: 'Menlo', 'Liberation Mono', 'Consolas', 'DejaVu Sans Mono', 'Ubuntu Mono', 'Courier New', 'andale mono', 'lucida console', monospace;
-$regular_font: 'Source Sans Pro', "Helvetica Neue", Helvetica, Arial, sans-serif;
+$regular_font: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif;
/*
* Dropdowns
@@ -226,6 +282,7 @@ $dropdown-divider-color: rgba(#000, .1);
$dropdown-header-color: #959494;
$dropdown-title-btn-color: #bfbfbf;
$dropdown-input-color: #555;
+$dropdown-input-fa-color: #c7c7c7;
$dropdown-input-focus-border: $focus-border-color;
$dropdown-input-focus-shadow: rgba($dropdown-input-focus-border, .4);
$dropdown-loading-bg: rgba(#fff, .6);
@@ -243,6 +300,7 @@ $dropdown-toggle-hover-icon-color: darken($dropdown-toggle-icon-color, 7%);
* Buttons
*/
$btn-active-gray: #ececec;
+$btn-active-gray-light: e4e7ed;
$btn-placeholder-gray: #c7c7c7;
$btn-white-active: #848484;
$btn-gray-hover: #eee;
@@ -252,6 +310,7 @@ $btn-gray-hover: #eee;
*/
$award-emoji-menu-bg: #fff;
$award-emoji-menu-border: #f1f2f4;
+$award-emoji-menu-shadow: rgba(0,0,0,.175);
$award-emoji-new-btn-icon-color: #dcdcdc;
/*
@@ -273,17 +332,28 @@ $notes-light-color: #8e8e8e;
$notes-action-color: #c3c3c3;
$notes-role-color: #8e8e8e;
$notes-role-border-color: #e4e4e4;
-
$note-disabled-comment-color: #b2b2b2;
$note-form-border-color: #e5e5e5;
$note-toolbar-color: #959494;
+$note-targe3-outside: #fffff0;
+$note-targe3-inside: #ffffd3;
+$note-line2-border: #ddd;
+
+/*
+* Zen
+*/
+$zen-control-color: #555;
$zen-control-hover-color: #111;
+/*
+* Calendar
+*/
$calendar-header-color: #b8b8b8;
$calendar-hover-bg: #ecf3fe;
$calendar-border-color: rgba(#000, .1);
$calendar-unselectable-bg: $gray-light;
+$calendar-user-contrib-text: #959494;
/*
* Cycle Analytics
@@ -293,13 +363,211 @@ $cycle-analytics-box-text-color: #8c8c8c;
$cycle-analytics-big-font: 19px;
$cycle-analytics-dark-text: $gl-title-color;
$cycle-analytics-light-gray: #bfbfbf;
+$cycle-analytics-dismiss-icon-color: #b2b2b2;
/*
* Personal Access Tokens
*/
$personal-access-tokens-disabled-label-color: #bbb;
+/*
+* CI
+*/
$ci-output-bg: #1d1f21;
$ci-text-color: #c5c8c6;
+$ci-skipped-color: #888;
+
+/*
+* Boards
+*/
+$issue-boards-font-size: 14px;
+$issue-boards-card-shadow: rgba(186, 186, 186, 0.5);
+
+/*
+* Avatar
+*/
+$avatar_radius: 50%;
+$avatar-border: rgba(0, 0, 0, .1);
+$gl-avatar-size: 40px;
+
+/*
+* Builds
+*/
+$builds-trace-bg: #111;
+
+/*
+* Callout
+*/
+$callout-danger-bg: #fdf7f7;
+$callout-danger-border: #eed3d7;
+$callout-danger-color: #b94a48;
+$callout-warning-bg: #faf8f0;
+$callout-warning-border: #faebcc;
+$callout-warning-color: #8a6d3b;
+$callout-info-bg: #f4f8fa;
+$callout-info-border: #bce8f1;
+$callout-info-color: #34789a;
+$callout-success-bg: #dff0d8;
+$callout-success-border: #5ca64d;
+$callout-success-color: #3c763d;
+
+/*
+* Commit Page
+*/
+$commit-committer-color: #999;
+$commit-max-width-marker-color: rgba(0, 0, 0, 0.0);
+$commit-message-text-area-bg: rgba(0, 0, 0, 0.0);
+
+/*
+* Common
+*/
+$common-gray: $gl-gray;
+$common-gray-light: #bbb;
+$common-gray-dark: #444;
+$common-red: $gl-text-red;
+$common-green: $gl-text-green;
+
+/*
+* Editor
+*/
+$editor-cancel-color: #b94a48;
+
+/*
+* Events
+*/
+$events-pre-color: #777;
+$events-note-icon-color: #777;
+$events-body-border: #ddd;
+
+/*
+* Files
+*/
+$file-image-bg: #eee;
+$blob-bg: #eee;
+$blame-border: #eee;
+$blame-line-numbers-border: #ddd;
+$logs-bg: #eee;
+$logs-li-color: #888;
+$logs-p-color: #333;
+
+/*
+* Forms
+*/
+$input-danger-bg: #f2dede;
+$input-danger-border: #d66;
+$input-group-addon-bg: #f7f8fa;
+$gl-field-focus-shadow: rgba(0, 0, 0, 0.075);
+$gl-field-focus-shadow-error: rgba(210, 40, 82, 0.6);
-$issue-boards-font-size: 15px;
+/*
+* Help
+*/
+$document-index-color: #888;
+$help-shortcut-color: #999;
+$help-shortcut-mapping-color: #555;
+$help-shortcut-header-color: #333;
+
+/*
+* Issues
+*/
+$issues-border: #e5e5e5;
+$issues-today-bg: #f3fff2;
+$issues-today-border: #e1e8d5;
+
+/*
+* jQuery UI
+*/
+$jq-ui-border: #ddd;
+$jq-ui-default-color: #777;
+
+/*
+* Label
+*/
+$label-gray-bg: #f8fafc;
+$label-inverse-bg: #333;
+$label-remove-border: rgba(0, 0, 0, .1);
+
+/*
+* Lint
+*/
+$lint-incorrect-color: red;
+$lint-correct-color: #47a447;
+
+/*
+* Login
+*/
+$login-brand-holder-color: #888;
+$login-devise-error-color: #a00;
+
+/*
+* Nav
+*/
+$nav-link-gray: #959494;
+$nav-badge-bg: #eee;
+$nav-toggle-gray: #666;
+
+/*
+* Notify
+*/
+$notify-details: #777;
+$notify-footer: #777;
+$notify-new-file: #090;
+$notify-deleted-file: #b00;
+
+/*
+* Projects
+*/
+$project-option-descr-color: #54565b;
+$project-breadcrumb-color: #999;
+$project-private-forks-notice-odd: #2aa056;
+$project-network-controls-color: #888;
+$project-limit-message-bg: #f28d35;
+
+/*
+* Runners
+*/
+$runner-state-shared-bg: #32b186;
+$runner-state-specific-bg: #3498db;
+$runner-status-online-color: green;
+$runner-status-offline-color: gray;
+$runner-status-paused-color: red;
+
+/*
+Stat Graph
+*/
+$stat-graph-common-bg: #f3f3f3;
+$stat-graph-area-fill: #1db34f;
+$stat-graph-axis-fill: #aaa;
+$stat-graph-orange-fill: #f17f49;
+$stat-graph-selection-fill: #333;
+$stat-graph-selection-stroke: #333;
+
+/*
+* Selects
+*/
+$select2-drop-shadow1: rgba(76, 86, 103, 0.247059);
+$select2-drop-shadow2: rgba(31, 37, 50, 0.317647);
+
+
+/*
+* Todo
+*/
+$todo-alert-blue: #428bca;
+$todo-body-pre-color: #777;
+$todo-body-border: #ddd;
+
+/*
+* Typography
+*/
+$kdb-bg: #fcfcfc;
+$kdb-color: #555;
+$kdb-border: #ccc;
+$kdb-border-bottom: #bbb;
+$kdb-shadow: #bbb;
+$body-text-shadow: rgba(255,255,255,0.01);
+
+/*
+* UI Dev Kit
+*/
+$ui-dev-kit-example-color: #bbb;
+$ui-dev-kit-example-border: #ddd;
diff --git a/app/assets/stylesheets/framework/wells.scss b/app/assets/stylesheets/framework/wells.scss
index 192939f4527..f2860dfe84d 100644
--- a/app/assets/stylesheets/framework/wells.scss
+++ b/app/assets/stylesheets/framework/wells.scss
@@ -43,3 +43,16 @@
background-color: $well-expand-item;
}
}
+
+.light-well {
+ background-color: $background-color;
+ padding: 15px;
+}
+
+.well-centered {
+ h1 {
+ font-weight: normal;
+ text-align: center;
+ font-size: 48px;
+ }
+}
diff --git a/app/assets/stylesheets/framework/zen.scss b/app/assets/stylesheets/framework/zen.scss
index ff02ebdd34c..e5c7d70d45a 100644
--- a/app/assets/stylesheets/framework/zen.scss
+++ b/app/assets/stylesheets/framework/zen.scss
@@ -1,6 +1,6 @@
.zen-backdrop {
&.fullscreen {
- background-color: white;
+ background-color: $white-light;
position: fixed;
top: 0;
bottom: 0;
@@ -12,7 +12,7 @@
border: none;
box-shadow: none;
border-radius: 0;
- color: #000;
+ color: $black;
font-size: 20px;
line-height: 26px;
padding: 30px;
@@ -34,7 +34,7 @@
.zen-control {
padding: 0;
- color: #555;
+ color: $zen-control-color;
background: none;
border: 0;
}
diff --git a/app/assets/stylesheets/highlight/dark.scss b/app/assets/stylesheets/highlight/dark.scss
index d22d9b01495..cb923166b25 100644
--- a/app/assets/stylesheets/highlight/dark.scss
+++ b/app/assets/stylesheets/highlight/dark.scss
@@ -1,27 +1,109 @@
/* https://github.com/MozMorris/tomorrow-pygments */
+
+/*
+* Dark syntax colors
+*/
+$dark-new-bg: rgba(51, 255, 51, 0.1);
+$dark-new-idiff: rgba(51, 255, 51, 0.2);
+$dark-old-bg: rgba(255, 51, 51, 0.2);
+$dark-old-idiff: rgba(255, 51, 51, 0.25);
+$dark-border: #808080;
+$dark-code-border: #666;
+$dark-main-bg: #1d1f21;
+$dark-main-color: #1d1f21;
+$dark-line-color: #c5c8c6;
+$dark-line-num-color: rgba(255, 255, 255, 0.3);
+$dark-diff-not-empty-bg: #557;
+$dark-highlight-bg: #ffe792;
+$dark-highlight-color: $black;
+$dark-pre-hll-bg: #373b41;
+$dark-hll-bg: #373b41;
+$dark-c: #969896;
+$dark-err: #c66;
+$dark-k: #b294bb;
+$dark-l: #de935f;
+$dark-n: #c5c8c6;
+$dark-o: #8abeb7;
+$dark-p: #c5c8c6;
+$dark-cm: #969896;
+$dark-cp: #969896;
+$dark-c1: #969896;
+$dark-cs: #969896;
+$dark-gd: #c66;
+$dark-gh: #c5c8c6;
+$dark-gi: #b5bd68;
+$dark-gp: #969896;
+$dark-gu: #8abeb7;
+$dark-kc: #b294bb;
+$dark-kd: #b294bb;
+$dark-kn: #8abeb7;
+$dark-kp: #b294bb;
+$dark-kr: #b294bb;
+$dark-kt: #f0c674;
+$dark-ld: #b5bd68;
+$dark-m: #de935f;
+$dark-s: #b5bd68;
+$dark-na: #81a2be;
+$dark-nb: #c5c8c6;
+$dark-nc: #f0c674;
+$dark-no: #c66;
+$dark-nd: #8abeb7;
+$dark-ni: #c5c8c6;
+$dark-ne: #c66;
+$dark-nf: #81a2be;
+$dark-nl: #c5c8c6;
+$dark-nn: #f0c674;
+$dark-nx: #81a2be;
+$dark-py: #c5c8c6;
+$dark-nt: #8abeb7;
+$dark-nv: #c66;
+$dark-ow: #8abeb7;
+$dark-w: #c5c8c6;
+$dark-mf: #de935f;
+$dark-mh: #de935f;
+$dark-mi: #de935f;
+$dark-mo: #de935f;
+$dark-sb: #b5bd68;
+$dark-sc: #c5c8c6;
+$dark-sd: #969896;
+$dark-s2: #b5bd68;
+$dark-se: #de935f;
+$dark-sh: #b5bd68;
+$dark-si: #de935f;
+$dark-sx: #b5bd68;
+$dark-sr: #b5bd68;
+$dark-s1: #b5bd68;
+$dark-ss: #b5bd68;
+$dark-bp: #c5c8c6;
+$dark-vc: #c66;
+$dark-vg: #c66;
+$dark-vi: #c66;
+$dark-il: #de935f;
+
.code.dark {
// Line numbers
.line-numbers,
.diff-line-num {
- background-color: #1d1f21;
+ background-color: $dark-main-bg;
}
.diff-line-num,
.diff-line-num a {
- color: rgba(255, 255, 255, 0.3);
+ color: $dark-main-color;
+ color: $dark-line-num-color;
}
// Code itself
pre.code,
.diff-line-num {
- border-color: #666;
+ border-color: $dark-code-border;
}
&,
pre.code,
.line_holder .line_content {
- background-color: #1d1f21;
- color: #c5c8c6;
+ background-color: $dark-main-bg;
+ color: $dark-line-color;
}
// Diff line
@@ -32,18 +114,18 @@
td.diff-line-num.hll:not(.empty-cell),
td.line_content.hll:not(.empty-cell) {
- background-color: #557;
- border-color: darken(#557, 15%);
+ background-color: $dark-diff-not-empty-bg;
+ border-color: darken($dark-diff-not-empty-bg, 15%);
}
.diff-line-num.new,
.line_content.new {
- @include diff_background(rgba(51, 255, 51, 0.1), rgba(51, 255, 51, 0.2), #808080);
+ @include diff_background($dark-new-bg, $dark-new-idiff, $dark-border);
}
.diff-line-num.old,
.line_content.old {
- @include diff_background(rgba(255, 51, 51, 0.2), rgba(255, 51, 51, 0.25), #808080);
+ @include diff_background($dark-old-bg, $dark-old-idiff, $dark-border);
}
.line_content.match {
@@ -53,77 +135,77 @@
// highlight line via anchor
pre .hll {
- background-color: #557 !important;
+ background-color: $dark-pre-hll-bg !important;
}
// Search result highlight
span.highlight_word {
- background-color: #ffe792 !important;
- color: #000 !important;
+ background-color: $dark-highlight-bg !important;
+ color: $dark-highlight-color !important;
}
- .hll { background-color: #373b41; }
- .c { color: #969896; } /* Comment */
- .err { color: #c66; } /* Error */
- .k { color: #b294bb; } /* Keyword */
- .l { color: #de935f; } /* Literal */
- .n { color: #c5c8c6; } /* Name */
- .o { color: #8abeb7; } /* Operator */
- .p { color: #c5c8c6; } /* Punctuation */
- .cm { color: #969896; } /* Comment.Multiline */
- .cp { color: #969896; } /* Comment.Preproc */
- .c1 { color: #969896; } /* Comment.Single */
- .cs { color: #969896; } /* Comment.Special */
- .gd { color: #c66; } /* Generic.Deleted */
+ .hll { background-color: $dark-hll-bg; }
+ .c { color: $dark-c; } /* Comment */
+ .err { color: $dark-err; } /* Error */
+ .k { color: $dark-k; } /* Keyword */
+ .l { color: $dark-l; } /* Literal */
+ .n { color: $dark-n; } /* Name */
+ .o { color: $dark-o; } /* Operator */
+ .p { color: $dark-p; } /* Punctuation */
+ .cm { color: $dark-cm; } /* Comment.Multiline */
+ .cp { color: $dark-cp; } /* Comment.Preproc */
+ .c1 { color: $dark-c1; } /* Comment.Single */
+ .cs { color: $dark-cs; } /* Comment.Special */
+ .gd { color: $dark-gd; } /* Generic.Deleted */
.ge { font-style: italic; } /* Generic.Emph */
- .gh { color: #c5c8c6; font-weight: bold; } /* Generic.Heading */
- .gi { color: #b5bd68; } /* Generic.Inserted */
- .gp { color: #969896; font-weight: bold; } /* Generic.Prompt */
+ .gh { color: $dark-gh; font-weight: bold; } /* Generic.Heading */
+ .gi { color: $dark-gi; } /* Generic.Inserted */
+ .gp { color: $dark-gp; font-weight: bold; } /* Generic.Prompt */
.gs { font-weight: bold; } /* Generic.Strong */
- .gu { color: #8abeb7; font-weight: bold; } /* Generic.Subheading */
- .kc { color: #b294bb; } /* Keyword.Constant */
- .kd { color: #b294bb; } /* Keyword.Declaration */
- .kn { color: #8abeb7; } /* Keyword.Namespace */
- .kp { color: #b294bb; } /* Keyword.Pseudo */
- .kr { color: #b294bb; } /* Keyword.Reserved */
- .kt { color: #f0c674; } /* Keyword.Type */
- .ld { color: #b5bd68; } /* Literal.Date */
- .m { color: #de935f; } /* Literal.Number */
- .s { color: #b5bd68; } /* Literal.String */
- .na { color: #81a2be; } /* Name.Attribute */
- .nb { color: #c5c8c6; } /* Name.Builtin */
- .nc { color: #f0c674; } /* Name.Class */
- .no { color: #c66; } /* Name.Constant */
- .nd { color: #8abeb7; } /* Name.Decorator */
- .ni { color: #c5c8c6; } /* Name.Entity */
- .ne { color: #c66; } /* Name.Exception */
- .nf { color: #81a2be; } /* Name.Function */
- .nl { color: #c5c8c6; } /* Name.Label */
- .nn { color: #f0c674; } /* Name.Namespace */
- .nx { color: #81a2be; } /* Name.Other */
- .py { color: #c5c8c6; } /* Name.Property */
- .nt { color: #8abeb7; } /* Name.Tag */
- .nv { color: #c66; } /* Name.Variable */
- .ow { color: #8abeb7; } /* Operator.Word */
- .w { color: #c5c8c6; } /* Text.Whitespace */
- .mf { color: #de935f; } /* Literal.Number.Float */
- .mh { color: #de935f; } /* Literal.Number.Hex */
- .mi { color: #de935f; } /* Literal.Number.Integer */
- .mo { color: #de935f; } /* Literal.Number.Oct */
- .sb { color: #b5bd68; } /* Literal.String.Backtick */
- .sc { color: #c5c8c6; } /* Literal.String.Char */
- .sd { color: #969896; } /* Literal.String.Doc */
- .s2 { color: #b5bd68; } /* Literal.String.Double */
- .se { color: #de935f; } /* Literal.String.Escape */
- .sh { color: #b5bd68; } /* Literal.String.Heredoc */
- .si { color: #de935f; } /* Literal.String.Interpol */
- .sx { color: #b5bd68; } /* Literal.String.Other */
- .sr { color: #b5bd68; } /* Literal.String.Regex */
- .s1 { color: #b5bd68; } /* Literal.String.Single */
- .ss { color: #b5bd68; } /* Literal.String.Symbol */
- .bp { color: #c5c8c6; } /* Name.Builtin.Pseudo */
- .vc { color: #c66; } /* Name.Variable.Class */
- .vg { color: #c66; } /* Name.Variable.Global */
- .vi { color: #c66; } /* Name.Variable.Instance */
- .il { color: #de935f; } /* Literal.Number.Integer.Long */
+ .gu { color: $dark-gu; font-weight: bold; } /* Generic.Subheading */
+ .kc { color: $dark-kc; } /* Keyword.Constant */
+ .kd { color: $dark-kd; } /* Keyword.Declaration */
+ .kn { color: $dark-kn; } /* Keyword.Namespace */
+ .kp { color: $dark-kp; } /* Keyword.Pseudo */
+ .kr { color: $dark-kr; } /* Keyword.Reserved */
+ .kt { color: $dark-kt; } /* Keyword.Type */
+ .ld { color: $dark-ld; } /* Literal.Date */
+ .m { color: $dark-m; } /* Literal.Number */
+ .s { color: $dark-s; } /* Literal.String */
+ .na { color: $dark-na; } /* Name.Attribute */
+ .nb { color: $dark-nb; } /* Name.Builtin */
+ .nc { color: $dark-nc; } /* Name.Class */
+ .no { color: $dark-no; } /* Name.Constant */
+ .nd { color: $dark-nd; } /* Name.Decorator */
+ .ni { color: $dark-ni; } /* Name.Entity */
+ .ne { color: $dark-ne; } /* Name.Exception */
+ .nf { color: $dark-nf; } /* Name.Function */
+ .nl { color: $dark-nl; } /* Name.Label */
+ .nn { color: $dark-nn; } /* Name.Namespace */
+ .nx { color: $dark-nx; } /* Name.Other */
+ .py { color: $dark-py; } /* Name.Property */
+ .nt { color: $dark-nt; } /* Name.Tag */
+ .nv { color: $dark-nv; } /* Name.Variable */
+ .ow { color: $dark-ow; } /* Operator.Word */
+ .w { color: $dark-w; } /* Text.Whitespace */
+ .mf { color: $dark-mf; } /* Literal.Number.Float */
+ .mh { color: $dark-mh; } /* Literal.Number.Hex */
+ .mi { color: $dark-mi; } /* Literal.Number.Integer */
+ .mo { color: $dark-mo; } /* Literal.Number.Oct */
+ .sb { color: $dark-sb; } /* Literal.String.Backtick */
+ .sc { color: $dark-sc; } /* Literal.String.Char */
+ .sd { color: $dark-sd; } /* Literal.String.Doc */
+ .s2 { color: $dark-s2; } /* Literal.String.Double */
+ .se { color: $dark-se; } /* Literal.String.Escape */
+ .sh { color: $dark-sh; } /* Literal.String.Heredoc */
+ .si { color: $dark-si; } /* Literal.String.Interpol */
+ .sx { color: $dark-sx; } /* Literal.String.Other */
+ .sr { color: $dark-sr; } /* Literal.String.Regex */
+ .s1 { color: $dark-s1; } /* Literal.String.Single */
+ .ss { color: $dark-ss; } /* Literal.String.Symbol */
+ .bp { color: $dark-bp; } /* Name.Builtin.Pseudo */
+ .vc { color: $dark-vc; } /* Name.Variable.Class */
+ .vg { color: $dark-vg; } /* Name.Variable.Global */
+ .vi { color: $dark-vi; } /* Name.Variable.Instance */
+ .il { color: $dark-il; } /* Literal.Number.Integer.Long */
}
diff --git a/app/assets/stylesheets/highlight/monokai.scss b/app/assets/stylesheets/highlight/monokai.scss
index db8da8aab10..d8510baad8a 100644
--- a/app/assets/stylesheets/highlight/monokai.scss
+++ b/app/assets/stylesheets/highlight/monokai.scss
@@ -1,27 +1,108 @@
/* https://github.com/richleland/pygments-css/blob/master/monokai.css */
+
+/*
+* Monokai Colors
+*/
+$monokai-bg: #272822;
+$monokai-border: #555;
+$monokai-text-color: #f8f8f2;
+$monokai-line-num-color: rgba(255, 255, 255, 0.3);
+$monokai-line-empty-bg: #49483e;
+$monokai-line-empty-border: darken($monokai-line-empty-bg, 15%);
+$monokai-diff-border: #808080;
+$monokai-highlight-bg: #ffe792;
+
+$monokai-new-bg: rgba(166, 226, 46, 0.1);
+$monokai-new-idiff: rgba(166, 226, 46, 0.15);
+
+$monokai-old-bg: rgba(254, 147, 140, 0.15);
+$monokai-old-idiff: rgba(254, 147, 140, 0.2);
+
+$monokai-hll: #49483e;
+$monokai-c: #75715e;
+$monokai-err-color: #960050;
+$monokai-err-bg: #1e0010;
+$monokai-k: #66d9ef;
+$monokai-l: #ae81ff;
+$monokai-n: #f8f8f2;
+$monokai-o: #f92672;
+$monokai-p: #f8f8f2;
+$monokai-cm: #75715e;
+$monokai-cp: #75715e;
+$monokai-c1: #75715e;
+$monokai-cs: #75715e;
+$monokai-kc: #66d9ef;
+$monokai-kd: #66d9ef;
+$monokai-kn: #f92672;
+$monokai-kp: #66d9ef;
+$monokai-kr: #66d9ef;
+$monokai-kt: #66d9ef;
+$monokai-ld: #e6db74;
+$monokai-m: #ae81ff;
+$monokai-s: #e6db74;
+$monokai-na: #a6e22e;
+$monokai-nb: #f8f8f2;
+$monokai-nc: #a6e22e;
+$monokai-no: #66d9ef;
+$monokai-nd: #a6e22e;
+$monokai-ni: #f8f8f2;
+$monokai-ne: #a6e22e;
+$monokai-nf: #a6e22e;
+$monokai-nl: #f8f8f2;
+$monokai-nn: #f8f8f2;
+$monokai-nx: #a6e22e;
+$monokai-py: #f8f8f2;
+$monokai-nt: #f92672;
+$monokai-nv: #f8f8f2;
+$monokai-ow: #f92672;
+$monokai-w: #f8f8f2;
+$monokai-mf: #ae81ff;
+$monokai-mh: #ae81ff;
+$monokai-mi: #ae81ff;
+$monokai-mo: #ae81ff;
+$monokai-sb: #e6db74;
+$monokai-sc: #e6db74;
+$monokai-sd: #e6db74;
+$monokai-s2: #e6db74;
+$monokai-se: #ae81ff;
+$monokai-sh: #e6db74;
+$monokai-si: #e6db74;
+$monokai-sx: #e6db74;
+$monokai-sr: #e6db74;
+$monokai-s1: #e6db74;
+$monokai-ss: #e6db74;
+$monokai-bp: #f8f8f2;
+$monokai-vc: #f8f8f2;
+$monokai-vg: #f8f8f2;
+$monokai-vi: #f8f8f2;
+$monokai-il: #ae81ff;
+$monokai-gu: #75715e;
+$monokai-gd: #f92672;
+$monokai-gi: #a6e22e;
+
.code.monokai {
// Line numbers
.line-numbers,
.diff-line-num {
- background-color: #272822;
+ background-color: $monokai-bg;
}
.diff-line-num,
.diff-line-num a {
- color: rgba(255, 255, 255, 0.3);
+ color: $monokai-line-num-color;
}
// Code itself
pre.code,
.diff-line-num {
- border-color: #555;
+ border-color: $monokai-border;
}
&,
pre.code,
.line_holder .line_content {
- background-color: #272822;
- color: #f8f8f2;
+ background-color: $monokai-bg;
+ color: $monokai-text-color;
}
// Diff line
@@ -32,18 +113,18 @@
td.diff-line-num.hll:not(.empty-cell),
td.line_content.hll:not(.empty-cell) {
- background-color: #49483e;
- border-color: darken(#49483e, 15%);
+ background-color: $monokai-line-empty-bg;
+ border-color: $monokai-line-empty-border;
}
.diff-line-num.new,
.line_content.new {
- @include diff_background(rgba(166, 226, 46, 0.1), rgba(166, 226, 46, 0.15), #808080);
+ @include diff_background($monokai-new-bg, $monokai-new-idiff, $monokai-diff-border);
}
.diff-line-num.old,
.line_content.old {
- @include diff_background(rgba(254, 147, 140, 0.15), rgba(254, 147, 140, 0.2), #808080);
+ @include diff_background($monokai-old-bg, $monokai-old-idiff, $monokai-diff-border);
}
.line_content.match {
@@ -53,75 +134,75 @@
// highlight line via anchor
pre .hll {
- background-color: #49483e !important;
+ background-color: $monokai-hll !important;
}
// Search result highlight
span.highlight_word {
- background-color: #ffe792 !important;
- color: #000 !important;
+ background-color: $monokai-highlight-bg !important;
+ color: $black !important;
}
- .hll { background-color: #49483e; }
- .c { color: #75715e; } /* Comment */
- .err { color: #960050; background-color: #1e0010; } /* Error */
- .k { color: #66d9ef; } /* Keyword */
- .l { color: #ae81ff; } /* Literal */
- .n { color: #f8f8f2; } /* Name */
- .o { color: #f92672; } /* Operator */
- .p { color: #f8f8f2; } /* Punctuation */
- .cm { color: #75715e; } /* Comment.Multiline */
- .cp { color: #75715e; } /* Comment.Preproc */
- .c1 { color: #75715e; } /* Comment.Single */
- .cs { color: #75715e; } /* Comment.Special */
+ .hll { background-color: $monokai-hll; }
+ .c { color: $monokai-c; } /* Comment */
+ .err { color: $monokai-err-color; background-color: $monokai-err-bg; } /* Error */
+ .k { color: $monokai-k; } /* Keyword */
+ .l { color: $monokai-l; } /* Literal */
+ .n { color: $monokai-n; } /* Name */
+ .o { color: $monokai-o; } /* Operator */
+ .p { color: $monokai-p; } /* Punctuation */
+ .cm { color: $monokai-cm; } /* Comment.Multiline */
+ .cp { color: $monokai-cp; } /* Comment.Preproc */
+ .c1 { color: $monokai-c1; } /* Comment.Single */
+ .cs { color: $monokai-cs; } /* Comment.Special */
.ge { font-style: italic; } /* Generic.Emph */
.gs { font-weight: bold; } /* Generic.Strong */
- .kc { color: #66d9ef; } /* Keyword.Constant */
- .kd { color: #66d9ef; } /* Keyword.Declaration */
- .kn { color: #f92672; } /* Keyword.Namespace */
- .kp { color: #66d9ef; } /* Keyword.Pseudo */
- .kr { color: #66d9ef; } /* Keyword.Reserved */
- .kt { color: #66d9ef; } /* Keyword.Type */
- .ld { color: #e6db74; } /* Literal.Date */
- .m { color: #ae81ff; } /* Literal.Number */
- .s { color: #e6db74; } /* Literal.String */
- .na { color: #a6e22e; } /* Name.Attribute */
- .nb { color: #f8f8f2; } /* Name.Builtin */
- .nc { color: #a6e22e; } /* Name.Class */
- .no { color: #66d9ef; } /* Name.Constant */
- .nd { color: #a6e22e; } /* Name.Decorator */
- .ni { color: #f8f8f2; } /* Name.Entity */
- .ne { color: #a6e22e; } /* Name.Exception */
- .nf { color: #a6e22e; } /* Name.Function */
- .nl { color: #f8f8f2; } /* Name.Label */
- .nn { color: #f8f8f2; } /* Name.Namespace */
- .nx { color: #a6e22e; } /* Name.Other */
- .py { color: #f8f8f2; } /* Name.Property */
- .nt { color: #f92672; } /* Name.Tag */
- .nv { color: #f8f8f2; } /* Name.Variable */
- .ow { color: #f92672; } /* Operator.Word */
- .w { color: #f8f8f2; } /* Text.Whitespace */
- .mf { color: #ae81ff; } /* Literal.Number.Float */
- .mh { color: #ae81ff; } /* Literal.Number.Hex */
- .mi { color: #ae81ff; } /* Literal.Number.Integer */
- .mo { color: #ae81ff; } /* Literal.Number.Oct */
- .sb { color: #e6db74; } /* Literal.String.Backtick */
- .sc { color: #e6db74; } /* Literal.String.Char */
- .sd { color: #e6db74; } /* Literal.String.Doc */
- .s2 { color: #e6db74; } /* Literal.String.Double */
- .se { color: #ae81ff; } /* Literal.String.Escape */
- .sh { color: #e6db74; } /* Literal.String.Heredoc */
- .si { color: #e6db74; } /* Literal.String.Interpol */
- .sx { color: #e6db74; } /* Literal.String.Other */
- .sr { color: #e6db74; } /* Literal.String.Regex */
- .s1 { color: #e6db74; } /* Literal.String.Single */
- .ss { color: #e6db74; } /* Literal.String.Symbol */
- .bp { color: #f8f8f2; } /* Name.Builtin.Pseudo */
- .vc { color: #f8f8f2; } /* Name.Variable.Class */
- .vg { color: #f8f8f2; } /* Name.Variable.Global */
- .vi { color: #f8f8f2; } /* Name.Variable.Instance */
- .il { color: #ae81ff; } /* Literal.Number.Integer.Long */
- .gu { color: #75715e; } /* Generic.Subheading & Diff Unified/Comment? */
- .gd { color: #f92672; } /* Generic.Deleted & Diff Deleted */
- .gi { color: #a6e22e; } /* Generic.Inserted & Diff Inserted */
+ .kc { color: $monokai-kc; } /* Keyword.Constant */
+ .kd { color: $monokai-kd; } /* Keyword.Declaration */
+ .kn { color: $monokai-kn; } /* Keyword.Namespace */
+ .kp { color: $monokai-kp; } /* Keyword.Pseudo */
+ .kr { color: $monokai-kr; } /* Keyword.Reserved */
+ .kt { color: $monokai-kt; } /* Keyword.Type */
+ .ld { color: $monokai-ld; } /* Literal.Date */
+ .m { color: $monokai-m; } /* Literal.Number */
+ .s { color: $monokai-s; } /* Literal.String */
+ .na { color: $monokai-na; } /* Name.Attribute */
+ .nb { color: $monokai-nb; } /* Name.Builtin */
+ .nc { color: $monokai-nc; } /* Name.Class */
+ .no { color: $monokai-no; } /* Name.Constant */
+ .nd { color: $monokai-nd; } /* Name.Decorator */
+ .ni { color: $monokai-ni; } /* Name.Entity */
+ .ne { color: $monokai-ne; } /* Name.Exception */
+ .nf { color: $monokai-nf; } /* Name.Function */
+ .nl { color: $monokai-nl; } /* Name.Label */
+ .nn { color: $monokai-nn; } /* Name.Namespace */
+ .nx { color: $monokai-nx; } /* Name.Other */
+ .py { color: $monokai-py; } /* Name.Property */
+ .nt { color: $monokai-nt; } /* Name.Tag */
+ .nv { color: $monokai-nv; } /* Name.Variable */
+ .ow { color: $monokai-ow; } /* Operator.Word */
+ .w { color: $monokai-w; } /* Text.Whitespace */
+ .mf { color: $monokai-mf; } /* Literal.Number.Float */
+ .mh { color: $monokai-mh; } /* Literal.Number.Hex */
+ .mi { color: $monokai-mi; } /* Literal.Number.Integer */
+ .mo { color: $monokai-mo; } /* Literal.Number.Oct */
+ .sb { color: $monokai-sb; } /* Literal.String.Backtick */
+ .sc { color: $monokai-sc; } /* Literal.String.Char */
+ .sd { color: $monokai-sd; } /* Literal.String.Doc */
+ .s2 { color: $monokai-s2; } /* Literal.String.Double */
+ .se { color: $monokai-se; } /* Literal.String.Escape */
+ .sh { color: $monokai-sh; } /* Literal.String.Heredoc */
+ .si { color: $monokai-si; } /* Literal.String.Interpol */
+ .sx { color: $monokai-sx; } /* Literal.String.Other */
+ .sr { color: $monokai-sr; } /* Literal.String.Regex */
+ .s1 { color: $monokai-s1; } /* Literal.String.Single */
+ .ss { color: $monokai-ss; } /* Literal.String.Symbol */
+ .bp { color: $monokai-bp; } /* Name.Builtin.Pseudo */
+ .vc { color: $monokai-vc; } /* Name.Variable.Class */
+ .vg { color: $monokai-vg; } /* Name.Variable.Global */
+ .vi { color: $monokai-vi; } /* Name.Variable.Instance */
+ .il { color: $monokai-il; } /* Literal.Number.Integer.Long */
+ .gu { color: $monokai-gu; } /* Generic.Subheading & Diff Unified/Comment? */
+ .gd { color: $monokai-gd; } /* Generic.Deleted & Diff Deleted */
+ .gi { color: $monokai-gi; } /* Generic.Inserted & Diff Inserted */
}
diff --git a/app/assets/stylesheets/highlight/solarized_dark.scss b/app/assets/stylesheets/highlight/solarized_dark.scss
index a87333146de..874aecb5e16 100644
--- a/app/assets/stylesheets/highlight/solarized_dark.scss
+++ b/app/assets/stylesheets/highlight/solarized_dark.scss
@@ -1,27 +1,112 @@
/* https://gist.github.com/qguv/7936275 */
+
+/*
+* Solarized dark colors
+*/
+$solarized-dark-new-bg: rgba(133, 153, 0, 0.15);
+$solarized-dark-new-idiff: rgba(133, 153, 0, 0.25);
+$solarized-dark-old-bg: rgba(220, 50, 47, 0.3);
+$solarized-dark-old-idiff: rgba(220, 50, 47, 0.25);
+$solarized-dark-border: #113b46;
+$solarized-dark-pre-bg: #002b36;
+$solarized-dark-pre-color: #93a1a1;
+$solarized-dark-pre-border: #113b46;
+$solarized-dark-line-bg: #002b36;
+$solarized-dark-line-color: rgba(255, 255, 255, 0.3);
+$solarized-dark-highlight: #094554;
+$solarized-dark-hll-bg: #174652;
+$solarized-dark-c: #586e75;
+$solarized-dark-err: #93a1a1;
+$solarized-dark-g: #93a1a1;
+$solarized-dark-k: #859900;
+$solarized-dark-l: #93a1a1;
+$solarized-dark-n: #93a1a1;
+$solarized-dark-o: #859900;
+$solarized-dark-x: #cb4b16;
+$solarized-dark-p: #93a1a1;
+$solarized-dark-cm: #586e75;
+$solarized-dark-cp: #859900;
+$solarized-dark-c1: #586e75;
+$solarized-dark-cs: #859900;
+$solarized-dark-gd: #2aa198;
+$solarized-dark-ge: #93a1a1;
+$solarized-dark-gr: #dc322f;
+$solarized-dark-gh: #cb4b16;
+$solarized-dark-gi: #859900;
+$solarized-dark-go: #93a1a1;
+$solarized-dark-gp: #93a1a1;
+$solarized-dark-gs: #93a1a1;
+$solarized-dark-gu: #cb4b16;
+$solarized-dark-gt: #93a1a1;
+$solarized-dark-kc: #cb4b16;
+$solarized-dark-kd: #268bd2;
+$solarized-dark-kn: #859900;
+$solarized-dark-kp: #859900;
+$solarized-dark-kr: #268bd2;
+$solarized-dark-kt: #dc322f;
+$solarized-dark-ld: #93a1a1;
+$solarized-dark-m: #2aa198;
+$solarized-dark-s: #2aa198;
+$solarized-dark-na: #93a1a1;
+$solarized-dark-nb: #b58900;
+$solarized-dark-nc: #268bd2;
+$solarized-dark-no: #cb4b16;
+$solarized-dark-nd: #268bd2;
+$solarized-dark-ni: #cb4b16;
+$solarized-dark-ne: #cb4b16;
+$solarized-dark-nf: #268bd2;
+$solarized-dark-nl: #93a1a1;
+$solarized-dark-nn: #93a1a1;
+$solarized-dark-nx: #93a1a1;
+$solarized-dark-py: #93a1a1;
+$solarized-dark-nt: #268bd2;
+$solarized-dark-nv: #268bd2;
+$solarized-dark-ow: #859900;
+$solarized-dark-w: #93a1a1;
+$solarized-dark-mf: #2aa198;
+$solarized-dark-mh: #2aa198;
+$solarized-dark-mi: #2aa198;
+$solarized-dark-mo: #2aa198;
+$solarized-dark-sb: #586e75;
+$solarized-dark-sc: #2aa198;
+$solarized-dark-sd: #93a1a1;
+$solarized-dark-s2: #2aa198;
+$solarized-dark-se: #cb4b16;
+$solarized-dark-sh: #93a1a1;
+$solarized-dark-si: #2aa198;
+$solarized-dark-sx: #2aa198;
+$solarized-dark-sr: #dc322f;
+$solarized-dark-s1: #2aa198;
+$solarized-dark-ss: #2aa198;
+$solarized-dark-bp: #268bd2;
+$solarized-dark-vc: #268bd2;
+$solarized-dark-vg: #268bd2;
+$solarized-dark-vi: #268bd2;
+$solarized-dark-il: #2aa198;
+
.code.solarized-dark {
// Line numbers
.line-numbers,
.diff-line-num {
- background-color: #002b36;
+ background-color: $solarized-dark-line-bg;
}
.diff-line-num,
.diff-line-num a {
- color: rgba(255, 255, 255, 0.3);
+ color: $solarized-dark-line-color;
}
// Code itself
pre.code,
.diff-line-num {
- border-color: #113b46;
+ border-color: $solarized-dark-pre-border;
}
&,
pre.code,
.line_holder .line_content {
- background-color: #002b36;
- color: #93a1a1;
+ background-color: $solarized-dark-pre-bg;
+ color: $solarized-dark-pre-color;
}
// Diff line
@@ -32,18 +117,18 @@
td.diff-line-num.hll:not(.empty-cell),
td.line_content.hll:not(.empty-cell) {
- background-color: #174652;
- border-color: darken(#174652, 15%);
+ background-color: $solarized-dark-hll-bg;
+ border-color: darken($solarized-dark-hll-bg, 15%);
}
.diff-line-num.new,
.line_content.new {
- @include diff_background(rgba(133, 153, 0, 0.15), rgba(133, 153, 0, 0.25), #113b46);
+ @include diff_background($solarized-dark-new-bg, $solarized-dark-new-idiff, $solarized-dark-border);
}
.diff-line-num.old,
.line_content.old {
- @include diff_background(rgba(220, 50, 47, 0.3), rgba(220, 50, 47, 0.25), #113b46);
+ @include diff_background($solarized-dark-old-bg, $solarized-dark-old-idiff, $solarized-dark-border);
}
.line_content.match {
@@ -53,12 +138,12 @@
// highlight line via anchor
pre .hll {
- background-color: #174652 !important;
+ background-color: $solarized-dark-hll-bg !important;
}
// Search result highlight
span.highlight_word {
- background-color: #094554 !important;
+ background-color: $solarized-dark-highlight !important;
}
/* Solarized Dark
@@ -79,72 +164,72 @@
green #859900 operators, other keywords
*/
- .c { color: #586e75; } /* Comment */
- .err { color: #93a1a1; } /* Error */
- .g { color: #93a1a1; } /* Generic */
- .k { color: #859900; } /* Keyword */
- .l { color: #93a1a1; } /* Literal */
- .n { color: #93a1a1; } /* Name */
- .o { color: #859900; } /* Operator */
- .x { color: #cb4b16; } /* Other */
- .p { color: #93a1a1; } /* Punctuation */
- .cm { color: #586e75; } /* Comment.Multiline */
- .cp { color: #859900; } /* Comment.Preproc */
- .c1 { color: #586e75; } /* Comment.Single */
- .cs { color: #859900; } /* Comment.Special */
- .gd { color: #2aa198; } /* Generic.Deleted */
- .ge { color: #93a1a1; font-style: italic; } /* Generic.Emph */
- .gr { color: #dc322f; } /* Generic.Error */
- .gh { color: #cb4b16; } /* Generic.Heading */
- .gi { color: #859900; } /* Generic.Inserted */
- .go { color: #93a1a1; } /* Generic.Output */
- .gp { color: #93a1a1; } /* Generic.Prompt */
- .gs { color: #93a1a1; font-weight: bold; } /* Generic.Strong */
- .gu { color: #cb4b16; } /* Generic.Subheading */
- .gt { color: #93a1a1; } /* Generic.Traceback */
- .kc { color: #cb4b16; } /* Keyword.Constant */
- .kd { color: #268bd2; } /* Keyword.Declaration */
- .kn { color: #859900; } /* Keyword.Namespace */
- .kp { color: #859900; } /* Keyword.Pseudo */
- .kr { color: #268bd2; } /* Keyword.Reserved */
- .kt { color: #dc322f; } /* Keyword.Type */
- .ld { color: #93a1a1; } /* Literal.Date */
- .m { color: #2aa198; } /* Literal.Number */
- .s { color: #2aa198; } /* Literal.String */
- .na { color: #93a1a1; } /* Name.Attribute */
- .nb { color: #b58900; } /* Name.Builtin */
- .nc { color: #268bd2; } /* Name.Class */
- .no { color: #cb4b16; } /* Name.Constant */
- .nd { color: #268bd2; } /* Name.Decorator */
- .ni { color: #cb4b16; } /* Name.Entity */
- .ne { color: #cb4b16; } /* Name.Exception */
- .nf { color: #268bd2; } /* Name.Function */
- .nl { color: #93a1a1; } /* Name.Label */
- .nn { color: #93a1a1; } /* Name.Namespace */
- .nx { color: #93a1a1; } /* Name.Other */
- .py { color: #93a1a1; } /* Name.Property */
- .nt { color: #268bd2; } /* Name.Tag */
- .nv { color: #268bd2; } /* Name.Variable */
- .ow { color: #859900; } /* Operator.Word */
- .w { color: #93a1a1; } /* Text.Whitespace */
- .mf { color: #2aa198; } /* Literal.Number.Float */
- .mh { color: #2aa198; } /* Literal.Number.Hex */
- .mi { color: #2aa198; } /* Literal.Number.Integer */
- .mo { color: #2aa198; } /* Literal.Number.Oct */
- .sb { color: #586e75; } /* Literal.String.Backtick */
- .sc { color: #2aa198; } /* Literal.String.Char */
- .sd { color: #93a1a1; } /* Literal.String.Doc */
- .s2 { color: #2aa198; } /* Literal.String.Double */
- .se { color: #cb4b16; } /* Literal.String.Escape */
- .sh { color: #93a1a1; } /* Literal.String.Heredoc */
- .si { color: #2aa198; } /* Literal.String.Interpol */
- .sx { color: #2aa198; } /* Literal.String.Other */
- .sr { color: #dc322f; } /* Literal.String.Regex */
- .s1 { color: #2aa198; } /* Literal.String.Single */
- .ss { color: #2aa198; } /* Literal.String.Symbol */
- .bp { color: #268bd2; } /* Name.Builtin.Pseudo */
- .vc { color: #268bd2; } /* Name.Variable.Class */
- .vg { color: #268bd2; } /* Name.Variable.Global */
- .vi { color: #268bd2; } /* Name.Variable.Instance */
- .il { color: #2aa198; } /* Literal.Number.Integer.Long */
+ .c { color: $solarized-dark-c; } /* Comment */
+ .err { color: $solarized-dark-err; } /* Error */
+ .g { color: $solarized-dark-g; } /* Generic */
+ .k { color: $solarized-dark-k; } /* Keyword */
+ .l { color: $solarized-dark-l; } /* Literal */
+ .n { color: $solarized-dark-n; } /* Name */
+ .o { color: $solarized-dark-o; } /* Operator */
+ .x { color: $solarized-dark-x; } /* Other */
+ .p { color: $solarized-dark-p; } /* Punctuation */
+ .cm { color: $solarized-dark-cm; } /* Comment.Multiline */
+ .cp { color: $solarized-dark-cp; } /* Comment.Preproc */
+ .c1 { color: $solarized-dark-c1; } /* Comment.Single */
+ .cs { color: $solarized-dark-cs; } /* Comment.Special */
+ .gd { color: $solarized-dark-gd; } /* Generic.Deleted */
+ .ge { color: $solarized-dark-ge; font-style: italic; } /* Generic.Emph */
+ .gr { color: $solarized-dark-gr; } /* Generic.Error */
+ .gh { color: $solarized-dark-gh; } /* Generic.Heading */
+ .gi { color: $solarized-dark-gi; } /* Generic.Inserted */
+ .go { color: $solarized-dark-go; } /* Generic.Output */
+ .gp { color: $solarized-dark-gp; } /* Generic.Prompt */
+ .gs { color: $solarized-dark-gs; font-weight: bold; } /* Generic.Strong */
+ .gu { color: $solarized-dark-gu; } /* Generic.Subheading */
+ .gt { color: $solarized-dark-gt; } /* Generic.Traceback */
+ .kc { color: $solarized-dark-kc; } /* Keyword.Constant */
+ .kd { color: $solarized-dark-kd; } /* Keyword.Declaration */
+ .kn { color: $solarized-dark-kn; } /* Keyword.Namespace */
+ .kp { color: $solarized-dark-kp; } /* Keyword.Pseudo */
+ .kr { color: $solarized-dark-kr; } /* Keyword.Reserved */
+ .kt { color: $solarized-dark-kt; } /* Keyword.Type */
+ .ld { color: $solarized-dark-ld; } /* Literal.Date */
+ .m { color: $solarized-dark-m; } /* Literal.Number */
+ .s { color: $solarized-dark-s; } /* Literal.String */
+ .na { color: $solarized-dark-na; } /* Name.Attribute */
+ .nb { color: $solarized-dark-nb; } /* Name.Builtin */
+ .nc { color: $solarized-dark-nc; } /* Name.Class */
+ .no { color: $solarized-dark-no; } /* Name.Constant */
+ .nd { color: $solarized-dark-nd; } /* Name.Decorator */
+ .ni { color: $solarized-dark-ni; } /* Name.Entity */
+ .ne { color: $solarized-dark-ne; } /* Name.Exception */
+ .nf { color: $solarized-dark-nf; } /* Name.Function */
+ .nl { color: $solarized-dark-nl; } /* Name.Label */
+ .nn { color: $solarized-dark-nn; } /* Name.Namespace */
+ .nx { color: $solarized-dark-nx; } /* Name.Other */
+ .py { color: $solarized-dark-py; } /* Name.Property */
+ .nt { color: $solarized-dark-nt; } /* Name.Tag */
+ .nv { color: $solarized-dark-nv; } /* Name.Variable */
+ .ow { color: $solarized-dark-ow; } /* Operator.Word */
+ .w { color: $solarized-dark-w; } /* Text.Whitespace */
+ .mf { color: $solarized-dark-mf; } /* Literal.Number.Float */
+ .mh { color: $solarized-dark-mh; } /* Literal.Number.Hex */
+ .mi { color: $solarized-dark-mi; } /* Literal.Number.Integer */
+ .mo { color: $solarized-dark-mo; } /* Literal.Number.Oct */
+ .sb { color: $solarized-dark-sb; } /* Literal.String.Backtick */
+ .sc { color: $solarized-dark-sc; } /* Literal.String.Char */
+ .sd { color: $solarized-dark-sd; } /* Literal.String.Doc */
+ .s2 { color: $solarized-dark-s2; } /* Literal.String.Double */
+ .se { color: $solarized-dark-se; } /* Literal.String.Escape */
+ .sh { color: $solarized-dark-sh; } /* Literal.String.Heredoc */
+ .si { color: $solarized-dark-si; } /* Literal.String.Interpol */
+ .sx { color: $solarized-dark-sx; } /* Literal.String.Other */
+ .sr { color: $solarized-dark-sr; } /* Literal.String.Regex */
+ .s1 { color: $solarized-dark-s1; } /* Literal.String.Single */
+ .ss { color: $solarized-dark-ss; } /* Literal.String.Symbol */
+ .bp { color: $solarized-dark-bp; } /* Name.Builtin.Pseudo */
+ .vc { color: $solarized-dark-vc; } /* Name.Variable.Class */
+ .vg { color: $solarized-dark-vg; } /* Name.Variable.Global */
+ .vi { color: $solarized-dark-vi; } /* Name.Variable.Instance */
+ .il { color: $solarized-dark-il; } /* Literal.Number.Integer.Long */
}
diff --git a/app/assets/stylesheets/highlight/solarized_light.scss b/app/assets/stylesheets/highlight/solarized_light.scss
index faff353ded7..499a1c108b8 100644
--- a/app/assets/stylesheets/highlight/solarized_light.scss
+++ b/app/assets/stylesheets/highlight/solarized_light.scss
@@ -1,15 +1,99 @@
/* https://gist.github.com/qguv/7936275 */
+/*
+* Solarized light syntax colors
+*/
+$solarized-light-matchline-bg: rgba(255, 255, 255, 0.4);
+$solarized-light-new-bg: rgba(133, 153, 0, 0.2);
+$solarized-light-new-idiff: rgba(133, 153, 0, 0.25);
+$solarized-light-old-bg: rgba(220, 50, 47, 0.2);
+$solarized-light-old-idiff: rgba(220, 50, 47, 0.25);
+$solarized-light-border: #c5d0d4;
+$solarized-light-pre-bg: #002b36;
+$solarized-light-pre-bg: #fdf6e3;
+$solarized-light-pre-color: #586e75;
+$solarized-light-line-bg: #fdf6e3;
+$solarized-light-highlight: #eee8d5;
+$solarized-light-hll-bg: #ddd8c5;
+$solarized-light-c: #93a1a1;
+$solarized-light-err: #586e75;
+$solarized-light-g: #586e75;
+$solarized-light-k: #859900;
+$solarized-light-l: #586e75;
+$solarized-light-n: #586e75;
+$solarized-light-o: #859900;
+$solarized-light-x: #cb4b16;
+$solarized-light-p: #586e75;
+$solarized-light-cm: #93a1a1;
+$solarized-light-cp: #859900;
+$solarized-light-c1: #93a1a1;
+$solarized-light-cs: #859900;
+$solarized-light-gd: #2aa198;
+$solarized-light-ge: #586e75;
+$solarized-light-gr: #dc322f;
+$solarized-light-gh: #cb4b16;
+$solarized-light-gi: #859900;
+$solarized-light-go: #586e75;
+$solarized-light-gp: #586e75;
+$solarized-light-gs: #586e75;
+$solarized-light-gu: #cb4b16;
+$solarized-light-gt: #586e75;
+$solarized-light-kc: #cb4b16;
+$solarized-light-kd: #268bd2;
+$solarized-light-kn: #859900;
+$solarized-light-kp: #859900;
+$solarized-light-kr: #268bd2;
+$solarized-light-kt: #dc322f;
+$solarized-light-ld: #586e75;
+$solarized-light-m: #2aa198;
+$solarized-light-s: #2aa198;
+$solarized-light-na: #586e75;
+$solarized-light-nb: #b58900;
+$solarized-light-nc: #268bd2;
+$solarized-light-no: #cb4b16;
+$solarized-light-nd: #268bd2;
+$solarized-light-ni: #cb4b16;
+$solarized-light-ne: #cb4b16;
+$solarized-light-nf: #268bd2;
+$solarized-light-nl: #586e75;
+$solarized-light-nn: #586e75;
+$solarized-light-nx: #586e75;
+$solarized-light-py: #586e75;
+$solarized-light-nt: #268bd2;
+$solarized-light-nv: #268bd2;
+$solarized-light-ow: #859900;
+$solarized-light-w: #586e75;
+$solarized-light-mf: #2aa198;
+$solarized-light-mh: #2aa198;
+$solarized-light-mi: #2aa198;
+$solarized-light-mo: #2aa198;
+$solarized-light-sb: #93a1a1;
+$solarized-light-sc: #2aa198;
+$solarized-light-sd: #586e75;
+$solarized-light-s2: #2aa198;
+$solarized-light-se: #cb4b16;
+$solarized-light-sh: #586e75;
+$solarized-light-si: #2aa198;
+$solarized-light-sx: #2aa198;
+$solarized-light-sr: #dc322f;
+$solarized-light-s1: #2aa198;
+$solarized-light-ss: #2aa198;
+$solarized-light-bp: #268bd2;
+$solarized-light-vc: #268bd2;
+$solarized-light-vg: #268bd2;
+$solarized-light-vi: #268bd2;
+$solarized-light-il: #2aa198;
+
@mixin matchLine {
color: $black-transparent;
- background: rgba(255, 255, 255, 0.4);
+ background: $solarized-light-matchline-bg;
}
.code.solarized-light {
// Line numbers
.line-numbers,
.diff-line-num {
- background-color: #fdf6e3;
+ background-color: $solarized-light-line-bg;
}
.diff-line-num,
@@ -20,14 +104,14 @@
// Code itself
pre.code,
.diff-line-num {
- border-color: #c5d0d4;
+ border-color: $solarized-light-border;
}
&,
pre.code,
.line_holder .line_content {
- background-color: #fdf6e3;
- color: #586e75;
+ background-color: $solarized-light-pre-bg;
+ color: $solarized-light-pre-color;
}
// Diff line
@@ -38,18 +122,19 @@
td.diff-line-num.hll:not(.empty-cell),
td.line_content.hll:not(.empty-cell) {
- background-color: #ddd8c5;
- border-color: darken(#ddd8c5, 15%);
+ background-color: $solarized-light-hll-bg;
+ border-color: darken($solarized-light-hll-bg, 15%);
}
.diff-line-num.new,
.line_content.new {
- @include diff_background(rgba(133, 153, 0, 0.2), rgba(133, 153, 0, 0.25), #c5d0d4);
+ @include diff_background($solarized-light-new-bg,
+ $solarized-light-new-idiff, $solarized-light-border);
}
.diff-line-num.old,
.line_content.old {
- @include diff_background(rgba(220, 50, 47, 0.2), rgba(220, 50, 47, 0.25), #c5d0d4);
+ @include diff_background($solarized-light-old-bg, $solarized-light-old-idiff, $solarized-light-border);
}
.line_content.match {
@@ -59,12 +144,12 @@
// highlight line via anchor
pre .hll {
- background-color: #ddd8c5 !important;
+ background-color: $solarized-light-hll-bg !important;
}
// Search result highlight
span.highlight_word {
- background-color: #eee8d5 !important;
+ background-color: $solarized-light-highlight !important;
}
/* Solarized Light
@@ -85,72 +170,72 @@
green #859900 operators, other keywords
*/
- .c { color: #93a1a1; } /* Comment */
- .err { color: #586e75; } /* Error */
- .g { color: #586e75; } /* Generic */
- .k { color: #859900; } /* Keyword */
- .l { color: #586e75; } /* Literal */
- .n { color: #586e75; } /* Name */
- .o { color: #859900; } /* Operator */
- .x { color: #cb4b16; } /* Other */
- .p { color: #586e75; } /* Punctuation */
- .cm { color: #93a1a1; } /* Comment.Multiline */
- .cp { color: #859900; } /* Comment.Preproc */
- .c1 { color: #93a1a1; } /* Comment.Single */
- .cs { color: #859900; } /* Comment.Special */
- .gd { color: #2aa198; } /* Generic.Deleted */
- .ge { color: #586e75; font-style: italic; } /* Generic.Emph */
- .gr { color: #dc322f; } /* Generic.Error */
- .gh { color: #cb4b16; } /* Generic.Heading */
- .gi { color: #859900; } /* Generic.Inserted */
- .go { color: #586e75; } /* Generic.Output */
- .gp { color: #586e75; } /* Generic.Prompt */
- .gs { color: #586e75; font-weight: bold; } /* Generic.Strong */
- .gu { color: #cb4b16; } /* Generic.Subheading */
- .gt { color: #586e75; } /* Generic.Traceback */
- .kc { color: #cb4b16; } /* Keyword.Constant */
- .kd { color: #268bd2; } /* Keyword.Declaration */
- .kn { color: #859900; } /* Keyword.Namespace */
- .kp { color: #859900; } /* Keyword.Pseudo */
- .kr { color: #268bd2; } /* Keyword.Reserved */
- .kt { color: #dc322f; } /* Keyword.Type */
- .ld { color: #586e75; } /* Literal.Date */
- .m { color: #2aa198; } /* Literal.Number */
- .s { color: #2aa198; } /* Literal.String */
- .na { color: #586e75; } /* Name.Attribute */
- .nb { color: #b58900; } /* Name.Builtin */
- .nc { color: #268bd2; } /* Name.Class */
- .no { color: #cb4b16; } /* Name.Constant */
- .nd { color: #268bd2; } /* Name.Decorator */
- .ni { color: #cb4b16; } /* Name.Entity */
- .ne { color: #cb4b16; } /* Name.Exception */
- .nf { color: #268bd2; } /* Name.Function */
- .nl { color: #586e75; } /* Name.Label */
- .nn { color: #586e75; } /* Name.Namespace */
- .nx { color: #586e75; } /* Name.Other */
- .py { color: #586e75; } /* Name.Property */
- .nt { color: #268bd2; } /* Name.Tag */
- .nv { color: #268bd2; } /* Name.Variable */
- .ow { color: #859900; } /* Operator.Word */
- .w { color: #586e75; } /* Text.Whitespace */
- .mf { color: #2aa198; } /* Literal.Number.Float */
- .mh { color: #2aa198; } /* Literal.Number.Hex */
- .mi { color: #2aa198; } /* Literal.Number.Integer */
- .mo { color: #2aa198; } /* Literal.Number.Oct */
- .sb { color: #93a1a1; } /* Literal.String.Backtick */
- .sc { color: #2aa198; } /* Literal.String.Char */
- .sd { color: #586e75; } /* Literal.String.Doc */
- .s2 { color: #2aa198; } /* Literal.String.Double */
- .se { color: #cb4b16; } /* Literal.String.Escape */
- .sh { color: #586e75; } /* Literal.String.Heredoc */
- .si { color: #2aa198; } /* Literal.String.Interpol */
- .sx { color: #2aa198; } /* Literal.String.Other */
- .sr { color: #dc322f; } /* Literal.String.Regex */
- .s1 { color: #2aa198; } /* Literal.String.Single */
- .ss { color: #2aa198; } /* Literal.String.Symbol */
- .bp { color: #268bd2; } /* Name.Builtin.Pseudo */
- .vc { color: #268bd2; } /* Name.Variable.Class */
- .vg { color: #268bd2; } /* Name.Variable.Global */
- .vi { color: #268bd2; } /* Name.Variable.Instance */
- .il { color: #2aa198; } /* Literal.Number.Integer.Long */
+ .c { color: $solarized-light-c; } /* Comment */
+ .err { color: $solarized-light-err; } /* Error */
+ .g { color: $solarized-light-g; } /* Generic */
+ .k { color: $solarized-light-k; } /* Keyword */
+ .l { color: $solarized-light-l; } /* Literal */
+ .n { color: $solarized-light-n; } /* Name */
+ .o { color: $solarized-light-o; } /* Operator */
+ .x { color: $solarized-light-x; } /* Other */
+ .p { color: $solarized-light-p; } /* Punctuation */
+ .cm { color: $solarized-light-cm; } /* Comment.Multiline */
+ .cp { color: $solarized-light-cp; } /* Comment.Preproc */
+ .c1 { color: $solarized-light-c1; } /* Comment.Single */
+ .cs { color: $solarized-light-cs; } /* Comment.Special */
+ .gd { color: $solarized-light-gd; } /* Generic.Deleted */
+ .ge { color: $solarized-light-ge; font-style: italic; } /* Generic.Emph */
+ .gr { color: $solarized-light-gr; } /* Generic.Error */
+ .gh { color: $solarized-light-gh; } /* Generic.Heading */
+ .gi { color: $solarized-light-gi; } /* Generic.Inserted */
+ .go { color: $solarized-light-go; } /* Generic.Output */
+ .gp { color: $solarized-light-gp; } /* Generic.Prompt */
+ .gs { color: $solarized-light-gs; font-weight: bold; } /* Generic.Strong */
+ .gu { color: $solarized-light-gu; } /* Generic.Subheading */
+ .gt { color: $solarized-light-gt; } /* Generic.Traceback */
+ .kc { color: $solarized-light-kc; } /* Keyword.Constant */
+ .kd { color: $solarized-light-kd; } /* Keyword.Declaration */
+ .kn { color: $solarized-light-kn; } /* Keyword.Namespace */
+ .kp { color: $solarized-light-kp; } /* Keyword.Pseudo */
+ .kr { color: $solarized-light-kr; } /* Keyword.Reserved */
+ .kt { color: $solarized-light-kt; } /* Keyword.Type */
+ .ld { color: $solarized-light-ld; } /* Literal.Date */
+ .m { color: $solarized-light-m; } /* Literal.Number */
+ .s { color: $solarized-light-s; } /* Literal.String */
+ .na { color: $solarized-light-na; } /* Name.Attribute */
+ .nb { color: $solarized-light-nb; } /* Name.Builtin */
+ .nc { color: $solarized-light-nc; } /* Name.Class */
+ .no { color: $solarized-light-no; } /* Name.Constant */
+ .nd { color: $solarized-light-nd; } /* Name.Decorator */
+ .ni { color: $solarized-light-ni; } /* Name.Entity */
+ .ne { color: $solarized-light-ne; } /* Name.Exception */
+ .nf { color: $solarized-light-nf; } /* Name.Function */
+ .nl { color: $solarized-light-nl; } /* Name.Label */
+ .nn { color: $solarized-light-nn; } /* Name.Namespace */
+ .nx { color: $solarized-light-nx; } /* Name.Other */
+ .py { color: $solarized-light-py; } /* Name.Property */
+ .nt { color: $solarized-light-nt; } /* Name.Tag */
+ .nv { color: $solarized-light-nv; } /* Name.Variable */
+ .ow { color: $solarized-light-ow; } /* Operator.Word */
+ .w { color: $solarized-light-w; } /* Text.Whitespace */
+ .mf { color: $solarized-light-mf; } /* Literal.Number.Float */
+ .mh { color: $solarized-light-mh; } /* Literal.Number.Hex */
+ .mi { color: $solarized-light-mi; } /* Literal.Number.Integer */
+ .mo { color: $solarized-light-mo; } /* Literal.Number.Oct */
+ .sb { color: $solarized-light-sb; } /* Literal.String.Backtick */
+ .sc { color: $solarized-light-sc; } /* Literal.String.Char */
+ .sd { color: $solarized-light-sd; } /* Literal.String.Doc */
+ .s2 { color: $solarized-light-s2; } /* Literal.String.Double */
+ .se { color: $solarized-light-se; } /* Literal.String.Escape */
+ .sh { color: $solarized-light-sh; } /* Literal.String.Heredoc */
+ .si { color: $solarized-light-si; } /* Literal.String.Interpol */
+ .sx { color: $solarized-light-sx; } /* Literal.String.Other */
+ .sr { color: $solarized-light-sr; } /* Literal.String.Regex */
+ .s1 { color: $solarized-light-s1; } /* Literal.String.Single */
+ .ss { color: $solarized-light-ss; } /* Literal.String.Symbol */
+ .bp { color: $solarized-light-bp; } /* Name.Builtin.Pseudo */
+ .vc { color: $solarized-light-vc; } /* Name.Variable.Class */
+ .vg { color: $solarized-light-vg; } /* Name.Variable.Global */
+ .vi { color: $solarized-light-vi; } /* Name.Variable.Instance */
+ .il { color: $solarized-light-il; } /* Literal.Number.Integer.Long */
}
diff --git a/app/assets/stylesheets/highlight/white.scss b/app/assets/stylesheets/highlight/white.scss
index d5367d5f3f0..1adab3ffd94 100644
--- a/app/assets/stylesheets/highlight/white.scss
+++ b/app/assets/stylesheets/highlight/white.scss
@@ -1,5 +1,72 @@
/* https://github.com/aahan/pygments-github-style */
+/*
+* White Syntax Colors
+*/
+$white-code-color: #333;
+$white-highlight: #fafe3d;
+$white-pre-hll-bg: #f8eec7;
+$white-hll-bg: #f8f8f8;
+$white-c: #998;
+$white-err: #a61717;
+$white-err-bg: #e3d2d2;
+$white-cm: #998;
+$white-cp: #999;
+$white-c1: #998;
+$white-cs: #999;
+$white-gd: $black;
+$white-gd-bg: #fdd;
+$white-gd-x: $black;
+$white-gd-x-bg: #faa;
+$white-gr: #a00;
+$white-gh: #999;
+$white-gi: $black;
+$white-gi-bg: #dfd;
+$white-gi-x: $black;
+$white-gi-x-bg: #afa;
+$white-go: #888;
+$white-gp: #555;
+$white-gu: #800080;
+$white-gt: #a00;
+$white-kt: #458;
+$white-m: #099;
+$white-s: #d14;
+$white-n: #333;
+$white-na: teal;
+$white-nb: #0086b3;
+$white-nc: #458;
+$white-no: teal;
+$white-ni: purple;
+$white-ne: #900;
+$white-nf: #900;
+$white-nn: #555;
+$white-nt: navy;
+$white-nv: teal;
+$white-w: #bbb;
+$white-mf: #099;
+$white-mh: #099;
+$white-mi: #099;
+$white-mo: #099;
+$white-sb: #d14;
+$white-sc: #d14;
+$white-sd: #d14;
+$white-s2: #d14;
+$white-se: #d14;
+$white-sh: #d14;
+$white-si: #d14;
+$white-sx: #d14;
+$white-sr: #009926;
+$white-s1: #d14;
+$white-ss: #990073;
+$white-bp: #999;
+$white-vc: teal;
+$white-vg: teal;
+$white-vi: teal;
+$white-il: #099;
+$white-gc-color: #999;
+$white-gc-bg: #eaf2f5;
+
+
@mixin matchLine {
color: $black-transparent;
background-color: $match-line;
@@ -26,8 +93,8 @@
&,
pre.code,
.line_holder .line_content {
- background-color: #fff;
- color: #333;
+ background-color: $white-light;
+ color: $white-code-color;
}
// Diff line
@@ -83,75 +150,75 @@
// highlight line via anchor
pre .hll {
- background-color: #f8eec7 !important;
+ background-color: $white-pre-hll-bg !important;
}
// Search result highlight
span.highlight_word {
- background-color: #fafe3d !important;
+ background-color: $white-highlight !important;
}
- .hll { background-color: #f8f8f8; }
- .c { color: #998; font-style: italic; }
- .err { color: #a61717; background-color: #e3d2d2; }
+ .hll { background-color: $white-hll-bg; }
+ .c { color: $white-c; font-style: italic; }
+ .err { color: $white-err; background-color: $white-err-bg; }
.k { font-weight: bold; }
.o { font-weight: bold; }
- .cm { color: #998; font-style: italic; }
- .cp { color: #999; font-weight: bold; }
- .c1 { color: #998; font-style: italic; }
- .cs { color: #999; font-weight: bold; font-style: italic; }
- .gd { color: #000; background-color: #fdd; }
- .gd .x { color: #000; background-color: #faa; }
+ .cm { color: $white-cm; font-style: italic; }
+ .cp { color: $white-cp; font-weight: bold; }
+ .c1 { color: $white-c1; font-style: italic; }
+ .cs { color: $white-cs; font-weight: bold; font-style: italic; }
+ .gd { color: $white-gd; background-color: $white-gd-bg; }
+ .gd .x { color: $white-gd-x; background-color: $white-gd-x-bg; }
.ge { font-style: italic; }
- .gr { color: #a00; }
- .gh { color: #999; }
- .gi { color: #000; background-color: #dfd; }
- .gi .x { color: #000; background-color: #afa; }
- .go { color: #888; }
- .gp { color: #555; }
+ .gr { color: $white-gr; }
+ .gh { color: $white-gh; }
+ .gi { color: $white-gi; background-color: $white-gi-bg; }
+ .gi .x { color: $white-gi-x; background-color: $white-gi-x-bg; }
+ .go { color: $white-go; }
+ .gp { color: $white-gp; }
.gs { font-weight: bold; }
- .gu { color: #800080; font-weight: bold; }
- .gt { color: #a00; }
+ .gu { color: $white-gu; font-weight: bold; }
+ .gt { color: $white-gt; }
.kc { font-weight: bold; }
.kd { font-weight: bold; }
.kn { font-weight: bold; }
.kp { font-weight: bold; }
.kr { font-weight: bold; }
- .kt { color: #458; font-weight: bold; }
- .m { color: #099; }
- .s { color: #d14; }
- .n { color: #333; }
- .na { color: teal; }
- .nb { color: #0086b3; }
- .nc { color: #458; font-weight: bold; }
- .no { color: teal; }
- .ni { color: purple; }
- .ne { color: #900; font-weight: bold; }
- .nf { color: #900; font-weight: bold; }
- .nn { color: #555; }
- .nt { color: navy; }
- .nv { color: teal; }
+ .kt { color: $white-kt; font-weight: bold; }
+ .m { color: $white-m; }
+ .s { color: $white-s; }
+ .n { color: $white-n; }
+ .na { color: $white-na; }
+ .nb { color: $white-nb; }
+ .nc { color: $white-nc; font-weight: bold; }
+ .no { color: $white-no; }
+ .ni { color: $white-ni; }
+ .ne { color: $white-ne; font-weight: bold; }
+ .nf { color: $white-nf; font-weight: bold; }
+ .nn { color: $white-nn; }
+ .nt { color: $white-nt; }
+ .nv { color: $white-nv; }
.ow { font-weight: bold; }
- .w { color: #bbb; }
- .mf { color: #099; }
- .mh { color: #099; }
- .mi { color: #099; }
- .mo { color: #099; }
- .sb { color: #d14; }
- .sc { color: #d14; }
- .sd { color: #d14; }
- .s2 { color: #d14; }
- .se { color: #d14; }
- .sh { color: #d14; }
- .si { color: #d14; }
- .sx { color: #d14; }
- .sr { color: #009926; }
- .s1 { color: #d14; }
- .ss { color: #990073; }
- .bp { color: #999; }
- .vc { color: teal; }
- .vg { color: teal; }
- .vi { color: teal; }
- .il { color: #099; }
- .gc { color: #999; background-color: #eaf2f5; }
+ .w { color: $white-w; }
+ .mf { color: $white-mf; }
+ .mh { color: $white-mh; }
+ .mi { color: $white-mi; }
+ .mo { color: $white-mo; }
+ .sb { color: $white-sb; }
+ .sc { color: $white-sc; }
+ .sd { color: $white-sd; }
+ .s2 { color: $white-s2; }
+ .se { color: $white-se; }
+ .sh { color: $white-sh; }
+ .si { color: $white-si; }
+ .sx { color: $white-sx; }
+ .sr { color: $white-sr; }
+ .s1 { color: $white-s1; }
+ .ss { color: $white-ss; }
+ .bp { color: $white-bp; }
+ .vc { color: $white-vc; }
+ .vg { color: $white-vg; }
+ .vi { color: $white-vi; }
+ .il { color: $white-il; }
+ .gc { color: $white-gc-color; background-color: $white-gc-bg; }
}
diff --git a/app/assets/stylesheets/mailers/devise.scss b/app/assets/stylesheets/mailers/devise.scss
index b2bce482fde..9f613710cf4 100644
--- a/app/assets/stylesheets/mailers/devise.scss
+++ b/app/assets/stylesheets/mailers/devise.scss
@@ -1,3 +1,5 @@
+@import "framework/variables";
+
// NOTE: This stylesheet is for the exclusive use of the `devise_mailer` layout
// used for Devise email templates, and _should not_ be included in any
// application stylesheets.
@@ -46,7 +48,7 @@ table {
&#body {
background-color: $message-background-color;
- border: 1px solid #000;
+ border: 1px solid $black;
border-radius: 4px;
margin: 0 auto;
width: 600px;
diff --git a/app/assets/stylesheets/mailers/highlighted_diff_email.scss b/app/assets/stylesheets/mailers/highlighted_diff_email.scss
index 8d1a6020ca4..024b4df6bd0 100644
--- a/app/assets/stylesheets/mailers/highlighted_diff_email.scss
+++ b/app/assets/stylesheets/mailers/highlighted_diff_email.scss
@@ -10,8 +10,72 @@
// preference): plain class selectors, type (element name) selectors, or
// explicit child selectors.
+/*
+* Highlighted Diff Email Syntax Colors
+*/
+$highlighted-highlight-word: #fafe3d;
+$highlighted-hll-bg: #f8f8f8;
+$highlighted-c: #998;
+$highlighted-err: #a61717;
+$highlighted-err-bg: #e3d2d2;
+$highlighted-cm: #998;
+$highlighted-cp: #999;
+$highlighted-c1: #998;
+$highlighted-cs: #999;
+$highlighted-gd: #000;
+$highlighted-gd-bg: #fdd;
+$highlighted-gd-x: #000;
+$highlighted-gd-x-bg: #faa;
+$highlighted-gr: #a00;
+$highlighted-gh: #999;
+$highlighted-gi: #000;
+$highlighted-gi-bg: #dfd;
+$highlighted-gi-x: #000;
+$highlighted-gi-x-bg: #afa;
+$highlighted-go: #888;
+$highlighted-gp: #555;
+$highlighted-gu: #800080;
+$highlighted-gt: #a00;
+$highlighted-kt: #458;
+$highlighted-m: #099;
+$highlighted-s: #d14;
+$highlighted-n: #333;
+$highlighted-na: teal;
+$highlighted-nb: #0086b3;
+$highlighted-nc: #458;
+$highlighted-no: teal;
+$highlighted-ni: purple;
+$highlighted-ne: #900;
+$highlighted-nf: #900;
+$highlighted-nn: #555;
+$highlighted-nt: navy;
+$highlighted-nv: teal;
+$highlighted-w: #bbb;
+$highlighted-mf: #099;
+$highlighted-mh: #099;
+$highlighted-mi: #099;
+$highlighted-mo: #099;
+$highlighted-sb: #d14;
+$highlighted-sc: #d14;
+$highlighted-sd: #d14;
+$highlighted-s2: #d14;
+$highlighted-se: #d14;
+$highlighted-sh: #d14;
+$highlighted-si: #d14;
+$highlighted-sx: #d14;
+$highlighted-sr: #009926;
+$highlighted-s1: #d14;
+$highlighted-ss: #990073;
+$highlighted-bp: #999;
+$highlighted-vc: teal;
+$highlighted-vg: teal;
+$highlighted-vi: teal;
+$highlighted-il: #099;
+$highlighted-gc: #999;
+$highlighted-gc-bg: #eaf2f5;
+
.code {
- background-color: #fff;
+ background-color: $white-light;
font-family: monospace;
font-size: $code_font_size;
-premailer-cellpadding: 0;
@@ -75,69 +139,69 @@ pre {
}
span.highlight_word {
- background-color: #fafe3d !important;
+ background-color: $highlighted-highlight-word !important;
}
-.hll { background-color: #f8f8f8; }
-.c { color: #998; font-style: italic; }
-.err { color: #a61717; background-color: #e3d2d2; }
+.hll { background-color: $highlighted-hll-bg; }
+.c { color: $highlighted-c; font-style: italic; }
+.err { color: $highlighted-err; background-color: $highlighted-err-bg; }
.k { font-weight: bold; }
.o { font-weight: bold; }
-.cm { color: #998; font-style: italic; }
-.cp { color: #999; font-weight: bold; }
-.c1 { color: #998; font-style: italic; }
-.cs { color: #999; font-weight: bold; font-style: italic; }
-.gd { color: #000; background-color: #fdd; }
-.gd .x { color: #000; background-color: #faa; }
+.cm { color: $highlighted-cm; font-style: italic; }
+.cp { color: $highlighted-cp; font-weight: bold; }
+.c1 { color: $highlighted-c1; font-style: italic; }
+.cs { color: $highlighted-cs; font-weight: bold; font-style: italic; }
+.gd { color: $highlighted-gd; background-color: $highlighted-gd-bg; }
+.gd .x { color: $highlighted-gd; background-color: $highlighted-gd-x-bg; }
.ge { font-style: italic; }
-.gr { color: #a00; }
-.gh { color: #999; }
-.gi { color: #000; background-color: #dfd; }
-.gi .x { color: #000; background-color: #afa; }
-.go { color: #888; }
-.gp { color: #555; }
+.gr { color: $highlighted-gr; }
+.gh { color: $highlighted-gh; }
+.gi { color: $highlighted-gi; background-color: $highlighted-gi-bg; }
+.gi .x { color: $highlighted-gi; background-color: $highlighted-gi-x-bg; }
+.go { color: $highlighted-go; }
+.gp { color: $highlighted-gp; }
.gs { font-weight: bold; }
-.gu { color: #800080; font-weight: bold; }
-.gt { color: #a00; }
+.gu { color: $highlighted-gu; font-weight: bold; }
+.gt { color: $highlighted-gt; }
.kc { font-weight: bold; }
.kd { font-weight: bold; }
.kn { font-weight: bold; }
.kp { font-weight: bold; }
.kr { font-weight: bold; }
-.kt { color: #458; font-weight: bold; }
-.m { color: #099; }
-.s { color: #d14; }
-.n { color: #333; }
-.na { color: teal; }
-.nb { color: #0086b3; }
-.nc { color: #458; font-weight: bold; }
-.no { color: teal; }
-.ni { color: purple; }
-.ne { color: #900; font-weight: bold; }
-.nf { color: #900; font-weight: bold; }
-.nn { color: #555; }
-.nt { color: navy; }
-.nv { color: teal; }
+.kt { color: $highlighted-kt; font-weight: bold; }
+.m { color: $highlighted-m; }
+.s { color: $highlighted-s; }
+.n { color: $highlighted-n; }
+.na { color: $highlighted-na; }
+.nb { color: $highlighted-nb; }
+.nc { color: $highlighted-nc; font-weight: bold; }
+.no { color: $highlighted-no; }
+.ni { color: $highlighted-ni; }
+.ne { color: $highlighted-ne; font-weight: bold; }
+.nf { color: $highlighted-nf; font-weight: bold; }
+.nn { color: $highlighted-nn; }
+.nt { color: $highlighted-nt; }
+.nv { color: $highlighted-nv; }
.ow { font-weight: bold; }
-.w { color: #bbb; }
-.mf { color: #099; }
-.mh { color: #099; }
-.mi { color: #099; }
-.mo { color: #099; }
-.sb { color: #d14; }
-.sc { color: #d14; }
-.sd { color: #d14; }
-.s2 { color: #d14; }
-.se { color: #d14; }
-.sh { color: #d14; }
-.si { color: #d14; }
-.sx { color: #d14; }
-.sr { color: #009926; }
-.s1 { color: #d14; }
-.ss { color: #990073; }
-.bp { color: #999; }
-.vc { color: teal; }
-.vg { color: teal; }
-.vi { color: teal; }
-.il { color: #099; }
-.gc { color: #999; background-color: #eaf2f5; }
+.w { color: $highlighted-w; }
+.mf { color: $highlighted-mf; }
+.mh { color: $highlighted-mh; }
+.mi { color: $highlighted-mi; }
+.mo { color: $highlighted-mo; }
+.sb { color: $highlighted-sb; }
+.sc { color: $highlighted-sc; }
+.sd { color: $highlighted-sd; }
+.s2 { color: $highlighted-s2; }
+.se { color: $highlighted-se; }
+.sh { color: $highlighted-sh; }
+.si { color: $highlighted-si; }
+.sx { color: $highlighted-sx; }
+.sr { color: $highlighted-sr; }
+.s1 { color: $highlighted-s1; }
+.ss { color: $highlighted-ss; }
+.bp { color: $highlighted-bp; }
+.vc { color: $highlighted-vc; }
+.vg { color: $highlighted-vg; }
+.vi { color: $highlighted-vi; }
+.il { color: $highlighted-il; }
+.gc { color: $highlighted-gc; background-color: $highlighted-gc-bg; }
diff --git a/app/assets/stylesheets/notify.scss b/app/assets/stylesheets/notify.scss
index ced8c4a9907..ddc382362f7 100644
--- a/app/assets/stylesheets/notify.scss
+++ b/app/assets/stylesheets/notify.scss
@@ -1,3 +1,5 @@
+@import "framework/variables";
+
img {
max-width: 100%;
height: auto;
@@ -5,12 +7,12 @@ img {
p.details {
font-style: italic;
- color: #777;
+ color: $notify-details;
}
.footer > p {
font-size: small;
- color: #777;
+ color: $notify-footer;
}
pre.commit-message {
@@ -21,10 +23,10 @@ pre.commit-message {
text-decoration: none;
> .new-file {
- color: #090;
+ color: $notify-new-file;
}
> .deleted-file {
- color: #b00;
+ color: $notify-deleted-file;
}
}
diff --git a/app/assets/stylesheets/pages/admin.scss b/app/assets/stylesheets/pages/admin.scss
deleted file mode 100644
index 14812e171fd..00000000000
--- a/app/assets/stylesheets/pages/admin.scss
+++ /dev/null
@@ -1,168 +0,0 @@
-/**
- * Admin area
- *
- */
-.admin-dashboard {
- .data {
- a {
- h1 {
- line-height: 48px;
- font-size: 48px;
- padding: 20px;
- text-align: center;
- font-weight: normal;
- }
- }
- }
-
- .str-truncated {
- max-width: 60%;
- }
-}
-
-.admin-filter form {
- .select2-container {
- width: 100%;
- }
-
- .controls {
- margin-left: 130px;
- }
-
- .form-actions {
- padding-left: 130px;
- background: #fff;
- }
-
- .visibility-levels {
- .controls {
- margin-bottom: 9px;
- }
-
- i {
- color: inherit;
- }
- }
-}
-
-.broadcast-messages {
- .message {
- line-height: 2;
- }
-}
-
-.broadcast-message {
- @extend .alert-warning;
- padding: 10px;
- text-align: center;
-
- > div,
- p {
- display: inline;
- margin: 0;
-
- a {
- color: inherit;
- text-decoration: underline;
- }
- }
-}
-
-.broadcast-message-preview {
- @extend .broadcast-message;
- margin-bottom: 20px;
-}
-
-// Users List
-
-.users-list {
- .user-row {
- display: -webkit-flex;
- display: -ms-flexbox;
- display: flex;
- white-space: nowrap;
- }
-
- .user-details {
- flex: 1 1 auto;
- overflow: hidden;
- padding-right: 8px;
- }
-
- .user-name {
- display: inline-block;
- font-weight: 600;
- }
-
- .user-name,
- .user-email {
- overflow: hidden;
- text-overflow: ellipsis;
- }
-
- .dropdown {
- .btn-block {
- margin-bottom: 0;
- line-height: inherit;
- }
- }
-
- .label-default {
- color: $btn-transparent-color;
- }
-}
-
-.abuse-reports {
- .table {
- table-layout: fixed;
- }
-
- .subheading {
- padding-bottom: $gl-padding;
- }
-
- .message {
- word-wrap: break-word;
- }
-
- .btn {
- white-space: normal;
- padding: $gl-btn-padding;
- }
-
- th {
- width: 15%;
-
- &.wide {
- width: 55%;
- }
- }
-
- @media (max-width: $screen-sm-max) {
- th {
- width: 100%;
- }
-
- td {
- width: 100%;
- float: left;
- }
- }
-
- .no-reports {
- .emoji-icon {
- margin-left: $btn-side-margin;
- margin-top: 3px;
- }
-
- span {
- font-size: 19px;
- }
- }
-}
-
-.admin-builds-table {
- .ci-table td:last-child {
- min-width: 120px;
- }
-}
diff --git a/app/assets/stylesheets/pages/boards.scss b/app/assets/stylesheets/pages/boards.scss
index 82f36f24867..0d9cf679e7c 100644
--- a/app/assets/stylesheets/pages/boards.scss
+++ b/app/assets/stylesheets/pages/boards.scss
@@ -145,7 +145,7 @@
.board-blank-state {
height: calc(100% - 49px);
padding: $gl-padding;
- background-color: #fff;
+ background-color: $white-light;
}
.board-blank-state-list {
@@ -191,9 +191,9 @@
.card {
position: relative;
padding: 10px $gl-padding;
- background: #fff;
+ background: $white-light;
border-radius: $border-radius-default;
- box-shadow: 0 1px 2px rgba(186, 186, 186, 0.5);
+ box-shadow: 0 1px 2px $issue-boards-card-shadow;
list-style: none;
&:not(:last-child) {
diff --git a/app/assets/stylesheets/pages/builds.scss b/app/assets/stylesheets/pages/builds.scss
index 48f11eb2552..dcc13f6d74a 100644
--- a/app/assets/stylesheets/pages/builds.scss
+++ b/app/assets/stylesheets/pages/builds.scss
@@ -1,7 +1,7 @@
.build-page {
pre.trace {
- background: #111;
- color: #fff;
+ background: $builds-trace-bg;
+ color: $white-light;
font-family: $monospace_font;
white-space: pre-wrap;
overflow: auto;
@@ -64,6 +64,7 @@
@media (max-width: $screen-sm-max) {
padding-right: 40px;
+ margin-top: 6px;
.btn-inverted {
display: none;
diff --git a/app/assets/stylesheets/pages/ci_projects.scss b/app/assets/stylesheets/pages/ci_projects.scss
index 87c453a7a27..d1cd1e5d848 100644
--- a/app/assets/stylesheets/pages/ci_projects.scss
+++ b/app/assets/stylesheets/pages/ci_projects.scss
@@ -1,7 +1,7 @@
.ci-body {
.project-title {
margin: 0;
- color: #444;
+ color: $common-gray-dark;
font-size: 20px;
line-height: 1.5;
}
diff --git a/app/assets/stylesheets/pages/commit.scss b/app/assets/stylesheets/pages/commit.scss
index ddc9d0e2b1a..bf656d0e28e 100644
--- a/app/assets/stylesheets/pages/commit.scss
+++ b/app/assets/stylesheets/pages/commit.scss
@@ -5,7 +5,7 @@
.commit-author,
.commit-committer {
display: block;
- color: #999;
+ color: $commit-committer-color;
font-weight: normal;
font-style: italic;
}
@@ -113,17 +113,17 @@
overflow: hidden; // See https://gitlab.com/gitlab-org/gitlab-ce/issues/13987
.max-width-marker {
width: 72ch;
- color: rgba(0, 0, 0, 0.0);
+ color: $commit-max-width-marker-color;
font-family: inherit;
left: $left;
height: 100%;
- border-right: 1px solid mix($input-border, white);
+ border-right: 1px solid mix($input-border, $white-light);
position: absolute;
z-index: 1;
}
> textarea {
- background-color: rgba(0, 0, 0, 0.0);
+ background-color: $commit-message-text-area-bg;
font-family: inherit;
padding-left: $left;
position: relative;
diff --git a/app/assets/stylesheets/pages/commits.scss b/app/assets/stylesheets/pages/commits.scss
index 83ffa0e1d39..c29b5fdea78 100644
--- a/app/assets/stylesheets/pages/commits.scss
+++ b/app/assets/stylesheets/pages/commits.scss
@@ -8,8 +8,8 @@
.commit-header {
padding: 5px 10px;
background-color: $background-color;
- border-top: 1px solid #eee;
- border-bottom: 1px solid #eee;
+ border-top: 1px solid $gray-darker;
+ border-bottom: 1px solid $gray-darker;
font-size: 14px;
&:first-child {
@@ -94,7 +94,7 @@
}
&:not(:last-child) {
- border-bottom: 1px solid #eee;
+ border-bottom: 1px solid $gray-darker;
}
a,
@@ -201,7 +201,7 @@
.bar {
position: absolute;
height: 4px;
- background-color: #ccc;
+ background-color: $divergence-graph-bar-bg;
}
.bar-behind {
@@ -218,7 +218,7 @@
padding-top: 6px;
padding-bottom: 0;
font-size: 12px;
- color: #333;
+ color: $gl-title-color;
display: block;
}
@@ -239,6 +239,6 @@
height: 18px;
margin: 5px 0 0;
float: left;
- background-color: #ccc;
+ background-color: $divergence-graph-separator-bg;
}
}
diff --git a/app/assets/stylesheets/pages/confirmation.scss b/app/assets/stylesheets/pages/confirmation.scss
deleted file mode 100644
index 81e5cee240d..00000000000
--- a/app/assets/stylesheets/pages/confirmation.scss
+++ /dev/null
@@ -1,32 +0,0 @@
-.well-confirmation {
- margin-bottom: 20px;
- border-bottom: 1px solid #eee;
-
- > h1,
- h2,
- h3,
- h4,
- h5,
- h6 {
- font-weight: 400;
- }
-
- .lead {
- margin-bottom: 20px;
- }
-
- ul,
- ol {
- padding-left: 0;
- }
-
- li {
- list-style-type: none;
- }
-}
-
-.confirmation-content {
- a {
- color: $md-link-color;
- }
-}
diff --git a/app/assets/stylesheets/pages/cycle_analytics.scss b/app/assets/stylesheets/pages/cycle_analytics.scss
index 0b4930ec98f..57146e1fccd 100644
--- a/app/assets/stylesheets/pages/cycle_analytics.scss
+++ b/app/assets/stylesheets/pages/cycle_analytics.scss
@@ -109,7 +109,7 @@
&.title {
line-height: 19px;
- font-size: 15px;
+ font-size: 14px;
font-weight: 600;
color: $gl-title-color;
}
@@ -141,9 +141,9 @@
.dismiss-icon {
position: absolute;
- right: $cycle-analytics-box-padding;
+ right: $cycle-analytics-dismiss-icon-color;
cursor: pointer;
- color: #b2b2b2;
+ color: $cycle-analytics-dismiss-icon-color;
}
.svg-container {
diff --git a/app/assets/stylesheets/pages/dashboard.scss b/app/assets/stylesheets/pages/dashboard.scss
deleted file mode 100644
index 016bab104eb..00000000000
--- a/app/assets/stylesheets/pages/dashboard.scss
+++ /dev/null
@@ -1,43 +0,0 @@
-.dashboard {
- .side {
- .panel {
- .panel-heading {
- background: $background-color;
- border-top-left-radius: 0;
- }
-
- border-top-left-radius: 0;
- }
- }
-}
-
-.dashboard-search-filter {
- padding: 5px;
-
- .search-text-input {
- float: left;
- @extend .col-md-2;
- }
-
- .btn {
- margin-left: 5px;
- float: left;
- }
-}
-
-.project-access-icon {
- margin-left: 10px;
- float: left;
- margin-right: 15px;
- margin-bottom: 15px;
-
- i {
- color: #888;
- }
-}
-
-.dash-project-access-icon {
- float: left;
- margin-right: 5px;
- width: 16px;
-}
diff --git a/app/assets/stylesheets/pages/detail_page.scss b/app/assets/stylesheets/pages/detail_page.scss
index 0f0c0abe7ae..80baebd5ea3 100644
--- a/app/assets/stylesheets/pages/detail_page.scss
+++ b/app/assets/stylesheets/pages/detail_page.scss
@@ -1,16 +1,16 @@
.detail-page-header {
padding: $gl-padding-top 0;
border-bottom: 1px solid $border-color;
- color: #5c5d5e;
+ color: $gl-text-color-dark;
font-size: 16px;
line-height: 34px;
.author {
- color: #5c5d5e;
+ color: $gl-text-color-dark;
}
.identifier {
- color: #5c5d5e;
+ color: $gl-text-color-dark;
}
.issue_created_ago,
diff --git a/app/assets/stylesheets/pages/diff.scss b/app/assets/stylesheets/pages/diff.scss
index 99fdea15218..737f6e0f4be 100644
--- a/app/assets/stylesheets/pages/diff.scss
+++ b/app/assets/stylesheets/pages/diff.scss
@@ -14,7 +14,7 @@
background: $background-color;
border-bottom: 1px solid $border-color;
padding: 10px 16px;
- color: #555;
+ color: $gl-diff-text-color;
z-index: 10;
border-radius: 3px 3px 0 0;
@@ -24,7 +24,7 @@
display: block;
.file-mode {
- color: #777;
+ color: $file-mode-changed;
}
}
@@ -49,8 +49,8 @@
.diff-content {
overflow: auto;
overflow-y: hidden;
- background: #fff;
- color: #333;
+ background: $white-light;
+ color: $gl-title-color;
border-radius: 0 0 3px 3px;
.unfold {
@@ -59,7 +59,7 @@
.file-mode-changed {
padding: 10px;
- color: #777;
+ color: $file-mode-changed;
}
.suppressed-container {
@@ -172,7 +172,7 @@
}
.image {
- background: #ddd;
+ background: $diff-image-bg;
text-align: center;
padding: 30px;
@@ -182,13 +182,13 @@
.frame {
display: inline-block;
- background-color: #fff;
+ background-color: $white-light;
line-height: 0;
img {
- border: 1px solid #fff;
- background-image: linear-gradient(45deg, #e5e5e5 25%, transparent 25%, transparent 75%, #e5e5e5 75%, #e5e5e5 100%),
- linear-gradient(45deg, #e5e5e5 25%, transparent 25%, transparent 75%, #e5e5e5 75%, #e5e5e5 100%);
+ border: 1px solid $white-light;
+ background-image: linear-gradient(45deg, $diff-image-img-bg 25%, transparent 25%, transparent 75%, $diff-image-img-bg 75%, $diff-image-img-bg 100%),
+ linear-gradient(45deg, $diff-image-img-bg 25%, transparent 25%, transparent 75%, $diff-image-img-bg 75%, $diff-image-img-bg 100%);
background-size: 10px 10px;
background-position: 0 0, 5px 5px;
max-width: 100%;
@@ -206,7 +206,7 @@
.image-info {
font-size: 12px;
margin: 5px 0 0;
- color: grey;
+ color: $diff-image-info-color;
}
.view.swipe {
@@ -220,7 +220,7 @@
.swipe-wrap {
overflow: hidden;
- border-left: 1px solid #999;
+ border-left: 1px solid $diff-swipe-border;
position: absolute;
display: block;
top: 13px;
@@ -350,7 +350,7 @@
.view-modes {
padding: 10px;
text-align: center;
- background: #eee;
+ background: $gray-darker;
ul,
li {
@@ -361,8 +361,8 @@
}
li {
- color: grey;
- border-left: 1px solid #c1c1c1;
+ color: $diff-view-modes-color;
+ border-left: 1px solid $diff-view-modes-border;
padding: 0 12px 0 16px;
cursor: pointer;
@@ -380,7 +380,7 @@
}
cursor: default;
- color: #333;
+ color: $gl-title-color;
}
&.disabled {
diff --git a/app/assets/stylesheets/pages/editor.scss b/app/assets/stylesheets/pages/editor.scss
index 778126bcfb7..6cde9c592de 100644
--- a/app/assets/stylesheets/pages/editor.scss
+++ b/app/assets/stylesheets/pages/editor.scss
@@ -14,10 +14,10 @@
}
.cancel-btn {
- color: #b94a48;
+ color: $editor-cancel-color;
&:hover {
- color: #b94a48;
+ color: $editor-cancel-color;
}
}
diff --git a/app/assets/stylesheets/pages/errors.scss b/app/assets/stylesheets/pages/errors.scss
deleted file mode 100644
index 11309817d31..00000000000
--- a/app/assets/stylesheets/pages/errors.scss
+++ /dev/null
@@ -1,16 +0,0 @@
-.error-page {
- max-width: 400px;
- margin: 0 auto;
-
- h1,
- h2,
- h3 {
- text-align: center;
- }
-
- h1 {
- font-size: 56px;
- line-height: 100px;
- font-weight: 300;
- }
-}
diff --git a/app/assets/stylesheets/pages/events.scss b/app/assets/stylesheets/pages/events.scss
index 3004959ff7b..dc67d411c71 100644
--- a/app/assets/stylesheets/pages/events.scss
+++ b/app/assets/stylesheets/pages/events.scss
@@ -62,7 +62,7 @@
border: none;
background: $gray-light;
border-radius: 0;
- color: #777;
+ color: $events-pre-color;
margin: 0 20px;
overflow: hidden;
}
@@ -80,7 +80,7 @@
}
.event-note-icon {
- color: #777;
+ color: $events-pre-color;
float: left;
font-size: $gl-font-size;
line-height: 16px;
@@ -91,7 +91,7 @@
.event_icon {
position: relative;
float: right;
- border: 1px solid #eee;
+ border: 1px solid $gray-darker;
padding: 5px;
border-radius: 5px;
background: $gray-light;
@@ -170,7 +170,7 @@
.event-body {
margin: 0;
- border-left: 2px solid #ddd;
+ border-left: 2px solid $events-body-border;
padding-left: 10px;
}
@@ -186,4 +186,3 @@
display: none;
}
}
-
diff --git a/app/assets/stylesheets/pages/graph.scss b/app/assets/stylesheets/pages/graph.scss
index f7f9a9bb770..84da9180f93 100644
--- a/app/assets/stylesheets/pages/graph.scss
+++ b/app/assets/stylesheets/pages/graph.scss
@@ -2,15 +2,15 @@
border: 1px solid $border-color;
.controls {
- color: #888;
+ color: $project-network-controls-color;
font-size: 14px;
padding: 5px;
border-bottom: 1px solid $border-color;
- background: #eee;
+ background: $gray-darker;
}
.network-graph {
- background: #fff;
+ background: $white-light;
height: 500px;
overflow-y: scroll;
overflow-x: hidden;
@@ -20,15 +20,14 @@
.graphs {
.graph-author-email {
float: right;
- color: #777;
+ color: $graph-author-email-color;
}
.graph-additions {
- color: #4a2;
+ color: $gl-text-green;
}
.graph-deletions {
- color: #d12f19;
+ color: $gl-text-red;
}
}
-
diff --git a/app/assets/stylesheets/pages/help.scss b/app/assets/stylesheets/pages/help.scss
index a48b4c65db8..e2e644dc23b 100644
--- a/app/assets/stylesheets/pages/help.scss
+++ b/app/assets/stylesheets/pages/help.scss
@@ -9,7 +9,7 @@
li {
line-height: 24px;
- color: #888;
+ color: $document-index-color;
a {
margin-right: 3px;
@@ -20,7 +20,7 @@
.shortcut-mappings {
font-size: 12px;
- color: #555;
+ color: $help-shortcut-mapping-color;
tbody:first-child tr:first-child {
padding-top: 0;
@@ -29,7 +29,7 @@
th {
padding-top: 15px;
line-height: 1.5;
- color: #333;
+ color: $help-shortcut-header-color;
text-align: left;
}
@@ -42,7 +42,7 @@
.shortcut {
padding-right: 10px;
- color: #999;
+ color: $help-shortcut-color;
text-align: right;
white-space: nowrap;
}
diff --git a/app/assets/stylesheets/pages/issuable.scss b/app/assets/stylesheets/pages/issuable.scss
index 7aad99eee4e..90587b9425b 100644
--- a/app/assets/stylesheets/pages/issuable.scss
+++ b/app/assets/stylesheets/pages/issuable.scss
@@ -233,7 +233,7 @@
width: 100%;
text-align: center;
padding-bottom: 10px;
- color: #999;
+ color: $issuable-sidebar-color;
&:hover {
color: $gl-gray;
@@ -249,12 +249,12 @@
}
.avatar:hover {
- border-color: #999;
+ border-color: $issuable-avatar-hover-border;
}
.btn-clipboard {
border: none;
- color: #999;
+ color: $issuable-clipboard-color;
&:hover {
background: transparent;
diff --git a/app/assets/stylesheets/pages/issues.scss b/app/assets/stylesheets/pages/issues.scss
index eb171195309..3b47f99df2c 100644
--- a/app/assets/stylesheets/pages/issues.scss
+++ b/app/assets/stylesheets/pages/issues.scss
@@ -82,18 +82,18 @@ ul.related-merge-requests > li {
.merge-request,
.issue {
&.today {
- background: #f3fff2;
- border-color: #e1e8d5;
+ background: $issues-today-bg;
+ border-color: $issues-today-border;
}
&.closed {
background: $gray-light;
- border-color: #e5e5e5;
+ border-color: $issues-border;
}
&.merged {
background: $gray-light;
- border-color: #e5e5e5;
+ border-color: $issues-border;
}
}
diff --git a/app/assets/stylesheets/pages/labels.scss b/app/assets/stylesheets/pages/labels.scss
index e39ce19f846..b1ccd644450 100644
--- a/app/assets/stylesheets/pages/labels.scss
+++ b/app/assets/stylesheets/pages/labels.scss
@@ -198,7 +198,7 @@
}
.label-remove {
- border-left: 1px solid rgba(0, 0, 0, .1);
+ border-left: 1px solid $label-remove-border;
z-index: 3;
}
diff --git a/app/assets/stylesheets/pages/lint.scss b/app/assets/stylesheets/pages/lint.scss
index 8290519dc25..a7c80dce424 100644
--- a/app/assets/stylesheets/pages/lint.scss
+++ b/app/assets/stylesheets/pages/lint.scss
@@ -1,11 +1,11 @@
.ci-body {
.incorrect-syntax {
- font-size: 19px;
- color: red;
+ font-size: 18px;
+ color: $lint-incorrect-color;
}
.correct-syntax {
- font-size: 19px;
- color: #47a447;
+ font-size: 18px;
+ color: $lint-correct-color;
}
}
diff --git a/app/assets/stylesheets/pages/login.scss b/app/assets/stylesheets/pages/login.scss
index 54c89d75e94..dd27a06fcd2 100644
--- a/app/assets/stylesheets/pages/login.scss
+++ b/app/assets/stylesheets/pages/login.scss
@@ -18,7 +18,7 @@
p {
font-size: 18px;
- color: #888;
+ color: $login-brand-holder-color;
}
h1:first-child {
@@ -174,7 +174,7 @@
.form-control {
&:active,
&:focus {
- background-color: #fff;
+ background-color: $white-light;
}
}
@@ -195,7 +195,7 @@
h2 {
margin-top: 0;
font-size: 14px;
- color: #a00;
+ color: $login-devise-error-color;
}
}
}
@@ -254,4 +254,3 @@
}
}
}
-
diff --git a/app/assets/stylesheets/pages/merge_conflicts.scss b/app/assets/stylesheets/pages/merge_conflicts.scss
index 19ab198c2e7..7a90713dd3f 100644
--- a/app/assets/stylesheets/pages/merge_conflicts.scss
+++ b/app/assets/stylesheets/pages/merge_conflicts.scss
@@ -1,3 +1,5 @@
+// Disabled to use the color map for creating color schemes
+// scss-lint:disable ColorVariable
$colors: (
white_header_head_neutral : #e1fad7,
white_line_head_neutral : #effdec,
@@ -98,6 +100,7 @@ $colors: (
solarized_dark_header_not_chosen : rgba(#839496, .25),
solarized_dark_line_not_chosen : rgba(#839496, .15)
);
+// scss-lint:enable ColorVariable
@mixin color-scheme($color) {
@@ -228,14 +231,15 @@ $colors: (
position: absolute;
right: 10px;
padding: 0;
- color: #fff;
+ outline: none;
+ color: $white-light;
width: 75px; // static width to make 2 buttons have same width
height: 19px;
}
}
.btn-success .fa-spinner {
- color: #fff;
+ color: $white-light;
}
.editor-wrap {
diff --git a/app/assets/stylesheets/pages/merge_requests.scss b/app/assets/stylesheets/pages/merge_requests.scss
index da1187af41c..6234779ac19 100644
--- a/app/assets/stylesheets/pages/merge_requests.scss
+++ b/app/assets/stylesheets/pages/merge_requests.scss
@@ -86,7 +86,7 @@
}
.normal {
- color: #5c5d5e;
+ color: $gl-text-color-dark;
}
.js-deployment-link {
@@ -116,7 +116,7 @@
@media (max-width: $screen-xs-max) {
h4 {
- font-size: 15px;
+ font-size: 14px;
}
p {
@@ -129,6 +129,11 @@
margin-bottom: 4px;
}
+ .btn-grouped {
+ float: none;
+ margin-right: 0;
+ }
+
.accept-action {
width: 100%;
text-align: center;
@@ -143,7 +148,7 @@
}
.mr-widget-footer {
- border-top: 1px solid #eee;
+ border-top: 1px solid $gray-darker;
}
.ci-coverage {
diff --git a/app/assets/stylesheets/pages/note_form.scss b/app/assets/stylesheets/pages/note_form.scss
index 65775c45e5b..c35d71f9e7b 100644
--- a/app/assets/stylesheets/pages/note_form.scss
+++ b/app/assets/stylesheets/pages/note_form.scss
@@ -129,10 +129,10 @@
.note-edit-form {
display: none;
- font-size: 15px;
+ font-size: 14px;
.md-area {
- background-color: #fff;
+ background-color: $white-light;
}
}
diff --git a/app/assets/stylesheets/pages/notes.scss b/app/assets/stylesheets/pages/notes.scss
index 56a798a7b6d..16b099c09eb 100644
--- a/app/assets/stylesheets/pages/notes.scss
+++ b/app/assets/stylesheets/pages/notes.scss
@@ -3,9 +3,9 @@
*/
@-webkit-keyframes targe3-note {
- from { background: #fffff0; }
- 50% { background: #ffffd3; }
- to { background: #fffff0; }
+ from { background: $note-targe3-outside; }
+ 50% { background: $note-targe3-inside; }
+ to { background: $note-targe3-outside; }
}
ul.notes {
@@ -305,7 +305,7 @@ ul.notes {
&.notes_line2 {
text-align: center;
padding: 10px 0;
- border-left: 1px solid #ddd !important;
+ border-left: 1px solid $note-line2-border !important;
}
&.notes_content {
@@ -471,7 +471,7 @@ ul.notes {
.add-diff-note {
margin-top: -4px;
border-radius: 40px;
- background: #fff;
+ background: $white-light;
padding: 4px;
font-size: 16px;
color: $gl-link-color;
@@ -484,7 +484,7 @@ ul.notes {
&:hover {
background: $gl-info;
- color: #fff;
+ color: $white-light;
@include show-add-diff-note;
}
}
diff --git a/app/assets/stylesheets/pages/pipelines.scss b/app/assets/stylesheets/pages/pipelines.scss
index 0027d2caf22..08062b85504 100644
--- a/app/assets/stylesheets/pages/pipelines.scss
+++ b/app/assets/stylesheets/pages/pipelines.scss
@@ -280,6 +280,12 @@
}
}
+.admin-builds-table {
+ .ci-table td:last-child {
+ min-width: 120px;
+ }
+}
+
// Pipeline visualization
.toggle-pipeline-btn {
diff --git a/app/assets/stylesheets/pages/projects.scss b/app/assets/stylesheets/pages/projects.scss
index 1cf7587dbb4..72b6685d940 100644
--- a/app/assets/stylesheets/pages/projects.scss
+++ b/app/assets/stylesheets/pages/projects.scss
@@ -8,7 +8,7 @@
.no-ssh-key-message,
.project-limit-message {
- background-color: #f28d35;
+ background-color: $project-limit-message-bg;
margin-bottom: 0;
}
@@ -76,7 +76,7 @@
&.static-namespace {
height: 35px;
border-radius: 3px;
- border: 1px solid #e5e5e5;
+ border: 1px solid $border-color;
}
&+ .select2 a {
@@ -225,7 +225,7 @@
left: 0;
margin-top: -6px;
border-width: 7px 5px 7px 0;
- border-right-color: #dce0e5;
+ border-right-color: $count-arrow-border;
pointer-events: none;
}
@@ -240,7 +240,7 @@
left: 1px;
margin-top: -9px;
border-width: 10px 7px 10px 0;
- border-right-color: #fff;
+ border-right-color: $white-light;
pointer-events: none;
}
}
@@ -248,7 +248,7 @@
.count {
@include btn-gray;
display: inline-block;
- background: white;
+ background: $white-light;
border-radius: 2px;
border-width: 1px;
border-style: solid;
@@ -270,7 +270,7 @@
}
&:hover {
- background: #fff;
+ background: $white-light;
}
}
}
@@ -302,7 +302,7 @@
.option-descr {
margin-left: 29px;
- color: #54565b;
+ color: $project-option-descr-color;
}
}
}
@@ -310,7 +310,7 @@
.save-project-loader {
margin-top: 50px;
margin-bottom: 50px;
- color: #555;
+ color: $save-project-loader-color;
}
.transfer-project .select2-container {
@@ -373,7 +373,7 @@ a.deploy-project-label {
> li + li::before {
padding: 0 3px;
- color: #999;
+ color: $project-breadcrumb-color;
}
a {
@@ -521,7 +521,7 @@ a.deploy-project-label {
.nav > li > a {
padding: 0;
background-color: transparent;
- font-size: 15px;
+ font-size: 14px;
line-height: 29px;
color: $notes-light-color;
@@ -549,20 +549,20 @@ a.deploy-project-label {
}
pre.light-well {
- border-color: #f1f1f1;
+ border-color: $well-light-border;
}
.git-empty {
margin: 0 7px 7px;
h5 {
- color: #5c5d5e;
+ color: $gl-text-color-dark;
}
.light-well {
border-radius: 2px;
- color: #5b6169;
+ color: $well-light-text-color;
font-size: 13px;
line-height: 1.6em;
}
@@ -716,7 +716,7 @@ pre.light-well {
.form-control {
@extend .monospace;
- background: #fff;
+ background: $white-light;
font-size: 14px;
margin-left: -1px;
cursor: auto;
@@ -726,17 +726,17 @@ pre.light-well {
.cannot-be-merged,
.cannot-be-merged:hover {
- color: #e62958;
+ color: $error-exclamation-point;
margin-top: 2px;
}
.private-forks-notice .private-fork-icon {
i:nth-child(1) {
- color: #2aa056;
+ color: $project-private-forks-notice-odd;
}
i:nth-child(2) {
- color: #fff;
+ color: $white-light;
}
}
diff --git a/app/assets/stylesheets/pages/runners.scss b/app/assets/stylesheets/pages/runners.scss
index 7b3878c91df..9b6ff237557 100644
--- a/app/assets/stylesheets/pages/runners.scss
+++ b/app/assets/stylesheets/pages/runners.scss
@@ -1,27 +1,27 @@
.runner-state {
padding: 6px 12px;
margin-right: 10px;
- color: #fff;
+ color: $white-light;
&.runner-state-shared {
- background: #32b186;
+ background: $runner-state-shared-bg;
}
&.runner-state-specific {
- background: #3498db;
+ background: $runner-state-specific-bg;
}
}
.runner-status-online {
- color: green;
+ color: $runner-status-online-color;
}
.runner-status-offline {
- color: gray;
+ color: $runner-status-offline-color;
}
.runner-status-paused {
- color: red;
+ color: $runner-status-paused-color;
}
.runner {
diff --git a/app/assets/stylesheets/pages/stat_graph.scss b/app/assets/stylesheets/pages/stat_graph.scss
index 779db77da60..dfa4d033fb8 100644
--- a/app/assets/stylesheets/pages/stat_graph.scss
+++ b/app/assets/stylesheets/pages/stat_graph.scss
@@ -1,16 +1,16 @@
.tint-box {
- background: #f3f3f3;
+ background: $stat-graph-common-bg;
position: relative;
margin-bottom: 10px;
}
.area {
- fill: #1db34f;
+ fill: $stat-graph-area-fill;
fill-opacity: 0.5;
}
.axis {
- fill: #aaa;
+ fill: $stat-graph-axis-fill;
font-size: 10px;
}
@@ -44,19 +44,19 @@
.person .spark {
display: block;
- background: #f3f3f3;
+ background: $stat-graph-common-bg;
width: 100%;
}
.person .area-contributor {
- fill: #f17f49;
+ fill: $stat-graph-orange-fill;
}
}
.selection rect {
- fill: #333;
+ fill: $stat-graph-selection-fill;
fill-opacity: 0.1;
- stroke: #333;
+ stroke: $stat-graph-selection-stroke;
stroke-width: 1px;
stroke-opacity: 0.4;
shape-rendering: crispedges;
diff --git a/app/assets/stylesheets/pages/status.scss b/app/assets/stylesheets/pages/status.scss
index 4c258bae1f4..5084b466722 100644
--- a/app/assets/stylesheets/pages/status.scss
+++ b/app/assets/stylesheets/pages/status.scss
@@ -2,7 +2,7 @@
.ci-status {
padding: 2px 7px;
margin-right: 10px;
- border: 1px solid #eee;
+ border: 1px solid $gray-darker;
white-space: nowrap;
border-radius: 4px;
diff --git a/app/assets/stylesheets/pages/tags.scss b/app/assets/stylesheets/pages/tags.scss
deleted file mode 100644
index 24ebd3e7cfa..00000000000
--- a/app/assets/stylesheets/pages/tags.scss
+++ /dev/null
@@ -1,7 +0,0 @@
-.tag-buttons {
- line-height: 40px;
-
- .btn:not(.dropdown-toggle) {
- margin-left: 10px;
- }
-}
diff --git a/app/assets/stylesheets/pages/todos.scss b/app/assets/stylesheets/pages/todos.scss
index b3aef2fdd32..508b30f3947 100644
--- a/app/assets/stylesheets/pages/todos.scss
+++ b/app/assets/stylesheets/pages/todos.scss
@@ -11,7 +11,7 @@
background: $todo-alert-blue;
margin-left: -17px;
font-size: 11px;
- color: white;
+ color: $white-light;
padding: 3px;
padding-top: 1px;
padding-bottom: 1px;
@@ -81,7 +81,7 @@
word-wrap: break-word;
.md {
- color: #7f8fa4;
+ color: $gl-grayish-blue;
font-size: $gl-font-size;
.label {
@@ -90,7 +90,7 @@
}
p {
- color: #5c5d5e;
+ color: $gl-text-color-dark;
}
}
@@ -102,7 +102,7 @@
border: none;
background: $gray-light;
border-radius: 0;
- color: #777;
+ color: $todo-body-pre-color;
margin: 0 20px;
overflow: hidden;
}
@@ -146,7 +146,7 @@
.todo-body {
margin: 0;
- border-left: 2px solid #ddd;
+ border-left: 2px solid $todo-body-border;
padding-left: 10px;
}
}
diff --git a/app/assets/stylesheets/pages/ui_dev_kit.scss b/app/assets/stylesheets/pages/ui_dev_kit.scss
index e73cecc92be..8c87bc3cafd 100644
--- a/app/assets/stylesheets/pages/ui_dev_kit.scss
+++ b/app/assets/stylesheets/pages/ui_dev_kit.scss
@@ -7,11 +7,11 @@
.example {
&::before {
content: "Example";
- color: #bbb;
+ color: $ui-dev-kit-example-color;
}
padding: 15px;
- border: 1px dashed #ddd;
+ border: 1px dashed $ui-dev-kit-example-border;
margin-bottom: 15px;
}
}
diff --git a/app/assets/stylesheets/pages/votes.scss b/app/assets/stylesheets/pages/votes.scss
deleted file mode 100644
index dc9a7d71e8b..00000000000
--- a/app/assets/stylesheets/pages/votes.scss
+++ /dev/null
@@ -1,4 +0,0 @@
-.votes-inline {
- display: inline-block;
- margin: 0 8px;
-}
diff --git a/app/assets/stylesheets/pages/xterm.scss b/app/assets/stylesheets/pages/xterm.scss
index 3fa7fa3d7e3..9f9d630978a 100644
--- a/app/assets/stylesheets/pages/xterm.scss
+++ b/app/assets/stylesheets/pages/xterm.scss
@@ -20,6 +20,266 @@
$l-cyan: #8abeb7;
$l-white: $ci-text-color;
+ /*
+ * xterm colors
+ */
+ $xterm-fg-0: $black;
+ $xterm-fg-1: #800000;
+ $xterm-fg-2: #008000;
+ $xterm-fg-3: #808000;
+ $xterm-fg-4: #000080;
+ $xterm-fg-5: #800080;
+ $xterm-fg-6: #008080;
+ $xterm-fg-7: #c0c0c0;
+ $xterm-fg-8: #808080;
+ $xterm-fg-9: #f00;
+ $xterm-fg-10: #0f0;
+ $xterm-fg-11: #ff0;
+ $xterm-fg-12: #00f;
+ $xterm-fg-13: #f0f;
+ $xterm-fg-14: #0ff;
+ $xterm-fg-15: $white-light;
+ $xterm-fg-16: $black;
+ $xterm-fg-17: #00005f;
+ $xterm-fg-18: #000087;
+ $xterm-fg-19: #0000af;
+ $xterm-fg-20: #0000d7;
+ $xterm-fg-21: #00f;
+ $xterm-fg-22: #005f00;
+ $xterm-fg-23: #005f5f;
+ $xterm-fg-24: #005f87;
+ $xterm-fg-25: #005faf;
+ $xterm-fg-26: #005fd7;
+ $xterm-fg-27: #005fff;
+ $xterm-fg-28: #008700;
+ $xterm-fg-29: #00875f;
+ $xterm-fg-30: #008787;
+ $xterm-fg-31: #0087af;
+ $xterm-fg-32: #0087d7;
+ $xterm-fg-33: #0087ff;
+ $xterm-fg-34: #00af00;
+ $xterm-fg-35: #00af5f;
+ $xterm-fg-36: #00af87;
+ $xterm-fg-37: #00afaf;
+ $xterm-fg-38: #00afd7;
+ $xterm-fg-39: #00afff;
+ $xterm-fg-40: #00d700;
+ $xterm-fg-41: #00d75f;
+ $xterm-fg-42: #00d787;
+ $xterm-fg-43: #00d7af;
+ $xterm-fg-44: #00d7d7;
+ $xterm-fg-45: #00d7ff;
+ $xterm-fg-46: #0f0;
+ $xterm-fg-47: #00ff5f;
+ $xterm-fg-48: #00ff87;
+ $xterm-fg-49: #00ffaf;
+ $xterm-fg-50: #00ffd7;
+ $xterm-fg-51: #0ff;
+ $xterm-fg-52: #5f0000;
+ $xterm-fg-53: #5f005f;
+ $xterm-fg-54: #5f0087;
+ $xterm-fg-55: #5f00af;
+ $xterm-fg-56: #5f00d7;
+ $xterm-fg-57: #5f00ff;
+ $xterm-fg-58: #5f5f00;
+ $xterm-fg-59: #5f5f5f;
+ $xterm-fg-60: #5f5f87;
+ $xterm-fg-61: #5f5faf;
+ $xterm-fg-62: #5f5fd7;
+ $xterm-fg-63: #5f5fff;
+ $xterm-fg-64: #5f8700;
+ $xterm-fg-65: #5f875f;
+ $xterm-fg-66: #5f8787;
+ $xterm-fg-67: #5f87af;
+ $xterm-fg-68: #5f87d7;
+ $xterm-fg-69: #5f87ff;
+ $xterm-fg-70: #5faf00;
+ $xterm-fg-71: #5faf5f;
+ $xterm-fg-72: #5faf87;
+ $xterm-fg-73: #5fafaf;
+ $xterm-fg-74: #5fafd7;
+ $xterm-fg-75: #5fafff;
+ $xterm-fg-76: #5fd700;
+ $xterm-fg-77: #5fd75f;
+ $xterm-fg-78: #5fd787;
+ $xterm-fg-79: #5fd7af;
+ $xterm-fg-80: #5fd7d7;
+ $xterm-fg-81: #5fd7ff;
+ $xterm-fg-82: #5fff00;
+ $xterm-fg-83: #5fff5f;
+ $xterm-fg-84: #5fff87;
+ $xterm-fg-85: #5fffaf;
+ $xterm-fg-86: #5fffd7;
+ $xterm-fg-87: #5fffff;
+ $xterm-fg-88: #870000;
+ $xterm-fg-89: #87005f;
+ $xterm-fg-90: #870087;
+ $xterm-fg-91: #8700af;
+ $xterm-fg-92: #8700d7;
+ $xterm-fg-93: #8700ff;
+ $xterm-fg-94: #875f00;
+ $xterm-fg-95: #875f5f;
+ $xterm-fg-96: #875f87;
+ $xterm-fg-97: #875faf;
+ $xterm-fg-98: #875fd7;
+ $xterm-fg-99: #875fff;
+ $xterm-fg-100: #878700;
+ $xterm-fg-101: #87875f;
+ $xterm-fg-102: #878787;
+ $xterm-fg-103: #8787af;
+ $xterm-fg-104: #8787d7;
+ $xterm-fg-105: #8787ff;
+ $xterm-fg-106: #87af00;
+ $xterm-fg-107: #87af5f;
+ $xterm-fg-108: #87af87;
+ $xterm-fg-109: #87afaf;
+ $xterm-fg-110: #87afd7;
+ $xterm-fg-111: #87afff;
+ $xterm-fg-112: #87d700;
+ $xterm-fg-113: #87d75f;
+ $xterm-fg-114: #87d787;
+ $xterm-fg-115: #87d7af;
+ $xterm-fg-116: #87d7d7;
+ $xterm-fg-117: #87d7ff;
+ $xterm-fg-118: #87ff00;
+ $xterm-fg-119: #87ff5f;
+ $xterm-fg-120: #87ff87;
+ $xterm-fg-121: #87ffaf;
+ $xterm-fg-122: #87ffd7;
+ $xterm-fg-123: #87ffff;
+ $xterm-fg-124: #af0000;
+ $xterm-fg-125: #af005f;
+ $xterm-fg-126: #af0087;
+ $xterm-fg-127: #af00af;
+ $xterm-fg-128: #af00d7;
+ $xterm-fg-129: #af00ff;
+ $xterm-fg-130: #af5f00;
+ $xterm-fg-131: #af5f5f;
+ $xterm-fg-132: #af5f87;
+ $xterm-fg-133: #af5faf;
+ $xterm-fg-134: #af5fd7;
+ $xterm-fg-135: #af5fff;
+ $xterm-fg-136: #af8700;
+ $xterm-fg-137: #af875f;
+ $xterm-fg-138: #af8787;
+ $xterm-fg-139: #af87af;
+ $xterm-fg-140: #af87d7;
+ $xterm-fg-141: #af87ff;
+ $xterm-fg-142: #afaf00;
+ $xterm-fg-143: #afaf5f;
+ $xterm-fg-144: #afaf87;
+ $xterm-fg-145: #afafaf;
+ $xterm-fg-146: #afafd7;
+ $xterm-fg-147: #afafff;
+ $xterm-fg-148: #afd700;
+ $xterm-fg-149: #afd75f;
+ $xterm-fg-150: #afd787;
+ $xterm-fg-151: #afd7af;
+ $xterm-fg-152: #afd7d7;
+ $xterm-fg-153: #afd7ff;
+ $xterm-fg-154: #afff00;
+ $xterm-fg-155: #afff5f;
+ $xterm-fg-156: #afff87;
+ $xterm-fg-157: #afffaf;
+ $xterm-fg-158: #afffd7;
+ $xterm-fg-159: #afffff;
+ $xterm-fg-160: #d70000;
+ $xterm-fg-161: #d7005f;
+ $xterm-fg-162: #d70087;
+ $xterm-fg-163: #d700af;
+ $xterm-fg-164: #d700d7;
+ $xterm-fg-165: #d700ff;
+ $xterm-fg-166: #d75f00;
+ $xterm-fg-167: #d75f5f;
+ $xterm-fg-168: #d75f87;
+ $xterm-fg-169: #d75faf;
+ $xterm-fg-170: #d75fd7;
+ $xterm-fg-171: #d75fff;
+ $xterm-fg-172: #d78700;
+ $xterm-fg-173: #d7875f;
+ $xterm-fg-174: #d78787;
+ $xterm-fg-175: #d787af;
+ $xterm-fg-176: #d787d7;
+ $xterm-fg-177: #d787ff;
+ $xterm-fg-178: #d7af00;
+ $xterm-fg-179: #d7af5f;
+ $xterm-fg-180: #d7af87;
+ $xterm-fg-181: #d7afaf;
+ $xterm-fg-182: #d7afd7;
+ $xterm-fg-183: #d7afff;
+ $xterm-fg-184: #d7d700;
+ $xterm-fg-185: #d7d75f;
+ $xterm-fg-186: #d7d787;
+ $xterm-fg-187: #d7d7af;
+ $xterm-fg-188: #d7d7d7;
+ $xterm-fg-189: #d7d7ff;
+ $xterm-fg-190: #d7ff00;
+ $xterm-fg-191: #d7ff5f;
+ $xterm-fg-192: #d7ff87;
+ $xterm-fg-193: #d7ffaf;
+ $xterm-fg-194: #d7ffd7;
+ $xterm-fg-195: #d7ffff;
+ $xterm-fg-196: #f00;
+ $xterm-fg-197: #ff005f;
+ $xterm-fg-198: #ff0087;
+ $xterm-fg-199: #ff00af;
+ $xterm-fg-200: #ff00d7;
+ $xterm-fg-201: #f0f;
+ $xterm-fg-202: #ff5f00;
+ $xterm-fg-203: #ff5f5f;
+ $xterm-fg-204: #ff5f87;
+ $xterm-fg-205: #ff5faf;
+ $xterm-fg-206: #ff5fd7;
+ $xterm-fg-207: #ff5fff;
+ $xterm-fg-208: #ff8700;
+ $xterm-fg-209: #ff875f;
+ $xterm-fg-210: #ff8787;
+ $xterm-fg-211: #ff87af;
+ $xterm-fg-212: #ff87d7;
+ $xterm-fg-213: #ff87ff;
+ $xterm-fg-214: #ffaf00;
+ $xterm-fg-215: #ffaf5f;
+ $xterm-fg-216: #ffaf87;
+ $xterm-fg-217: #ffafaf;
+ $xterm-fg-218: #ffafd7;
+ $xterm-fg-219: #ffafff;
+ $xterm-fg-220: #ffd700;
+ $xterm-fg-221: #ffd75f;
+ $xterm-fg-222: #ffd787;
+ $xterm-fg-223: #ffd7af;
+ $xterm-fg-224: #ffd7d7;
+ $xterm-fg-225: #ffd7ff;
+ $xterm-fg-226: #ff0;
+ $xterm-fg-227: #ffff5f;
+ $xterm-fg-228: #ffff87;
+ $xterm-fg-229: #ffffaf;
+ $xterm-fg-230: #ffffd7;
+ $xterm-fg-231: $white-light;
+ $xterm-fg-232: #080808;
+ $xterm-fg-233: #121212;
+ $xterm-fg-234: #1c1c1c;
+ $xterm-fg-235: #262626;
+ $xterm-fg-236: #303030;
+ $xterm-fg-237: #3a3a3a;
+ $xterm-fg-238: #444;
+ $xterm-fg-239: #4e4e4e;
+ $xterm-fg-240: #585858;
+ $xterm-fg-241: #626262;
+ $xterm-fg-242: #6c6c6c;
+ $xterm-fg-243: #767676;
+ $xterm-fg-244: #808080;
+ $xterm-fg-245: #8a8a8a;
+ $xterm-fg-246: #949494;
+ $xterm-fg-247: #9e9e9e;
+ $xterm-fg-248: #a8a8a8;
+ $xterm-fg-249: #b2b2b2;
+ $xterm-fg-250: #bcbcbc;
+ $xterm-fg-251: #c6c6c6;
+ $xterm-fg-252: #d0d0d0;
+ $xterm-fg-253: #dadada;
+ $xterm-fg-254: #e4e4e4;
+ $xterm-fg-255: #eee;
+
.term-bold {
font-weight: bold;
}
@@ -169,1026 +429,1026 @@
}
.xterm-fg-0 {
- color: #000;
+ color: $xterm-fg-0;
}
.xterm-fg-1 {
- color: #800000;
+ color: $xterm-fg-1;
}
.xterm-fg-2 {
- color: #008000;
+ color: $xterm-fg-2;
}
.xterm-fg-3 {
- color: #808000;
+ color: $xterm-fg-3;
}
.xterm-fg-4 {
- color: #000080;
+ color: $xterm-fg-4;
}
.xterm-fg-5 {
- color: #800080;
+ color: $xterm-fg-5;
}
.xterm-fg-6 {
- color: #008080;
+ color: $xterm-fg-6;
}
.xterm-fg-7 {
- color: #c0c0c0;
+ color: $xterm-fg-7;
}
.xterm-fg-8 {
- color: #808080;
+ color: $xterm-fg-8;
}
.xterm-fg-9 {
- color: #f00;
+ color: $xterm-fg-9;
}
.xterm-fg-10 {
- color: #0f0;
+ color: $xterm-fg-10;
}
.xterm-fg-11 {
- color: #ff0;
+ color: $xterm-fg-11;
}
.xterm-fg-12 {
- color: #00f;
+ color: $xterm-fg-12;
}
.xterm-fg-13 {
- color: #f0f;
+ color: $xterm-fg-13;
}
.xterm-fg-14 {
- color: #0ff;
+ color: $xterm-fg-14;
}
.xterm-fg-15 {
- color: #fff;
+ color: $white-light;
}
.xterm-fg-16 {
- color: #000;
+ color: $black;
}
.xterm-fg-17 {
- color: #00005f;
+ color: $xterm-fg-17;
}
.xterm-fg-18 {
- color: #000087;
+ color: $xterm-fg-18;
}
.xterm-fg-19 {
- color: #0000af;
+ color: $xterm-fg-19;
}
.xterm-fg-20 {
- color: #0000d7;
+ color: $xterm-fg-20;
}
.xterm-fg-21 {
- color: #00f;
+ color: $xterm-fg-21;
}
.xterm-fg-22 {
- color: #005f00;
+ color: $xterm-fg-22;
}
.xterm-fg-23 {
- color: #005f5f;
+ color: $xterm-fg-23;
}
.xterm-fg-24 {
- color: #005f87;
+ color: $xterm-fg-24;
}
.xterm-fg-25 {
- color: #005faf;
+ color: $xterm-fg-25;
}
.xterm-fg-26 {
- color: #005fd7;
+ color: $xterm-fg-26;
}
.xterm-fg-27 {
- color: #005fff;
+ color: $xterm-fg-27;
}
.xterm-fg-28 {
- color: #008700;
+ color: $xterm-fg-28;
}
.xterm-fg-29 {
- color: #00875f;
+ color: $xterm-fg-29;
}
.xterm-fg-30 {
- color: #008787;
+ color: $xterm-fg-30;
}
.xterm-fg-31 {
- color: #0087af;
+ color: $xterm-fg-31;
}
.xterm-fg-32 {
- color: #0087d7;
+ color: $xterm-fg-32;
}
.xterm-fg-33 {
- color: #0087ff;
+ color: $xterm-fg-33;
}
.xterm-fg-34 {
- color: #00af00;
+ color: $xterm-fg-34;
}
.xterm-fg-35 {
- color: #00af5f;
+ color: $xterm-fg-35;
}
.xterm-fg-36 {
- color: #00af87;
+ color: $xterm-fg-36;
}
.xterm-fg-37 {
- color: #00afaf;
+ color: $xterm-fg-37;
}
.xterm-fg-38 {
- color: #00afd7;
+ color: $xterm-fg-38;
}
.xterm-fg-39 {
- color: #00afff;
+ color: $xterm-fg-39;
}
.xterm-fg-40 {
- color: #00d700;
+ color: $xterm-fg-40;
}
.xterm-fg-41 {
- color: #00d75f;
+ color: $xterm-fg-41;
}
.xterm-fg-42 {
- color: #00d787;
+ color: $xterm-fg-42;
}
.xterm-fg-43 {
- color: #00d7af;
+ color: $xterm-fg-43;
}
.xterm-fg-44 {
- color: #00d7d7;
+ color: $xterm-fg-44;
}
.xterm-fg-45 {
- color: #00d7ff;
+ color: $xterm-fg-45;
}
.xterm-fg-46 {
- color: #0f0;
+ color: $xterm-fg-46;
}
.xterm-fg-47 {
- color: #00ff5f;
+ color: $xterm-fg-47;
}
.xterm-fg-48 {
- color: #00ff87;
+ color: $xterm-fg-48;
}
.xterm-fg-49 {
- color: #00ffaf;
+ color: $xterm-fg-49;
}
.xterm-fg-50 {
- color: #00ffd7;
+ color: $xterm-fg-50;
}
.xterm-fg-51 {
- color: #0ff;
+ color: $xterm-fg-51;
}
.xterm-fg-52 {
- color: #5f0000;
+ color: $xterm-fg-52;
}
.xterm-fg-53 {
- color: #5f005f;
+ color: $xterm-fg-53;
}
.xterm-fg-54 {
- color: #5f0087;
+ color: $xterm-fg-54;
}
.xterm-fg-55 {
- color: #5f00af;
+ color: $xterm-fg-55;
}
.xterm-fg-56 {
- color: #5f00d7;
+ color: $xterm-fg-56;
}
.xterm-fg-57 {
- color: #5f00ff;
+ color: $xterm-fg-57;
}
.xterm-fg-58 {
- color: #5f5f00;
+ color: $xterm-fg-58;
}
.xterm-fg-59 {
- color: #5f5f5f;
+ color: $xterm-fg-59;
}
.xterm-fg-60 {
- color: #5f5f87;
+ color: $xterm-fg-60;
}
.xterm-fg-61 {
- color: #5f5faf;
+ color: $xterm-fg-61;
}
.xterm-fg-62 {
- color: #5f5fd7;
+ color: $xterm-fg-62;
}
.xterm-fg-63 {
- color: #5f5fff;
+ color: $xterm-fg-63;
}
.xterm-fg-64 {
- color: #5f8700;
+ color: $xterm-fg-64;
}
.xterm-fg-65 {
- color: #5f875f;
+ color: $xterm-fg-65;
}
.xterm-fg-66 {
- color: #5f8787;
+ color: $xterm-fg-66;
}
.xterm-fg-67 {
- color: #5f87af;
+ color: $xterm-fg-67;
}
.xterm-fg-68 {
- color: #5f87d7;
+ color: $xterm-fg-68;
}
.xterm-fg-69 {
- color: #5f87ff;
+ color: $xterm-fg-69;
}
.xterm-fg-70 {
- color: #5faf00;
+ color: $xterm-fg-70;
}
.xterm-fg-71 {
- color: #5faf5f;
+ color: $xterm-fg-71;
}
.xterm-fg-72 {
- color: #5faf87;
+ color: $xterm-fg-72;
}
.xterm-fg-73 {
- color: #5fafaf;
+ color: $xterm-fg-73;
}
.xterm-fg-74 {
- color: #5fafd7;
+ color: $xterm-fg-74;
}
.xterm-fg-75 {
- color: #5fafff;
+ color: $xterm-fg-75;
}
.xterm-fg-76 {
- color: #5fd700;
+ color: $xterm-fg-76;
}
.xterm-fg-77 {
- color: #5fd75f;
+ color: $xterm-fg-77;
}
.xterm-fg-78 {
- color: #5fd787;
+ color: $xterm-fg-78;
}
.xterm-fg-79 {
- color: #5fd7af;
+ color: $xterm-fg-79;
}
.xterm-fg-80 {
- color: #5fd7d7;
+ color: $xterm-fg-80;
}
.xterm-fg-81 {
- color: #5fd7ff;
+ color: $xterm-fg-81;
}
.xterm-fg-82 {
- color: #5fff00;
+ color: $xterm-fg-82;
}
.xterm-fg-83 {
- color: #5fff5f;
+ color: $xterm-fg-83;
}
.xterm-fg-84 {
- color: #5fff87;
+ color: $xterm-fg-84;
}
.xterm-fg-85 {
- color: #5fffaf;
+ color: $xterm-fg-85;
}
.xterm-fg-86 {
- color: #5fffd7;
+ color: $xterm-fg-86;
}
.xterm-fg-87 {
- color: #5fffff;
+ color: $xterm-fg-87;
}
.xterm-fg-88 {
- color: #870000;
+ color: $xterm-fg-88;
}
.xterm-fg-89 {
- color: #87005f;
+ color: $xterm-fg-89;
}
.xterm-fg-90 {
- color: #870087;
+ color: $xterm-fg-90;
}
.xterm-fg-91 {
- color: #8700af;
+ color: $xterm-fg-91;
}
.xterm-fg-92 {
- color: #8700d7;
+ color: $xterm-fg-92;
}
.xterm-fg-93 {
- color: #8700ff;
+ color: $xterm-fg-93;
}
.xterm-fg-94 {
- color: #875f00;
+ color: $xterm-fg-94;
}
.xterm-fg-95 {
- color: #875f5f;
+ color: $xterm-fg-95;
}
.xterm-fg-96 {
- color: #875f87;
+ color: $xterm-fg-96;
}
.xterm-fg-97 {
- color: #875faf;
+ color: $xterm-fg-97;
}
.xterm-fg-98 {
- color: #875fd7;
+ color: $xterm-fg-98;
}
.xterm-fg-99 {
- color: #875fff;
+ color: $xterm-fg-99;
}
.xterm-fg-100 {
- color: #878700;
+ color: $xterm-fg-100;
}
.xterm-fg-101 {
- color: #87875f;
+ color: $xterm-fg-101;
}
.xterm-fg-102 {
- color: #878787;
+ color: $xterm-fg-102;
}
.xterm-fg-103 {
- color: #8787af;
+ color: $xterm-fg-103;
}
.xterm-fg-104 {
- color: #8787d7;
+ color: $xterm-fg-104;
}
.xterm-fg-105 {
- color: #8787ff;
+ color: $xterm-fg-105;
}
.xterm-fg-106 {
- color: #87af00;
+ color: $xterm-fg-106;
}
.xterm-fg-107 {
- color: #87af5f;
+ color: $xterm-fg-107;
}
.xterm-fg-108 {
- color: #87af87;
+ color: $xterm-fg-108;
}
.xterm-fg-109 {
- color: #87afaf;
+ color: $xterm-fg-109;
}
.xterm-fg-110 {
- color: #87afd7;
+ color: $xterm-fg-110;
}
.xterm-fg-111 {
- color: #87afff;
+ color: $xterm-fg-111;
}
.xterm-fg-112 {
- color: #87d700;
+ color: $xterm-fg-112;
}
.xterm-fg-113 {
- color: #87d75f;
+ color: $xterm-fg-113;
}
.xterm-fg-114 {
- color: #87d787;
+ color: $xterm-fg-114;
}
.xterm-fg-115 {
- color: #87d7af;
+ color: $xterm-fg-115;
}
.xterm-fg-116 {
- color: #87d7d7;
+ color: $xterm-fg-116;
}
.xterm-fg-117 {
- color: #87d7ff;
+ color: $xterm-fg-117;
}
.xterm-fg-118 {
- color: #87ff00;
+ color: $xterm-fg-118;
}
.xterm-fg-119 {
- color: #87ff5f;
+ color: $xterm-fg-119;
}
.xterm-fg-120 {
- color: #87ff87;
+ color: $xterm-fg-120;
}
.xterm-fg-121 {
- color: #87ffaf;
+ color: $xterm-fg-121;
}
.xterm-fg-122 {
- color: #87ffd7;
+ color: $xterm-fg-122;
}
.xterm-fg-123 {
- color: #87ffff;
+ color: $xterm-fg-123;
}
.xterm-fg-124 {
- color: #af0000;
+ color: $xterm-fg-124;
}
.xterm-fg-125 {
- color: #af005f;
+ color: $xterm-fg-125;
}
.xterm-fg-126 {
- color: #af0087;
+ color: $xterm-fg-126;
}
.xterm-fg-127 {
- color: #af00af;
+ color: $xterm-fg-127;
}
.xterm-fg-128 {
- color: #af00d7;
+ color: $xterm-fg-128;
}
.xterm-fg-129 {
- color: #af00ff;
+ color: $xterm-fg-129;
}
.xterm-fg-130 {
- color: #af5f00;
+ color: $xterm-fg-130;
}
.xterm-fg-131 {
- color: #af5f5f;
+ color: $xterm-fg-131;
}
.xterm-fg-132 {
- color: #af5f87;
+ color: $xterm-fg-132;
}
.xterm-fg-133 {
- color: #af5faf;
+ color: $xterm-fg-133;
}
.xterm-fg-134 {
- color: #af5fd7;
+ color: $xterm-fg-134;
}
.xterm-fg-135 {
- color: #af5fff;
+ color: $xterm-fg-135;
}
.xterm-fg-136 {
- color: #af8700;
+ color: $xterm-fg-136;
}
.xterm-fg-137 {
- color: #af875f;
+ color: $xterm-fg-137;
}
.xterm-fg-138 {
- color: #af8787;
+ color: $xterm-fg-138;
}
.xterm-fg-139 {
- color: #af87af;
+ color: $xterm-fg-139;
}
.xterm-fg-140 {
- color: #af87d7;
+ color: $xterm-fg-140;
}
.xterm-fg-141 {
- color: #af87ff;
+ color: $xterm-fg-141;
}
.xterm-fg-142 {
- color: #afaf00;
+ color: $xterm-fg-142;
}
.xterm-fg-143 {
- color: #afaf5f;
+ color: $xterm-fg-143;
}
.xterm-fg-144 {
- color: #afaf87;
+ color: $xterm-fg-144;
}
.xterm-fg-145 {
- color: #afafaf;
+ color: $xterm-fg-145;
}
.xterm-fg-146 {
- color: #afafd7;
+ color: $xterm-fg-146;
}
.xterm-fg-147 {
- color: #afafff;
+ color: $xterm-fg-147;
}
.xterm-fg-148 {
- color: #afd700;
+ color: $xterm-fg-148;
}
.xterm-fg-149 {
- color: #afd75f;
+ color: $xterm-fg-149;
}
.xterm-fg-150 {
- color: #afd787;
+ color: $xterm-fg-150;
}
.xterm-fg-151 {
- color: #afd7af;
+ color: $xterm-fg-151;
}
.xterm-fg-152 {
- color: #afd7d7;
+ color: $xterm-fg-152;
}
.xterm-fg-153 {
- color: #afd7ff;
+ color: $xterm-fg-153;
}
.xterm-fg-154 {
- color: #afff00;
+ color: $xterm-fg-154;
}
.xterm-fg-155 {
- color: #afff5f;
+ color: $xterm-fg-155;
}
.xterm-fg-156 {
- color: #afff87;
+ color: $xterm-fg-156;
}
.xterm-fg-157 {
- color: #afffaf;
+ color: $xterm-fg-157;
}
.xterm-fg-158 {
- color: #afffd7;
+ color: $xterm-fg-158;
}
.xterm-fg-159 {
- color: #afffff;
+ color: $xterm-fg-159;
}
.xterm-fg-160 {
- color: #d70000;
+ color: $xterm-fg-160;
}
.xterm-fg-161 {
- color: #d7005f;
+ color: $xterm-fg-161;
}
.xterm-fg-162 {
- color: #d70087;
+ color: $xterm-fg-162;
}
.xterm-fg-163 {
- color: #d700af;
+ color: $xterm-fg-163;
}
.xterm-fg-164 {
- color: #d700d7;
+ color: $xterm-fg-164;
}
.xterm-fg-165 {
- color: #d700ff;
+ color: $xterm-fg-165;
}
.xterm-fg-166 {
- color: #d75f00;
+ color: $xterm-fg-166;
}
.xterm-fg-167 {
- color: #d75f5f;
+ color: $xterm-fg-167;
}
.xterm-fg-168 {
- color: #d75f87;
+ color: $xterm-fg-168;
}
.xterm-fg-169 {
- color: #d75faf;
+ color: $xterm-fg-169;
}
.xterm-fg-170 {
- color: #d75fd7;
+ color: $xterm-fg-170;
}
.xterm-fg-171 {
- color: #d75fff;
+ color: $xterm-fg-171;
}
.xterm-fg-172 {
- color: #d78700;
+ color: $xterm-fg-172;
}
.xterm-fg-173 {
- color: #d7875f;
+ color: $xterm-fg-173;
}
.xterm-fg-174 {
- color: #d78787;
+ color: $xterm-fg-174;
}
.xterm-fg-175 {
- color: #d787af;
+ color: $xterm-fg-175;
}
.xterm-fg-176 {
- color: #d787d7;
+ color: $xterm-fg-176;
}
.xterm-fg-177 {
- color: #d787ff;
+ color: $xterm-fg-177;
}
.xterm-fg-178 {
- color: #d7af00;
+ color: $xterm-fg-178;
}
.xterm-fg-179 {
- color: #d7af5f;
+ color: $xterm-fg-179;
}
.xterm-fg-180 {
- color: #d7af87;
+ color: $xterm-fg-180;
}
.xterm-fg-181 {
- color: #d7afaf;
+ color: $xterm-fg-181;
}
.xterm-fg-182 {
- color: #d7afd7;
+ color: $xterm-fg-182;
}
.xterm-fg-183 {
- color: #d7afff;
+ color: $xterm-fg-183;
}
.xterm-fg-184 {
- color: #d7d700;
+ color: $xterm-fg-184;
}
.xterm-fg-185 {
- color: #d7d75f;
+ color: $xterm-fg-185;
}
.xterm-fg-186 {
- color: #d7d787;
+ color: $xterm-fg-186;
}
.xterm-fg-187 {
- color: #d7d7af;
+ color: $xterm-fg-187;
}
.xterm-fg-188 {
- color: #d7d7d7;
+ color: $xterm-fg-188;
}
.xterm-fg-189 {
- color: #d7d7ff;
+ color: $xterm-fg-189;
}
.xterm-fg-190 {
- color: #d7ff00;
+ color: $xterm-fg-190;
}
.xterm-fg-191 {
- color: #d7ff5f;
+ color: $xterm-fg-191;
}
.xterm-fg-192 {
- color: #d7ff87;
+ color: $xterm-fg-192;
}
.xterm-fg-193 {
- color: #d7ffaf;
+ color: $xterm-fg-193;
}
.xterm-fg-194 {
- color: #d7ffd7;
+ color: $xterm-fg-194;
}
.xterm-fg-195 {
- color: #d7ffff;
+ color: $xterm-fg-195;
}
.xterm-fg-196 {
- color: #f00;
+ color: $xterm-fg-196;
}
.xterm-fg-197 {
- color: #ff005f;
+ color: $xterm-fg-197;
}
.xterm-fg-198 {
- color: #ff0087;
+ color: $xterm-fg-198;
}
.xterm-fg-199 {
- color: #ff00af;
+ color: $xterm-fg-199;
}
.xterm-fg-200 {
- color: #ff00d7;
+ color: $xterm-fg-200;
}
.xterm-fg-201 {
- color: #f0f;
+ color: $xterm-fg-201;
}
.xterm-fg-202 {
- color: #ff5f00;
+ color: $xterm-fg-202;
}
.xterm-fg-203 {
- color: #ff5f5f;
+ color: $xterm-fg-203;
}
.xterm-fg-204 {
- color: #ff5f87;
+ color: $xterm-fg-204;
}
.xterm-fg-205 {
- color: #ff5faf;
+ color: $xterm-fg-205;
}
.xterm-fg-206 {
- color: #ff5fd7;
+ color: $xterm-fg-206;
}
.xterm-fg-207 {
- color: #ff5fff;
+ color: $xterm-fg-207;
}
.xterm-fg-208 {
- color: #ff8700;
+ color: $xterm-fg-208;
}
.xterm-fg-209 {
- color: #ff875f;
+ color: $xterm-fg-209;
}
.xterm-fg-210 {
- color: #ff8787;
+ color: $xterm-fg-210;
}
.xterm-fg-211 {
- color: #ff87af;
+ color: $xterm-fg-211;
}
.xterm-fg-212 {
- color: #ff87d7;
+ color: $xterm-fg-212;
}
.xterm-fg-213 {
- color: #ff87ff;
+ color: $xterm-fg-213;
}
.xterm-fg-214 {
- color: #ffaf00;
+ color: $xterm-fg-214;
}
.xterm-fg-215 {
- color: #ffaf5f;
+ color: $xterm-fg-215;
}
.xterm-fg-216 {
- color: #ffaf87;
+ color: $xterm-fg-216;
}
.xterm-fg-217 {
- color: #ffafaf;
+ color: $xterm-fg-217;
}
.xterm-fg-218 {
- color: #ffafd7;
+ color: $xterm-fg-218;
}
.xterm-fg-219 {
- color: #ffafff;
+ color: $xterm-fg-219;
}
.xterm-fg-220 {
- color: #ffd700;
+ color: $xterm-fg-220;
}
.xterm-fg-221 {
- color: #ffd75f;
+ color: $xterm-fg-221;
}
.xterm-fg-222 {
- color: #ffd787;
+ color: $xterm-fg-222;
}
.xterm-fg-223 {
- color: #ffd7af;
+ color: $xterm-fg-223;
}
.xterm-fg-224 {
- color: #ffd7d7;
+ color: $xterm-fg-224;
}
.xterm-fg-225 {
- color: #ffd7ff;
+ color: $xterm-fg-225;
}
.xterm-fg-226 {
- color: #ff0;
+ color: $xterm-fg-226;
}
.xterm-fg-227 {
- color: #ffff5f;
+ color: $xterm-fg-227;
}
.xterm-fg-228 {
- color: #ffff87;
+ color: $xterm-fg-228;
}
.xterm-fg-229 {
- color: #ffffaf;
+ color: $xterm-fg-229;
}
.xterm-fg-230 {
- color: #ffffd7;
+ color: $xterm-fg-230;
}
.xterm-fg-231 {
- color: #fff;
+ color: $xterm-fg-231;
}
.xterm-fg-232 {
- color: #080808;
+ color: $xterm-fg-232;
}
.xterm-fg-233 {
- color: #121212;
+ color: $xterm-fg-233;
}
.xterm-fg-234 {
- color: #1c1c1c;
+ color: $xterm-fg-234;
}
.xterm-fg-235 {
- color: #262626;
+ color: $xterm-fg-235;
}
.xterm-fg-236 {
- color: #303030;
+ color: $xterm-fg-236;
}
.xterm-fg-237 {
- color: #3a3a3a;
+ color: $xterm-fg-237;
}
.xterm-fg-238 {
- color: #444;
+ color: $xterm-fg-238;
}
.xterm-fg-239 {
- color: #4e4e4e;
+ color: $xterm-fg-239;
}
.xterm-fg-240 {
- color: #585858;
+ color: $xterm-fg-240;
}
.xterm-fg-241 {
- color: #626262;
+ color: $xterm-fg-241;
}
.xterm-fg-242 {
- color: #6c6c6c;
+ color: $xterm-fg-242;
}
.xterm-fg-243 {
- color: #767676;
+ color: $xterm-fg-243;
}
.xterm-fg-244 {
- color: #808080;
+ color: $xterm-fg-244;
}
.xterm-fg-245 {
- color: #8a8a8a;
+ color: $xterm-fg-245;
}
.xterm-fg-246 {
- color: #949494;
+ color: $xterm-fg-246;
}
.xterm-fg-247 {
- color: #9e9e9e;
+ color: $xterm-fg-247;
}
.xterm-fg-248 {
- color: #a8a8a8;
+ color: $xterm-fg-248;
}
.xterm-fg-249 {
- color: #b2b2b2;
+ color: $xterm-fg-249;
}
.xterm-fg-250 {
- color: #bcbcbc;
+ color: $xterm-fg-250;
}
.xterm-fg-251 {
- color: #c6c6c6;
+ color: $xterm-fg-251;
}
.xterm-fg-252 {
- color: #d0d0d0;
+ color: $xterm-fg-252;
}
.xterm-fg-253 {
- color: #dadada;
+ color: $xterm-fg-253;
}
.xterm-fg-254 {
- color: #e4e4e4;
+ color: $xterm-fg-254;
}
.xterm-fg-255 {
- color: #eee;
+ color: $xterm-fg-255;
}
}
diff --git a/app/controllers/concerns/merge_requests_action.rb b/app/controllers/concerns/merge_requests_action.rb
index 6546a07b41c..fdb05bb3228 100644
--- a/app/controllers/concerns/merge_requests_action.rb
+++ b/app/controllers/concerns/merge_requests_action.rb
@@ -6,7 +6,12 @@ module MergeRequestsAction
@label = merge_requests_finder.labels.first
@merge_requests = merge_requests_collection
- .non_archived
.page(params[:page])
end
+
+ private
+
+ def filter_params
+ super.merge(non_archived: true)
+ end
end
diff --git a/app/controllers/projects/discussions_controller.rb b/app/controllers/projects/discussions_controller.rb
index d174e1145a7..148e39630e3 100644
--- a/app/controllers/projects/discussions_controller.rb
+++ b/app/controllers/projects/discussions_controller.rb
@@ -5,9 +5,7 @@ class Projects::DiscussionsController < Projects::ApplicationController
before_action :authorize_resolve_discussion!
def resolve
- discussion.resolve!(current_user)
-
- MergeRequests::ResolvedDiscussionNotificationService.new(project, current_user).execute(merge_request)
+ Discussions::ResolveService.new(project, current_user, merge_request: merge_request).execute(discussion)
render json: {
resolved_by: discussion.resolved_by.try(:name),
diff --git a/app/controllers/projects/issues_controller.rb b/app/controllers/projects/issues_controller.rb
index 4aea7bb62c4..4f66e01e0f7 100644
--- a/app/controllers/projects/issues_controller.rb
+++ b/app/controllers/projects/issues_controller.rb
@@ -46,8 +46,9 @@ class Projects::IssuesController < Projects::ApplicationController
params[:issue] ||= ActionController::Parameters.new(
assignee_id: ""
)
+ build_params = issue_params.merge(merge_request_for_resolving_discussions: merge_request_for_resolving_discussions)
+ @issue = @noteable = Issues::BuildService.new(project, current_user, build_params).execute
- @issue = @noteable = @project.issues.new(issue_params)
respond_with(@issue)
end
@@ -75,7 +76,9 @@ class Projects::IssuesController < Projects::ApplicationController
end
def create
- @issue = Issues::CreateService.new(project, current_user, issue_params.merge(request: request)).execute
+ extra_params = { request: request,
+ merge_request_for_resolving_discussions: merge_request_for_resolving_discussions }
+ @issue = Issues::CreateService.new(project, current_user, issue_params.merge(extra_params)).execute
respond_to do |format|
format.html do
@@ -169,6 +172,14 @@ class Projects::IssuesController < Projects::ApplicationController
alias_method :awardable, :issue
alias_method :spammable, :issue
+ def merge_request_for_resolving_discussions
+ return unless merge_request_iid = params[:merge_request_for_resolving_discussions]
+
+ @merge_request_for_resolving_discussions ||= MergeRequestsFinder.new(current_user, project_id: project.id).
+ execute.
+ find_by(iid: merge_request_iid)
+ end
+
def authorize_read_issue!
return render_404 unless can?(current_user, :read_issue, @issue)
end
diff --git a/app/controllers/projects/merge_requests_controller.rb b/app/controllers/projects/merge_requests_controller.rb
index d2cef52842c..f0cb5a9d4b4 100644
--- a/app/controllers/projects/merge_requests_controller.rb
+++ b/app/controllers/projects/merge_requests_controller.rb
@@ -302,9 +302,13 @@ class Projects::MergeRequestsController < Projects::ApplicationController
end
def cancel_merge_when_build_succeeds
- return access_denied! unless @merge_request.can_cancel_merge_when_build_succeeds?(current_user)
+ unless @merge_request.can_cancel_merge_when_build_succeeds?(current_user)
+ return access_denied!
+ end
- MergeRequests::MergeWhenBuildSucceedsService.new(@project, current_user).cancel(@merge_request)
+ MergeRequests::MergeWhenPipelineSucceedsService
+ .new(@project, current_user)
+ .cancel(@merge_request)
end
def merge
@@ -331,8 +335,10 @@ class Projects::MergeRequestsController < Projects::ApplicationController
end
if @merge_request.head_pipeline.active?
- MergeRequests::MergeWhenBuildSucceedsService.new(@project, current_user, merge_params)
- .execute(@merge_request)
+ MergeRequests::MergeWhenPipelineSucceedsService
+ .new(@project, current_user, merge_params)
+ .execute(@merge_request)
+
@status = :merge_when_build_succeeds
elsif @merge_request.head_pipeline.success?
# This can be triggered when a user clicks the auto merge button while
diff --git a/app/finders/issuable_finder.rb b/app/finders/issuable_finder.rb
index 001c83ccb4b..c9bee01b9ad 100644
--- a/app/finders/issuable_finder.rb
+++ b/app/finders/issuable_finder.rb
@@ -7,7 +7,7 @@
# current_user - which user use
# params:
# scope: 'created-by-me' or 'assigned-to-me' or 'all'
-# state: 'open' or 'closed' or 'all'
+# state: 'opened' or 'closed' or 'all'
# group_id: integer
# project_id: integer
# milestone_title: string
@@ -15,6 +15,7 @@
# search: string
# label_name: string
# sort: string
+# non_archived: boolean
#
class IssuableFinder
NONE = '0'
@@ -38,6 +39,7 @@ class IssuableFinder
items = by_author(items)
items = by_label(items)
items = by_due_date(items)
+ items = by_non_archived(items)
sort(items)
end
@@ -207,10 +209,13 @@ class IssuableFinder
end
def by_state(items)
- params[:state] ||= 'all'
-
- if items.respond_to?(params[:state])
- items.public_send(params[:state])
+ case params[:state].to_s
+ when 'closed'
+ items.closed
+ when 'merged'
+ items.respond_to?(:merged) ? items.merged : items.closed
+ when 'opened'
+ items.opened
else
items
end
@@ -353,6 +358,10 @@ class IssuableFinder
end
end
+ def by_non_archived(items)
+ params[:non_archived].present? ? items.non_archived : items
+ end
+
def current_user_related?
params[:scope] == 'created-by-me' || params[:scope] == 'authored' || params[:scope] == 'assigned-to-me'
end
diff --git a/app/finders/merge_requests_finder.rb b/app/finders/merge_requests_finder.rb
index 3b254e7d9d5..8b82255445e 100644
--- a/app/finders/merge_requests_finder.rb
+++ b/app/finders/merge_requests_finder.rb
@@ -14,6 +14,7 @@
# search: string
# label_name: string
# sort: string
+# non_archived: boolean
#
class MergeRequestsFinder < IssuableFinder
def klass
diff --git a/app/helpers/ci_status_helper.rb b/app/helpers/ci_status_helper.rb
index abcf84b4d15..8e19752a8a1 100644
--- a/app/helpers/ci_status_helper.rb
+++ b/app/helpers/ci_status_helper.rb
@@ -5,8 +5,9 @@ module CiStatusHelper
end
def ci_status_with_icon(status, target = nil)
- content = ci_icon_for_status(status) + ci_label_for_status(status)
+ content = ci_icon_for_status(status) + ci_text_for_status(status)
klass = "ci-status ci-#{status}"
+
if target
link_to content, target, class: klass
else
@@ -14,7 +15,19 @@ module CiStatusHelper
end
end
+ def ci_text_for_status(status)
+ if detailed_status?(status)
+ status.text
+ else
+ status
+ end
+ end
+
def ci_label_for_status(status)
+ if detailed_status?(status)
+ return status.label
+ end
+
case status
when 'success'
'passed'
@@ -31,6 +44,10 @@ module CiStatusHelper
end
def ci_icon_for_status(status)
+ if detailed_status?(status)
+ return custom_icon(status.icon)
+ end
+
icon_name =
case status
when 'success'
@@ -94,4 +111,10 @@ module CiStatusHelper
class: klass, title: title, data: data
end
end
+
+ def detailed_status?(status)
+ status.respond_to?(:text) &&
+ status.respond_to?(:label) &&
+ status.respond_to?(:icon)
+ end
end
diff --git a/app/helpers/gitlab_markdown_helper.rb b/app/helpers/gitlab_markdown_helper.rb
index 0772d848289..eb435cc1783 100644
--- a/app/helpers/gitlab_markdown_helper.rb
+++ b/app/helpers/gitlab_markdown_helper.rb
@@ -174,7 +174,7 @@ module GitlabMarkdownHelper
# Returns a String
def cross_project_reference(project, entity)
if entity.respond_to?(:to_reference)
- "#{project.to_reference}#{entity.to_reference}"
+ entity.to_reference(project)
else
''
end
diff --git a/app/helpers/labels_helper.rb b/app/helpers/labels_helper.rb
index 4f180456b16..e5b1e6e8bc7 100644
--- a/app/helpers/labels_helper.rb
+++ b/app/helpers/labels_helper.rb
@@ -82,12 +82,6 @@ module LabelsHelper
span.html_safe
end
- def render_colored_cross_project_label(label, source_project = nil, tooltip: true)
- label_suffix = source_project ? source_project.name_with_namespace : label.project.name_with_namespace
- label_suffix = " <i>in #{escape_once(label_suffix)}</i>"
- render_colored_label(label, label_suffix, tooltip: tooltip)
- end
-
def suggested_colors
[
'#0033CC',
@@ -166,6 +160,5 @@ module LabelsHelper
end
# Required for Banzai::Filter::LabelReferenceFilter
- module_function :render_colored_label, :render_colored_cross_project_label,
- :text_color_for_bg, :escape_once
+ module_function :render_colored_label, :text_color_for_bg, :escape_once
end
diff --git a/app/helpers/projects_helper.rb b/app/helpers/projects_helper.rb
index 898ce6a3af7..9cda3b78761 100644
--- a/app/helpers/projects_helper.rb
+++ b/app/helpers/projects_helper.rb
@@ -390,21 +390,7 @@ module ProjectsHelper
"success"
end
end
-
- def new_readme_path
- ref = @repository.root_ref if @repository
- ref ||= 'master'
-
- namespace_project_new_blob_path(@project.namespace, @project, tree_join(ref), file_name: 'README.md')
- end
-
- def new_license_path
- ref = @repository.root_ref if @repository
- ref ||= 'master'
-
- namespace_project_new_blob_path(@project.namespace, @project, tree_join(ref), file_name: 'LICENSE')
- end
-
+
def readme_cache_key
sha = @project.commit.try(:sha) || 'nil'
[@project.path_with_namespace, sha, "readme"].join('-')
diff --git a/app/models/ci/pipeline.rb b/app/models/ci/pipeline.rb
index fabbf97d4db..caf6908505e 100644
--- a/app/models/ci/pipeline.rb
+++ b/app/models/ci/pipeline.rb
@@ -320,6 +320,10 @@ module Ci
.select { |merge_request| merge_request.head_pipeline.try(:id) == self.id }
end
+ def detailed_status
+ Gitlab::Ci::Status::Pipeline::Factory.new(self).fabricate!
+ end
+
private
def pipeline_data
diff --git a/app/models/commit.rb b/app/models/commit.rb
index 176c524cf7b..248140f421b 100644
--- a/app/models/commit.rb
+++ b/app/models/commit.rb
@@ -92,19 +92,11 @@ class Commit
end
def to_reference(from_project = nil)
- if cross_project_reference?(from_project)
- project.to_reference + self.class.reference_prefix + self.id
- else
- self.id
- end
+ commit_reference(from_project, id)
end
def reference_link_text(from_project = nil)
- if cross_project_reference?(from_project)
- project.to_reference + self.class.reference_prefix + self.short_id
- else
- self.short_id
- end
+ commit_reference(from_project, short_id)
end
def diff_line_count
@@ -329,6 +321,16 @@ class Commit
private
+ def commit_reference(from_project, referable_commit_id)
+ reference = project.to_reference(from_project)
+
+ if reference.present?
+ "#{reference}#{self.class.reference_prefix}#{referable_commit_id}"
+ else
+ referable_commit_id
+ end
+ end
+
def find_author_by_any_email
User.find_by_any_email(author_email.downcase)
end
diff --git a/app/models/commit_range.rb b/app/models/commit_range.rb
index ac2477fd973..d9af7f6c139 100644
--- a/app/models/commit_range.rb
+++ b/app/models/commit_range.rb
@@ -90,21 +90,24 @@ class CommitRange
alias_method :id, :to_s
def to_reference(from_project = nil)
- if cross_project_reference?(from_project)
- project.to_reference + self.class.reference_prefix + self.id
+ project_reference = project.to_reference(from_project)
+
+ if project_reference.present?
+ project_reference + self.class.reference_prefix + self.id
else
self.id
end
end
def reference_link_text(from_project = nil)
- reference = ref_from + notation + ref_to
+ project_reference = project.to_reference(from_project)
+ reference = ref_from + notation + ref_to
- if cross_project_reference?(from_project)
- reference = project.to_reference + self.class.reference_prefix + reference
+ if project_reference.present?
+ project_reference + self.class.reference_prefix + reference
+ else
+ reference
end
-
- reference
end
# Return a Hash of parameters for passing to a URL helper
diff --git a/app/models/concerns/referable.rb b/app/models/concerns/referable.rb
index dee940a3f88..8ba009fe04f 100644
--- a/app/models/concerns/referable.rb
+++ b/app/models/concerns/referable.rb
@@ -72,17 +72,4 @@ module Referable
}x
end
end
-
- private
-
- # Check if a reference is being done cross-project
- #
- # from_project - Refering Project object
- def cross_project_reference?(from_project)
- if self.is_a?(Project)
- self != from_project
- else
- from_project && self.project && self.project != from_project
- end
- end
end
diff --git a/app/models/discussion.rb b/app/models/discussion.rb
index 75a85563235..bbe813db823 100644
--- a/app/models/discussion.rb
+++ b/app/models/discussion.rb
@@ -88,6 +88,10 @@ class Discussion
@first_note ||= @notes.first
end
+ def first_note_to_resolve
+ @first_note_to_resolve ||= notes.detect(&:to_be_resolved?)
+ end
+
def last_note
@last_note ||= @notes.last
end
diff --git a/app/models/issue.rb b/app/models/issue.rb
index fbf07040301..7fe92051037 100644
--- a/app/models/issue.rb
+++ b/app/models/issue.rb
@@ -153,11 +153,7 @@ class Issue < ActiveRecord::Base
def to_reference(from_project = nil)
reference = "#{self.class.reference_prefix}#{iid}"
- if cross_project_reference?(from_project)
- reference = project.to_reference + reference
- end
-
- reference
+ "#{project.to_reference(from_project)}#{reference}"
end
def referenced_merge_requests(current_user = nil)
diff --git a/app/models/label.rb b/app/models/label.rb
index d9287f2dc29..d38c37344c9 100644
--- a/app/models/label.rb
+++ b/app/models/label.rb
@@ -144,9 +144,10 @@ class Label < ActiveRecord::Base
#
# Examples:
#
- # Label.first.to_reference # => "~1"
- # Label.first.to_reference(format: :name) # => "~\"bug\""
- # Label.first.to_reference(project1, project2) # => "gitlab-org/gitlab-ce~1"
+ # Label.first.to_reference # => "~1"
+ # Label.first.to_reference(format: :name) # => "~\"bug\""
+ # Label.first.to_reference(project, same_namespace_project) # => "gitlab-ce~1"
+ # Label.first.to_reference(project, another_namespace_project) # => "gitlab-org/gitlab-ce~1"
#
# Returns a String
#
@@ -154,8 +155,8 @@ class Label < ActiveRecord::Base
format_reference = label_format_reference(format)
reference = "#{self.class.reference_prefix}#{format_reference}"
- if cross_project_reference?(source_project, target_project)
- source_project.to_reference + reference
+ if source_project
+ "#{source_project.to_reference(target_project)}#{reference}"
else
reference
end
@@ -169,10 +170,6 @@ class Label < ActiveRecord::Base
private
- def cross_project_reference?(source_project, target_project)
- source_project && target_project && source_project != target_project
- end
-
def issues_count(user, params = {})
params.merge!(subject_foreign_key => subject.id, label_name: title, scope: 'all')
IssuesFinder.new(user, params.with_indifferent_access).execute.count
diff --git a/app/models/member.rb b/app/models/member.rb
index df93aaee847..3b65587c66b 100644
--- a/app/models/member.rb
+++ b/app/models/member.rb
@@ -63,6 +63,7 @@ class Member < ActiveRecord::Base
after_create :send_request, if: :request?, unless: :importing?
after_create :create_notification_setting, unless: [:pending?, :importing?]
after_create :post_create_hook, unless: [:pending?, :importing?]
+ after_create :refresh_member_authorized_projects, if: :importing?
after_update :post_update_hook, unless: [:pending?, :importing?]
after_destroy :post_destroy_hook, unless: :pending?
diff --git a/app/models/merge_request.rb b/app/models/merge_request.rb
index bfb016df46d..33b578e12c1 100644
--- a/app/models/merge_request.rb
+++ b/app/models/merge_request.rb
@@ -176,11 +176,7 @@ class MergeRequest < ActiveRecord::Base
def to_reference(from_project = nil)
reference = "#{self.class.reference_prefix}#{iid}"
- if cross_project_reference?(from_project)
- reference = project.to_reference + reference
- end
-
- reference
+ "#{project.to_reference(from_project)}#{reference}"
end
def first_commit
@@ -480,6 +476,14 @@ class MergeRequest < ActiveRecord::Base
@diff_discussions ||= self.notes.diff_notes.discussions
end
+ def resolvable_discussions
+ @resolvable_discussions ||= diff_discussions.select(&:to_be_resolved?)
+ end
+
+ def discussions_can_be_resolved_by?(user)
+ resolvable_discussions.all? { |discussion| discussion.can_resolve?(user) }
+ end
+
def find_diff_discussion(discussion_id)
notes = self.notes.diff_notes.where(discussion_id: discussion_id).fresh.to_a
return if notes.empty?
diff --git a/app/models/milestone.rb b/app/models/milestone.rb
index c774e69080c..45ca97adad1 100644
--- a/app/models/milestone.rb
+++ b/app/models/milestone.rb
@@ -113,19 +113,16 @@ class Milestone < ActiveRecord::Base
#
# Examples:
#
- # Milestone.first.to_reference # => "%1"
- # Milestone.first.to_reference(format: :name) # => "%\"goal\""
- # Milestone.first.to_reference(project) # => "gitlab-org/gitlab-ce%1"
+ # Milestone.first.to_reference # => "%1"
+ # Milestone.first.to_reference(format: :name) # => "%\"goal\""
+ # Milestone.first.to_reference(cross_namespace_project) # => "gitlab-org/gitlab-ce%1"
+ # Milestone.first.to_reference(same_namespace_project) # => "gitlab-ce%1"
#
def to_reference(from_project = nil, format: :iid)
format_reference = milestone_format_reference(format)
reference = "#{self.class.reference_prefix}#{format_reference}"
- if cross_project_reference?(from_project)
- project.to_reference + reference
- else
- reference
- end
+ "#{project.to_reference(from_project)}#{reference}"
end
def reference_link_text(from_project = nil)
diff --git a/app/models/note.rb b/app/models/note.rb
index 5b50ca285c3..08bd08743ef 100644
--- a/app/models/note.rb
+++ b/app/models/note.rb
@@ -99,7 +99,7 @@ class Note < ActiveRecord::Base
end
def discussions
- Discussion.for_notes(all)
+ Discussion.for_notes(fresh)
end
def grouped_diff_discussions
diff --git a/app/models/project.rb b/app/models/project.rb
index e783e455a49..590885c0177 100644
--- a/app/models/project.rb
+++ b/app/models/project.rb
@@ -419,7 +419,11 @@ class Project < ActiveRecord::Base
def reference_pattern
name_pattern = Gitlab::Regex::NAMESPACE_REGEX_STR
- %r{(?<project>#{name_pattern}/#{name_pattern})}
+
+ %r{
+ ((?<namespace>#{name_pattern})\/)?
+ (?<project>#{name_pattern})
+ }x
end
def trending
@@ -650,8 +654,20 @@ class Project < ActiveRecord::Base
end
end
- def to_reference(_from_project = nil)
- path_with_namespace
+ def to_reference(from_project = nil)
+ if cross_namespace_reference?(from_project)
+ path_with_namespace
+ elsif cross_project_reference?(from_project)
+ path
+ end
+ end
+
+ def to_human_reference(from_project = nil)
+ if cross_namespace_reference?(from_project)
+ name_with_namespace
+ elsif cross_project_reference?(from_project)
+ name
+ end
end
def web_url
@@ -1327,10 +1343,21 @@ class Project < ActiveRecord::Base
private
+ # Check if a reference is being done cross-project
+ #
+ # from_project - Refering Project object
+ def cross_project_reference?(from_project)
+ from_project && self != from_project
+ end
+
def pushes_since_gc_redis_key
"projects/#{id}/pushes_since_gc"
end
+ def cross_namespace_reference?(from_project)
+ from_project && namespace != from_project.namespace
+ end
+
def default_branch_protected?
current_application_settings.default_branch_protection == Gitlab::Access::PROTECTION_FULL ||
current_application_settings.default_branch_protection == Gitlab::Access::PROTECTION_DEV_CAN_MERGE
diff --git a/app/models/repository.rb b/app/models/repository.rb
index e2e7d08abac..3c4b0212af7 100644
--- a/app/models/repository.rb
+++ b/app/models/repository.rb
@@ -85,11 +85,7 @@ class Repository
# This method return true if repository contains some content visible in project page.
#
def has_visible_content?
- return @has_visible_content unless @has_visible_content.nil?
-
- @has_visible_content = cache.fetch(:has_visible_content?) do
- branch_count > 0
- end
+ branch_count > 0
end
def commit(ref = 'HEAD')
@@ -374,12 +370,6 @@ class Repository
return unless empty?
expire_method_caches(%i(empty?))
- expire_has_visible_content_cache
- end
-
- def expire_has_visible_content_cache
- cache.expire(:has_visible_content?)
- @has_visible_content = nil
end
def lookup_cache
@@ -467,7 +457,6 @@ class Repository
# Runs code after a new branch has been created.
def after_create_branch
expire_branches_cache
- expire_has_visible_content_cache
repository_event(:push_branch)
end
@@ -481,7 +470,6 @@ class Repository
# Runs code after an existing branch has been removed.
def after_remove_branch
- expire_has_visible_content_cache
expire_branches_cache
end
diff --git a/app/models/snippet.rb b/app/models/snippet.rb
index 99493e561ab..98ccf5f331f 100644
--- a/app/models/snippet.rb
+++ b/app/models/snippet.rb
@@ -67,11 +67,11 @@ class Snippet < ActiveRecord::Base
def to_reference(from_project = nil)
reference = "#{self.class.reference_prefix}#{id}"
- if cross_project_reference?(from_project)
- reference = project.to_reference + reference
+ if project.present?
+ "#{project.to_reference(from_project)}#{reference}"
+ else
+ reference
end
-
- reference
end
def self.content_types
diff --git a/app/models/user.rb b/app/models/user.rb
index b54ce14f0bf..b9bb4a9e3f7 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -512,7 +512,7 @@ class User < ActiveRecord::Base
end
def require_ssh_key?
- keys.count == 0
+ keys.count == 0 && Gitlab::ProtocolAccess.allowed?('ssh')
end
def require_password?
diff --git a/app/policies/ci/build_policy.rb b/app/policies/ci/build_policy.rb
index 8b25332b73c..7b1752df0e1 100644
--- a/app/policies/ci/build_policy.rb
+++ b/app/policies/ci/build_policy.rb
@@ -1,6 +1,8 @@
module Ci
class BuildPolicy < CommitStatusPolicy
def rules
+ can! :read_build if @subject.project.public_builds?
+
super
# If we can't read build we should also not have that
diff --git a/app/policies/project_policy.rb b/app/policies/project_policy.rb
index 8ac4bd9df6d..d5aadfce76a 100644
--- a/app/policies/project_policy.rb
+++ b/app/policies/project_policy.rb
@@ -12,9 +12,6 @@ class ProjectPolicy < BasePolicy
guest_access!
public_access!
- # Allow to read builds for internal projects
- can! :read_build if project.public_builds?
-
if project.request_access_enabled &&
!(owner || user.admin? || project.team.member?(user) || project_group_member?(user))
can! :request_access
@@ -46,6 +43,11 @@ class ProjectPolicy < BasePolicy
can! :create_note
can! :upload_file
can! :read_cycle_analytics
+
+ if project.public_builds?
+ can! :read_pipeline
+ can! :read_build
+ end
end
def reporter_access!
diff --git a/app/services/discussions/base_service.rb b/app/services/discussions/base_service.rb
new file mode 100644
index 00000000000..e4dfe6e71bb
--- /dev/null
+++ b/app/services/discussions/base_service.rb
@@ -0,0 +1,4 @@
+module Discussions
+ class BaseService < ::BaseService
+ end
+end
diff --git a/app/services/discussions/resolve_service.rb b/app/services/discussions/resolve_service.rb
new file mode 100644
index 00000000000..0437195f588
--- /dev/null
+++ b/app/services/discussions/resolve_service.rb
@@ -0,0 +1,24 @@
+module Discussions
+ class ResolveService < Discussions::BaseService
+ def execute(one_or_more_discussions)
+ Array(one_or_more_discussions).each { |discussion| resolve_discussion(discussion) }
+ end
+
+ def resolve_discussion(discussion)
+ return unless discussion.can_resolve?(current_user)
+
+ discussion.resolve!(current_user)
+
+ MergeRequests::ResolvedDiscussionNotificationService.new(project, current_user).execute(merge_request)
+ SystemNoteService.discussion_continued_in_issue(discussion, project, current_user, follow_up_issue) if follow_up_issue
+ end
+
+ def merge_request
+ params[:merge_request]
+ end
+
+ def follow_up_issue
+ params[:follow_up_issue]
+ end
+ end
+end
diff --git a/app/services/issuable_base_service.rb b/app/services/issuable_base_service.rb
index ce68e433ab8..b5f63cc5a1a 100644
--- a/app/services/issuable_base_service.rb
+++ b/app/services/issuable_base_service.rb
@@ -120,9 +120,10 @@ class IssuableBaseService < BaseService
def merge_slash_commands_into_params!(issuable)
description, command_params =
SlashCommands::InterpretService.new(project, current_user).
- execute(params[:description], issuable)
+ execute(params[:description], issuable)
- params[:description] = description
+ # Avoid a description already set on an issuable to be overwritten by a nil
+ params[:description] = description if params.has_key?(:description)
params.merge!(command_params)
end
diff --git a/app/services/issues/base_service.rb b/app/services/issues/base_service.rb
index 9ea3ce084ba..742e834df97 100644
--- a/app/services/issues/base_service.rb
+++ b/app/services/issues/base_service.rb
@@ -1,5 +1,13 @@
module Issues
class BaseService < ::IssuableBaseService
+ attr_reader :merge_request_for_resolving_discussions
+
+ def initialize(*args)
+ super
+
+ @merge_request_for_resolving_discussions ||= params.delete(:merge_request_for_resolving_discussions)
+ end
+
def hook_data(issue, action)
issue_data = issue.to_hook_data(current_user)
issue_url = Gitlab::UrlBuilder.build(issue)
diff --git a/app/services/issues/build_service.rb b/app/services/issues/build_service.rb
new file mode 100644
index 00000000000..a63982f60c8
--- /dev/null
+++ b/app/services/issues/build_service.rb
@@ -0,0 +1,50 @@
+module Issues
+ class BuildService < Issues::BaseService
+ def execute
+ @issue = project.issues.new(issue_params)
+ end
+
+ def issue_params_with_info_from_merge_request
+ return {} unless merge_request_for_resolving_discussions
+
+ { title: title_from_merge_request, description: description_from_merge_request }
+ end
+
+ def title_from_merge_request
+ "Follow-up from \"#{merge_request_for_resolving_discussions.title}\""
+ end
+
+ def description_from_merge_request
+ if merge_request_for_resolving_discussions.resolvable_discussions.empty?
+ return "There are no unresolved discussions. "\
+ "Review the conversation in #{merge_request_for_resolving_discussions.to_reference}"
+ end
+
+ description = "The following discussions from #{merge_request_for_resolving_discussions.to_reference} should be addressed:"
+ [description, *items_for_discussions].join("\n\n")
+ end
+
+ def items_for_discussions
+ merge_request_for_resolving_discussions.resolvable_discussions.map { |discussion| item_for_discussion(discussion) }
+ end
+
+ def item_for_discussion(discussion)
+ first_note = discussion.first_note_to_resolve
+ other_note_count = discussion.notes.size - 1
+ creation_time = first_note.created_at.to_s(:medium)
+ note_url = Gitlab::UrlBuilder.build(first_note)
+
+ discussion_info = "- [ ] #{first_note.author.to_reference} commented in a discussion on [#{creation_time}](#{note_url}): "
+ discussion_info << " (+#{other_note_count} #{'comment'.pluralize(other_note_count)})" if other_note_count > 0
+
+ note_without_block_quotes = Banzai::Filter::BlockquoteFenceFilter.new(first_note.note).call
+ quote = ">>>\n#{note_without_block_quotes}\n>>>"
+
+ [discussion_info, quote].join("\n\n")
+ end
+
+ def issue_params
+ @issue_params ||= issue_params_with_info_from_merge_request.merge(params.slice(:title, :description))
+ end
+ end
+end
diff --git a/app/services/issues/create_service.rb b/app/services/issues/create_service.rb
index ea1690f3e38..d2eb46ac41b 100644
--- a/app/services/issues/create_service.rb
+++ b/app/services/issues/create_service.rb
@@ -4,7 +4,8 @@ module Issues
@request = params.delete(:request)
@api = params.delete(:api)
- @issue = project.issues.new
+ issue_attributes = params.merge(merge_request_for_resolving_discussions: merge_request_for_resolving_discussions)
+ @issue = BuildService.new(project, current_user, issue_attributes).execute
create(@issue)
end
@@ -18,6 +19,17 @@ module Issues
notification_service.new_issue(issuable, current_user)
todo_service.new_issue(issuable, current_user)
user_agent_detail_service.create
+
+ if merge_request_for_resolving_discussions.try(:discussions_can_be_resolved_by?, current_user)
+ resolve_discussions_in_merge_request(issuable)
+ end
+ end
+
+ def resolve_discussions_in_merge_request(issue)
+ Discussions::ResolveService.new(project, current_user,
+ merge_request: merge_request_for_resolving_discussions,
+ follow_up_issue: issue).
+ execute(merge_request_for_resolving_discussions.resolvable_discussions)
end
private
diff --git a/app/services/merge_requests/merge_when_build_succeeds_service.rb b/app/services/merge_requests/merge_when_pipeline_succeeds_service.rb
index dc159de0058..5616edf8b4a 100644
--- a/app/services/merge_requests/merge_when_build_succeeds_service.rb
+++ b/app/services/merge_requests/merge_when_pipeline_succeeds_service.rb
@@ -1,5 +1,5 @@
module MergeRequests
- class MergeWhenBuildSucceedsService < MergeRequests::BaseService
+ class MergeWhenPipelineSucceedsService < MergeRequests::BaseService
# Marks the passed `merge_request` to be merged when the build succeeds or
# updates the params for the automatic merge
def execute(merge_request)
diff --git a/app/services/system_note_service.rb b/app/services/system_note_service.rb
index a33845848b4..8b48d90f60b 100644
--- a/app/services/system_note_service.rb
+++ b/app/services/system_note_service.rb
@@ -131,14 +131,14 @@ module SystemNoteService
create_note(noteable: noteable, project: project, author: author, note: body)
end
- # Called when 'merge when build succeeds' is executed
+ # Called when 'merge when pipeline succeeds' is executed
def merge_when_build_succeeds(noteable, project, author, last_commit)
- body = "enabled an automatic merge when the build for #{last_commit.to_reference(project)} succeeds"
+ body = "enabled an automatic merge when the pipeline for #{last_commit.to_reference(project)} succeeds"
create_note(noteable: noteable, project: project, author: author, note: body)
end
- # Called when 'merge when build succeeds' is canceled
+ # Called when 'merge when pipeline succeeds' is canceled
def cancel_merge_when_build_succeeds(noteable, project, author)
body = 'canceled the automatic merge'
@@ -163,6 +163,14 @@ module SystemNoteService
create_note(noteable: merge_request, project: project, author: author, note: body)
end
+ def discussion_continued_in_issue(discussion, project, author, issue)
+ body = "Added #{issue.to_reference} to continue this discussion"
+ note_attributes = discussion.reply_attributes.merge(project: project, author: author, note: body)
+ note_attributes[:type] = note_attributes.delete(:note_type)
+
+ create_note(note_attributes)
+ end
+
# Called when the title of a Noteable is changed
#
# noteable - Noteable object that responds to `title`
diff --git a/app/views/admin/abuse_reports/index.html.haml b/app/views/admin/abuse_reports/index.html.haml
index 7bbc75db9ff..c4b748d0ab8 100644
--- a/app/views/admin/abuse_reports/index.html.haml
+++ b/app/views/admin/abuse_reports/index.html.haml
@@ -4,7 +4,7 @@
.abuse-reports
- if @abuse_reports.present?
.table-holder
- %table.table
+ %table.table.responsive-table
%thead.hidden-sm.hidden-xs
%tr
%th User
@@ -13,8 +13,6 @@
%th Action
= render @abuse_reports
- else
- .no-reports
- %span.pull-left
- There are no abuse reports!
- .pull-left
- = emoji_icon 'tada'
+ .empty-state
+ .text-center
+ %h4 There are no abuse reports! #{emoji_icon 'tada'}
diff --git a/app/views/admin/dashboard/index.html.haml b/app/views/admin/dashboard/index.html.haml
index 1db2150f336..e51f4ac1d93 100644
--- a/app/views/admin/dashboard/index.html.haml
+++ b/app/views/admin/dashboard/index.html.haml
@@ -113,7 +113,7 @@
%hr
.row
.col-sm-4
- .light-well
+ .light-well.well-centered
%h4 Projects
.data
= link_to admin_namespaces_projects_path do
@@ -121,7 +121,7 @@
%hr
= link_to('New Project', new_project_path, class: "btn btn-new")
.col-sm-4
- .light-well
+ .light-well.well-centered
%h4 Users
.data
= link_to admin_users_path do
@@ -129,7 +129,7 @@
%hr
= link_to 'New User', new_admin_user_path, class: "btn btn-new"
.col-sm-4
- .light-well
+ .light-well.well-centered
%h4 Groups
.data
= link_to admin_groups_path do
@@ -143,7 +143,7 @@
%hr
- @projects.each do |project|
%p
- = link_to project.name_with_namespace, [:admin, project.namespace.becomes(Namespace), project], class: 'str-truncated'
+ = link_to project.name_with_namespace, [:admin, project.namespace.becomes(Namespace), project], class: 'str-truncated-60'
%span.light.pull-right
#{time_ago_with_tooltip(project.created_at)}
@@ -152,7 +152,7 @@
%hr
- @users.each do |user|
%p
- = link_to [:admin, user], class: 'str-truncated' do
+ = link_to [:admin, user], class: 'str-truncated-60' do
= user.name
%span.light.pull-right
#{time_ago_with_tooltip(user.created_at)}
@@ -162,7 +162,7 @@
%hr
- @groups.each do |group|
%p
- = link_to [:admin, group], class: 'str-truncated' do
+ = link_to [:admin, group], class: 'str-truncated-60' do
= group.name
%span.light.pull-right
#{time_ago_with_tooltip(group.created_at)}
diff --git a/app/views/admin/users/_user.html.haml b/app/views/admin/users/_user.html.haml
index 4bf1c9cde3c..2d9588f9d27 100644
--- a/app/views/admin/users/_user.html.haml
+++ b/app/views/admin/users/_user.html.haml
@@ -1,8 +1,8 @@
-%li.user-row
+%li.flex-row
.user-avatar
= image_tag avatar_icon(user), class: "avatar", alt: ''
- .user-details
- .user-name
+ .row-main-content
+ .user-name.row-title.str-truncated-100
= link_to user.name, [:admin, user]
- if user.blocked?
%span.label.label-danger blocked
@@ -12,7 +12,7 @@
%span.label.label-default External
- if user == current_user
%span It's you!
- .user-email
+ .row-second-line.str-truncated-100
= mail_to user.email, user.email
.controls
= link_to 'Edit', edit_admin_user_path(user), id: "edit_#{dom_id(user)}", class: 'btn'
diff --git a/app/views/admin/users/index.html.haml b/app/views/admin/users/index.html.haml
index d3038ae644f..4dc44225d49 100644
--- a/app/views/admin/users/index.html.haml
+++ b/app/views/admin/users/index.html.haml
@@ -68,7 +68,7 @@
%small.badge= number_with_delimiter(User.without_projects.count)
.fade-right
- %ul.users-list.content-list
+ %ul.flex-list.content-list
- if @users.empty?
%li
.nothing-here-block No users found.
diff --git a/app/views/admin/users/projects.html.haml b/app/views/admin/users/projects.html.haml
index 84b9ceb23b3..dd6b7303493 100644
--- a/app/views/admin/users/projects.html.haml
+++ b/app/views/admin/users/projects.html.haml
@@ -7,7 +7,7 @@
%ul.well-list
- @user.groups.each do |group|
%li
- %strong= group.name
+ %strong= link_to group.name, admin_group_path(group)
&ndash; access to
#{pluralize(group.projects.count, 'project')}
diff --git a/app/views/devise/confirmations/almost_there.haml b/app/views/devise/confirmations/almost_there.haml
index 20cd7b0179d..fb70d158096 100644
--- a/app/views/devise/confirmations/almost_there.haml
+++ b/app/views/devise/confirmations/almost_there.haml
@@ -1,12 +1,13 @@
-.well-confirmation.text-center
+.well-confirmation.text-center.append-bottom-20
%h1.prepend-top-0
Almost there...
- %p.lead
+ %p.lead.append-bottom-20
Please check your email to confirm your account
+ %hr
- if current_application_settings.after_sign_up_text.present?
.well-confirmation.text-center
= markdown_field(current_application_settings, :after_sign_up_text)
-%p.confirmation-content.text-center
+%p.text-center
No confirmation email received? Please check your spam folder or
.append-bottom-20.prepend-top-20.text-center
%a.btn.btn-lg.btn-success{ href: new_user_confirmation_path }
diff --git a/app/views/layouts/nav/_group.html.haml b/app/views/layouts/nav/_group.html.haml
index f7edb47b666..f3539fd372d 100644
--- a/app/views/layouts/nav/_group.html.haml
+++ b/app/views/layouts/nav/_group.html.haml
@@ -31,7 +31,7 @@
= link_to merge_requests_group_path(@group), title: 'Merge Requests' do
%span
Merge Requests
- - merge_requests = MergeRequestsFinder.new(current_user, group_id: @group.id, state: 'opened').execute
+ - merge_requests = MergeRequestsFinder.new(current_user, group_id: @group.id, state: 'opened', non_archived: true).execute
%span.badge.count= number_with_delimiter(merge_requests.count)
= nav_link(controller: [:group_members]) do
= link_to group_group_members_path(@group), title: 'Members' do
diff --git a/app/views/projects/_readme.html.haml b/app/views/projects/_readme.html.haml
index 369a847e7d4..b6fb08b68e9 100644
--- a/app/views/projects/_readme.html.haml
+++ b/app/views/projects/_readme.html.haml
@@ -18,5 +18,5 @@
distributed with computer software, forming part of its documentation.
%p
We recommend you to
- = link_to "add a README", new_readme_path, class: 'underlined-link'
+ = link_to "add a README", add_special_file_path(@project, file_name: 'README.md'), class: 'underlined-link'
file to the repository and GitLab will render it here instead of this message.
diff --git a/app/views/projects/blame/show.html.haml b/app/views/projects/blame/show.html.haml
index cadfe5a3e30..f63802ac88b 100644
--- a/app/views/projects/blame/show.html.haml
+++ b/app/views/projects/blame/show.html.haml
@@ -31,7 +31,7 @@
&nbsp;
.light
= commit_author_link(commit, avatar: false)
- authored
+ committed
#{time_ago_with_tooltip(commit.committed_date)}
%td.line-numbers
- line_count = blame_group[:lines].count
diff --git a/app/views/projects/buttons/_download.html.haml b/app/views/projects/buttons/_download.html.haml
index 7b995bd8735..40bfa01a45a 100644
--- a/app/views/projects/buttons/_download.html.haml
+++ b/app/views/projects/buttons/_download.html.haml
@@ -1,42 +1,41 @@
- if !project.empty_repo? && can?(current_user, :download_code, project)
- %span{class: 'download-button'}
- .dropdown.inline
- %button.btn{ 'data-toggle' => 'dropdown' }
- = icon('download')
- = icon("caret-down")
- %span.sr-only
- Select Archive Format
- %ul.dropdown-menu.dropdown-menu-align-right{ role: 'menu' }
- %li.dropdown-header Source code
- %li
- = link_to archive_namespace_project_repository_path(project.namespace, project, ref: ref, format: 'zip'), rel: 'nofollow' do
- %i.fa.fa-download
- %span Download zip
- %li
- = link_to archive_namespace_project_repository_path(project.namespace, project, ref: ref, format: 'tar.gz'), rel: 'nofollow' do
- %i.fa.fa-download
- %span Download tar.gz
- %li
- = link_to archive_namespace_project_repository_path(project.namespace, project, ref: ref, format: 'tar.bz2'), rel: 'nofollow' do
- %i.fa.fa-download
- %span Download tar.bz2
- %li
- = link_to archive_namespace_project_repository_path(project.namespace, project, ref: ref, format: 'tar'), rel: 'nofollow' do
- %i.fa.fa-download
- %span Download tar
+ .dropdown.inline.download-button
+ %button.btn{ 'data-toggle' => 'dropdown' }
+ = icon('download')
+ = icon("caret-down")
+ %span.sr-only
+ Select Archive Format
+ %ul.dropdown-menu.dropdown-menu-align-right{ role: 'menu' }
+ %li.dropdown-header Source code
+ %li
+ = link_to archive_namespace_project_repository_path(project.namespace, project, ref: ref, format: 'zip'), rel: 'nofollow' do
+ %i.fa.fa-download
+ %span Download zip
+ %li
+ = link_to archive_namespace_project_repository_path(project.namespace, project, ref: ref, format: 'tar.gz'), rel: 'nofollow' do
+ %i.fa.fa-download
+ %span Download tar.gz
+ %li
+ = link_to archive_namespace_project_repository_path(project.namespace, project, ref: ref, format: 'tar.bz2'), rel: 'nofollow' do
+ %i.fa.fa-download
+ %span Download tar.bz2
+ %li
+ = link_to archive_namespace_project_repository_path(project.namespace, project, ref: ref, format: 'tar'), rel: 'nofollow' do
+ %i.fa.fa-download
+ %span Download tar
- - pipeline = project.pipelines.latest_successful_for(ref)
- - if pipeline
- - artifacts = pipeline.builds.latest.with_artifacts
- - if artifacts.any?
- %li.dropdown-header Artifacts
- - unless pipeline.latest?
- - latest_pipeline = project.pipeline_for(ref)
- %li
- .unclickable= ci_status_for_statuseable(latest_pipeline)
- %li.dropdown-header Previous Artifacts
- - artifacts.each do |job|
- %li
- = link_to latest_succeeded_namespace_project_artifacts_path(project.namespace, project, "#{ref}/download", job: job.name), rel: 'nofollow' do
- %i.fa.fa-download
- %span Download '#{job.name}'
+ - pipeline = project.pipelines.latest_successful_for(ref)
+ - if pipeline
+ - artifacts = pipeline.builds.latest.with_artifacts
+ - if artifacts.any?
+ %li.dropdown-header Artifacts
+ - unless pipeline.latest?
+ - latest_pipeline = project.pipeline_for(ref)
+ %li
+ .unclickable= ci_status_for_statuseable(latest_pipeline)
+ %li.dropdown-header Previous Artifacts
+ - artifacts.each do |job|
+ %li
+ = link_to latest_succeeded_namespace_project_artifacts_path(project.namespace, project, "#{ref}/download", job: job.name), rel: 'nofollow' do
+ %i.fa.fa-download
+ %span Download '#{job.name}'
diff --git a/app/views/projects/ci/pipelines/_pipeline.html.haml b/app/views/projects/ci/pipelines/_pipeline.html.haml
index 4c7b14a04db..0f08f4e8592 100644
--- a/app/views/projects/ci/pipelines/_pipeline.html.haml
+++ b/app/views/projects/ci/pipelines/_pipeline.html.haml
@@ -1,12 +1,13 @@
- status = pipeline.status
+- detailed_status = pipeline.detailed_status
- show_commit = local_assigns.fetch(:show_commit, true)
- show_branch = local_assigns.fetch(:show_branch, true)
%tr.commit
%td.commit-link
- = link_to namespace_project_pipeline_path(pipeline.project.namespace, pipeline.project, pipeline.id), class: "ci-status ci-#{status}" do
- = ci_icon_for_status(status)
- = ci_label_for_status(status)
+ = link_to namespace_project_pipeline_path(pipeline.project.namespace, pipeline.project, pipeline.id), class: "ci-status ci-#{detailed_status}" do
+ = ci_icon_for_status(detailed_status)
+ = ci_text_for_status(detailed_status)
%td
= link_to namespace_project_pipeline_path(pipeline.project.namespace, pipeline.project, pipeline.id) do
diff --git a/app/views/projects/commits/_commit.html.haml b/app/views/projects/commits/_commit.html.haml
index 12096941209..a940515fadf 100644
--- a/app/views/projects/commits/_commit.html.haml
+++ b/app/views/projects/commits/_commit.html.haml
@@ -37,5 +37,5 @@
= preserve(markdown(commit.description, pipeline: :single_line, author: commit.author))
= commit_author_link(commit, avatar: false, size: 24)
- authored
+ committed
#{time_ago_with_tooltip(commit.committed_date)}
diff --git a/app/views/projects/empty.html.haml b/app/views/projects/empty.html.haml
index 7a39064adc5..c0a83091c8c 100644
--- a/app/views/projects/empty.html.haml
+++ b/app/views/projects/empty.html.haml
@@ -16,7 +16,7 @@
%p
Otherwise you can start with adding a
= succeed ',' do
- = link_to "README", new_readme_path, class: 'underlined-link'
+ = link_to "README", add_special_file_path(@project, file_name: 'README.md'), class: 'underlined-link'
a
= succeed ',' do
= link_to "LICENSE", add_special_file_path(@project, file_name: 'LICENSE'), class: 'underlined-link'
diff --git a/app/views/projects/merge_requests/widget/_heading.html.haml b/app/views/projects/merge_requests/widget/_heading.html.haml
index 6d9b91ad0e7..9ab7971b56c 100644
--- a/app/views/projects/merge_requests/widget/_heading.html.haml
+++ b/app/views/projects/merge_requests/widget/_heading.html.haml
@@ -8,14 +8,13 @@
= link_to "##{@pipeline.id}", namespace_project_pipeline_path(@pipeline.project.namespace, @pipeline.project, @pipeline.id), class: 'pipeline'
= ci_label_for_status(status)
for
- - commit = @merge_request.diff_head_commit
= succeed "." do
= link_to @pipeline.short_sha, namespace_project_commit_path(@merge_request.source_project.namespace, @merge_request.source_project, @pipeline.sha), class: "monospace"
%span.ci-coverage
- elsif @merge_request.has_ci?
- # Compatibility with old CI integrations (ex jenkins) when you request status from CI server via AJAX
- - # Remove in later versions when services like Jenkins will set CI status via Commit status API
+ - # TODO, remove in later versions when services like Jenkins will set CI status via Commit status API
.mr-widget-heading
- %w[success skipped canceled failed running pending].each do |status|
.ci_widget{class: "ci-#{status}", style: "display:none"}
diff --git a/app/views/projects/merge_requests/widget/open/_accept.html.haml b/app/views/projects/merge_requests/widget/open/_accept.html.haml
index ce43ca3a286..435fe835fae 100644
--- a/app/views/projects/merge_requests/widget/open/_accept.html.haml
+++ b/app/views/projects/merge_requests/widget/open/_accept.html.haml
@@ -9,7 +9,7 @@
- if @pipeline && @pipeline.active?
%span.btn-group
= button_tag class: "btn btn-create js-merge-button merge_when_build_succeeds" do
- Merge When Build Succeeds
+ Merge When Pipeline Succeeds
- unless @project.only_allow_merge_if_build_succeeds?
= button_tag class: "btn btn-success dropdown-toggle", 'data-toggle' => 'dropdown' do
= icon('caret-down')
@@ -19,7 +19,7 @@
%li
= link_to "#", class: "merge_when_build_succeeds" do
= icon('check fw')
- Merge When Build Succeeds
+ Merge When Pipeline Succeeds
%li
= link_to "#", class: "accept_merge_request" do
= icon('warning fw')
diff --git a/app/views/projects/merge_requests/widget/open/_merge_when_build_succeeds.html.haml b/app/views/projects/merge_requests/widget/open/_merge_when_build_succeeds.html.haml
index 1aeb12e4661..072d01d144e 100644
--- a/app/views/projects/merge_requests/widget/open/_merge_when_build_succeeds.html.haml
+++ b/app/views/projects/merge_requests/widget/open/_merge_when_build_succeeds.html.haml
@@ -1,6 +1,6 @@
%h4
Set by #{link_to_member(@project, @merge_request.merge_user, avatar: true)}
- to be merged automatically when the build succeeds.
+ to be merged automatically when the pipeline succeeds.
%div
%p
= succeed '.' do
diff --git a/app/views/projects/merge_requests/widget/open/_unresolved_discussions.html.haml b/app/views/projects/merge_requests/widget/open/_unresolved_discussions.html.haml
index 35d5677ee37..e094f97f3b6 100644
--- a/app/views/projects/merge_requests/widget/open/_unresolved_discussions.html.haml
+++ b/app/views/projects/merge_requests/widget/open/_unresolved_discussions.html.haml
@@ -3,4 +3,8 @@
This merge request has unresolved discussions
%p
- Please resolve these discussions to allow this merge request to be merged. \ No newline at end of file
+ Please resolve these discussions
+ - if @project.issues_enabled? && can?(current_user, :create_issue, @project)
+ or
+ = link_to "open an issue to resolve them later", new_namespace_project_issue_path(@project.namespace, @project, merge_request_for_resolving_discussions: @merge_request.iid)
+ to allow this merge request to be merged.
diff --git a/app/views/projects/pipelines/_info.html.haml b/app/views/projects/pipelines/_info.html.haml
index 095bd254d6b..229bdfb0e8d 100644
--- a/app/views/projects/pipelines/_info.html.haml
+++ b/app/views/projects/pipelines/_info.html.haml
@@ -1,6 +1,6 @@
.page-content-header
.header-main-content
- = ci_status_with_icon(@pipeline.status)
+ = ci_status_with_icon(@pipeline.detailed_status)
%strong Pipeline ##{@commit.pipelines.last.id}
triggered #{time_ago_with_tooltip(@commit.authored_date)} by
= author_avatar(@commit, size: 24)
diff --git a/app/views/projects/pipelines_settings/_badge.html.haml b/app/views/projects/pipelines_settings/_badge.html.haml
index 7b7fa56d993..22a3b884520 100644
--- a/app/views/projects/pipelines_settings/_badge.html.haml
+++ b/app/views/projects/pipelines_settings/_badge.html.haml
@@ -1,4 +1,4 @@
-.row{ class: badge.title.gsub(' ', '-') }
+%div{ class: badge.title.gsub(' ', '-') }
.col-lg-3.profile-settings-sidebar
%h4.prepend-top-0
= badge.title.capitalize
diff --git a/app/views/projects/pipelines_settings/show.html.haml b/app/views/projects/pipelines_settings/show.html.haml
index 96221a20502..1f698558bce 100644
--- a/app/views/projects/pipelines_settings/show.html.haml
+++ b/app/views/projects/pipelines_settings/show.html.haml
@@ -86,6 +86,9 @@
%li
tap --coverage-report=text-summary (NodeJS) -
%code ^Statements\s*:\s*([^%]+)
+ %li
+ excoveralls (Elixir) -
+ %code \[TOTAL\]\s+(\d+\.\d+)%
= f.submit 'Save changes', class: "btn btn-save"
diff --git a/app/views/projects/tags/show.html.haml b/app/views/projects/tags/show.html.haml
index 155af755759..12facb6eb73 100644
--- a/app/views/projects/tags/show.html.haml
+++ b/app/views/projects/tags/show.html.haml
@@ -3,8 +3,16 @@
= render "projects/commits/head"
%div{ class: container_class }
- .sub-header-block
- .pull-right.tag-buttons
+ .top-area.multi-line
+ .nav-text
+ .title
+ %span.item-title= @tag.name
+ - if @commit
+ = render 'projects/branches/commit', commit: @commit, project: @project
+ - else
+ Cant find HEAD commit for this tag
+
+ .nav-controls
- if can?(current_user, :push_code, @project)
= link_to edit_namespace_project_tag_release_path(@project.namespace, @project, @tag.name), class: 'btn has-tooltip', title: 'Edit release notes' do
= icon("pencil")
@@ -15,15 +23,8 @@
= render 'projects/buttons/download', project: @project, ref: @tag.name
- if can?(current_user, :admin_project, @project)
.pull-right
- = link_to namespace_project_tag_path(@project.namespace, @project, @tag.name), class: 'btn btn-remove remove-row grouped has-tooltip', title: "Delete tag", method: :delete, data: { confirm: "Deleting the '#{@tag.name}' tag cannot be undone. Are you sure?" } do
+ = link_to namespace_project_tag_path(@project.namespace, @project, @tag.name), class: 'btn btn-remove remove-row has-tooltip', title: "Delete tag", method: :delete, data: { confirm: "Deleting the '#{@tag.name}' tag cannot be undone. Are you sure?" } do
%i.fa.fa-trash-o
- .tag-info.append-bottom-10
- .title
- %span.item-title= @tag.name
- - if @commit
- = render 'projects/branches/commit', commit: @commit, project: @project
- - else
- Cant find HEAD commit for this tag
- if @tag.message.present?
%pre.body
= strip_gpg_signature(@tag.message)
diff --git a/app/views/shared/issuable/_form.html.haml b/app/views/shared/issuable/_form.html.haml
index 2f05093f435..bdb00bfa33c 100644
--- a/app/views/shared/issuable/_form.html.haml
+++ b/app/views/shared/issuable/_form.html.haml
@@ -42,6 +42,21 @@
= render 'shared/issuable/form/branch_chooser', issuable: issuable, form: form
+- if @merge_request_for_resolving_discussions
+ .form-group
+ .col-sm-10.col-sm-offset-2
+ - if @merge_request_for_resolving_discussions.discussions_can_be_resolved_by?(current_user)
+ = icon('exclamation-triangle')
+ Creating this issue will mark all discussions in
+ = link_to @merge_request_for_resolving_discussions.to_reference, merge_request_path(@merge_request_for_resolving_discussions)
+ as resolved.
+ = hidden_field_tag 'merge_request_for_resolving_discussions', @merge_request_for_resolving_discussions.iid
+ - else
+ = icon('exclamation-triangle')
+ You can't automatically mark all discussions in
+ = link_to @merge_request_for_resolving_discussions.to_reference, merge_request_path(@merge_request_for_resolving_discussions)
+ as resolved. Ask someone with sufficient rights to resolve the them.
+
- is_footer = !(issuable.is_a?(MergeRequest) && issuable.new_record?)
.row-content-block{class: (is_footer ? "footer-block" : "middle-block")}
- if issuable.new_record?
diff --git a/app/views/shared/issuable/_nav.html.haml b/app/views/shared/issuable/_nav.html.haml
index 5527a2f889a..0af92b59584 100644
--- a/app/views/shared/issuable/_nav.html.haml
+++ b/app/views/shared/issuable/_nav.html.haml
@@ -4,22 +4,22 @@
%ul.nav-links.issues-state-filters
%li{class: ("active" if params[:state] == 'opened')}
- = link_to page_filter_path(state: 'opened', label: true), title: "Filter by #{page_context_word} that are currently opened." do
+ = link_to page_filter_path(state: 'opened', label: true), id: 'state-opened', title: "Filter by #{page_context_word} that are currently opened." do
#{issuables_state_counter_text(type, :opened)}
- if type == :merge_requests
%li{class: ("active" if params[:state] == 'merged')}
- = link_to page_filter_path(state: 'merged', label: true), title: 'Filter by merge requests that are currently merged.' do
+ = link_to page_filter_path(state: 'merged', label: true), id: 'state-merged', title: 'Filter by merge requests that are currently merged.' do
#{issuables_state_counter_text(type, :merged)}
%li{class: ("active" if params[:state] == 'closed')}
- = link_to page_filter_path(state: 'closed', label: true), title: 'Filter by merge requests that are currently closed and unmerged.' do
+ = link_to page_filter_path(state: 'closed', label: true), id: 'state-closed', title: 'Filter by merge requests that are currently closed and unmerged.' do
#{issuables_state_counter_text(type, :closed)}
- else
%li{class: ("active" if params[:state] == 'closed')}
- = link_to page_filter_path(state: 'closed', label: true), title: 'Filter by issues that are currently closed.' do
+ = link_to page_filter_path(state: 'closed', label: true), id: 'state-all', title: 'Filter by issues that are currently closed.' do
#{issuables_state_counter_text(type, :closed)}
%li{class: ("active" if params[:state] == 'all')}
- = link_to page_filter_path(state: 'all', label: true), title: "Show all #{page_context_word}." do
+ = link_to page_filter_path(state: 'all', label: true), id: 'state-all', title: "Show all #{page_context_word}." do
#{issuables_state_counter_text(type, :all)}
diff --git a/app/workers/pipeline_success_worker.rb b/app/workers/pipeline_success_worker.rb
index 2aa6fff24da..cc0eb708cf9 100644
--- a/app/workers/pipeline_success_worker.rb
+++ b/app/workers/pipeline_success_worker.rb
@@ -4,7 +4,7 @@ class PipelineSuccessWorker
def perform(pipeline_id)
Ci::Pipeline.find_by(id: pipeline_id).try do |pipeline|
- MergeRequests::MergeWhenBuildSucceedsService
+ MergeRequests::MergeWhenPipelineSucceedsService
.new(pipeline.project, nil)
.trigger(pipeline)
end
diff --git a/changelogs/unreleased/23500-enable-colorvariable.yml b/changelogs/unreleased/23500-enable-colorvariable.yml
new file mode 100644
index 00000000000..98e22a934b8
--- /dev/null
+++ b/changelogs/unreleased/23500-enable-colorvariable.yml
@@ -0,0 +1,4 @@
+---
+title: Enable ColorVariable in scss-lint
+merge_request:
+author: Sam Rose
diff --git a/changelogs/unreleased/23589-open-issue-for-mr.yml b/changelogs/unreleased/23589-open-issue-for-mr.yml
new file mode 100644
index 00000000000..cea48b85254
--- /dev/null
+++ b/changelogs/unreleased/23589-open-issue-for-mr.yml
@@ -0,0 +1,5 @@
+---
+title: Resolve all discussions in a merge request by creating an issue collecting
+ them
+merge_request: 7180
+author: Bob Van Landuyt
diff --git a/changelogs/unreleased/23696-fix-diff-view-highlighting.yml b/changelogs/unreleased/23696-fix-diff-view-highlighting.yml
new file mode 100644
index 00000000000..db523caffed
--- /dev/null
+++ b/changelogs/unreleased/23696-fix-diff-view-highlighting.yml
@@ -0,0 +1,4 @@
+---
+title: Fix diff view permalink highlighting
+merge_request: 7090
+author:
diff --git a/changelogs/unreleased/24669-merge-request-dashboard-page-takes-over-a-minute-to-load.yml b/changelogs/unreleased/24669-merge-request-dashboard-page-takes-over-a-minute-to-load.yml
deleted file mode 100644
index 01b19a47ecd..00000000000
--- a/changelogs/unreleased/24669-merge-request-dashboard-page-takes-over-a-minute-to-load.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Speed up issuable dashboards
-merge_request:
-author:
diff --git a/changelogs/unreleased/24733-archived-project-merge-request-count.yml b/changelogs/unreleased/24733-archived-project-merge-request-count.yml
new file mode 100644
index 00000000000..2bc7e91825a
--- /dev/null
+++ b/changelogs/unreleased/24733-archived-project-merge-request-count.yml
@@ -0,0 +1,4 @@
+---
+title: Fix Archived project merge requests add to group's Merge Requests
+merge_request: 7790
+author: Jacopo Beschi @jacopo-beschi
diff --git a/changelogs/unreleased/24921-hide-prompt-to-add-ssh-key-if-ssh-protocol-is-disabled.yml b/changelogs/unreleased/24921-hide-prompt-to-add-ssh-key-if-ssh-protocol-is-disabled.yml
new file mode 100644
index 00000000000..4d4019e770e
--- /dev/null
+++ b/changelogs/unreleased/24921-hide-prompt-to-add-ssh-key-if-ssh-protocol-is-disabled.yml
@@ -0,0 +1,4 @@
+---
+title: Don't display prompt to add SSH keys if SSH protocol is disabled
+merge_request: 7840
+author: Andrew Smith (EspadaV8)
diff --git a/changelogs/unreleased/25098-header-margins-on-pipeline-settings.yml b/changelogs/unreleased/25098-header-margins-on-pipeline-settings.yml
new file mode 100644
index 00000000000..1799fad1631
--- /dev/null
+++ b/changelogs/unreleased/25098-header-margins-on-pipeline-settings.yml
@@ -0,0 +1,5 @@
+---
+title: Adjusted margins for Build Status and Coverage Report rows to match those of
+ the CI/CD Pipeline row
+merge_request:
+author: Ryan Harris
diff --git a/changelogs/unreleased/25199-fix-broken-urls-in-help-page.yml b/changelogs/unreleased/25199-fix-broken-urls-in-help-page.yml
deleted file mode 100644
index 58efd9113f2..00000000000
--- a/changelogs/unreleased/25199-fix-broken-urls-in-help-page.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Don't change relative URLs to absolute URLs in the Help page
-merge_request:
-author:
diff --git a/changelogs/unreleased/25202-fix-mr-widget-content-wrapping.yml b/changelogs/unreleased/25202-fix-mr-widget-content-wrapping.yml
new file mode 100644
index 00000000000..7afc794866b
--- /dev/null
+++ b/changelogs/unreleased/25202-fix-mr-widget-content-wrapping.yml
@@ -0,0 +1,5 @@
+---
+title: Centered Accept Merge Request button within MR widget and added padding for
+ viewports smaller than 768px
+merge_request:
+author: Ryan Harris
diff --git a/changelogs/unreleased/25221-fix-build-status-overflow-mobile.yml b/changelogs/unreleased/25221-fix-build-status-overflow-mobile.yml
new file mode 100644
index 00000000000..52de34478f0
--- /dev/null
+++ b/changelogs/unreleased/25221-fix-build-status-overflow-mobile.yml
@@ -0,0 +1,4 @@
+---
+title: Added top margin to Build status page header for mobile views
+merge_request:
+author: Ryan Harris
diff --git a/changelogs/unreleased/25251-actionview-template-error-undefined-method-text-for-nil-nilclass.yml b/changelogs/unreleased/25251-actionview-template-error-undefined-method-text-for-nil-nilclass.yml
new file mode 100644
index 00000000000..7f1c417bc77
--- /dev/null
+++ b/changelogs/unreleased/25251-actionview-template-error-undefined-method-text-for-nil-nilclass.yml
@@ -0,0 +1,5 @@
+---
+title: 'Fixes "ActionView::Template::Error: undefined method `text?` for nil:NilClass"
+ on MR pages'
+merge_request:
+author:
diff --git a/changelogs/unreleased/25264-ref-commit.yml b/changelogs/unreleased/25264-ref-commit.yml
new file mode 100644
index 00000000000..13a33da9801
--- /dev/null
+++ b/changelogs/unreleased/25264-ref-commit.yml
@@ -0,0 +1,4 @@
+---
+title: Change ref property to commitRef in vue commit component
+merge_request: 7901
+author:
diff --git a/changelogs/unreleased/api-expose-commiter-details.yml b/changelogs/unreleased/api-expose-commiter-details.yml
new file mode 100644
index 00000000000..5ee34adc5c9
--- /dev/null
+++ b/changelogs/unreleased/api-expose-commiter-details.yml
@@ -0,0 +1,4 @@
+---
+title: 'API: Expose committer details for commits'
+merge_request:
+author: Robert Schilling
diff --git a/changelogs/unreleased/cleanup-common_utils-js.yml b/changelogs/unreleased/cleanup-common_utils-js.yml
new file mode 100644
index 00000000000..54d81b76c28
--- /dev/null
+++ b/changelogs/unreleased/cleanup-common_utils-js.yml
@@ -0,0 +1,4 @@
+---
+title: Clean up common_utils.js
+merge_request: 7318
+author: winniehell
diff --git a/changelogs/unreleased/feature-admin-user-groups-link.yml b/changelogs/unreleased/feature-admin-user-groups-link.yml
new file mode 100644
index 00000000000..b89c08f82d7
--- /dev/null
+++ b/changelogs/unreleased/feature-admin-user-groups-link.yml
@@ -0,0 +1,4 @@
+---
+title: The admin user projects view now has a clickable group link
+merge_request: 7620
+author: James Gregory
diff --git a/changelogs/unreleased/fix-authorize-users-into-imported-gitlab-project.yml b/changelogs/unreleased/fix-authorize-users-into-imported-gitlab-project.yml
new file mode 100644
index 00000000000..9f14463fdd1
--- /dev/null
+++ b/changelogs/unreleased/fix-authorize-users-into-imported-gitlab-project.yml
@@ -0,0 +1,4 @@
+---
+title: Authorize users into imported GitLab project
+merge_request:
+author:
diff --git a/changelogs/unreleased/fix-compatibility-with-ie11-for-merge-requests.yml b/changelogs/unreleased/fix-compatibility-with-ie11-for-merge-requests.yml
new file mode 100644
index 00000000000..db92e45d8f1
--- /dev/null
+++ b/changelogs/unreleased/fix-compatibility-with-ie11-for-merge-requests.yml
@@ -0,0 +1,4 @@
+---
+title: Fix compatibility with Internet Explorer 11 for merge requests
+merge_request: 7525
+author: Steffen Rauh
diff --git a/changelogs/unreleased/fix-github-branch-formatter.yml b/changelogs/unreleased/fix-github-branch-formatter.yml
deleted file mode 100644
index c8698f507de..00000000000
--- a/changelogs/unreleased/fix-github-branch-formatter.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Fix branch validation for GitHub PR where repo/fork was renamed/deleted
-merge_request:
-author:
diff --git a/changelogs/unreleased/fix-rename-mwbs-to-merge-when-pipeline-succeeds.yml b/changelogs/unreleased/fix-rename-mwbs-to-merge-when-pipeline-succeeds.yml
new file mode 100644
index 00000000000..f8acc6ef8ad
--- /dev/null
+++ b/changelogs/unreleased/fix-rename-mwbs-to-merge-when-pipeline-succeeds.yml
@@ -0,0 +1,4 @@
+---
+title: Rename Merge When Build Succeeds to Merge When Pipeline Succeeds
+merge_request: 7135
+author:
diff --git a/changelogs/unreleased/glm-shorthand-reference.yml b/changelogs/unreleased/glm-shorthand-reference.yml
new file mode 100644
index 00000000000..6d60f23c798
--- /dev/null
+++ b/changelogs/unreleased/glm-shorthand-reference.yml
@@ -0,0 +1,4 @@
+---
+title: Add shorthand support to gitlab markdown references
+merge_request: 7255
+author: Oswaldo Ferreira
diff --git a/changelogs/unreleased/issues-1608-text.yml b/changelogs/unreleased/issues-1608-text.yml
new file mode 100644
index 00000000000..bef427a1e1e
--- /dev/null
+++ b/changelogs/unreleased/issues-1608-text.yml
@@ -0,0 +1,4 @@
+---
+title: change text around timestamps to make it clear which timestamp is displayed
+merge_request: 7860
+author: BM5k
diff --git a/changelogs/unreleased/mr-origin-7855.yml b/changelogs/unreleased/mr-origin-7855.yml
new file mode 100644
index 00000000000..0fdc6153d55
--- /dev/null
+++ b/changelogs/unreleased/mr-origin-7855.yml
@@ -0,0 +1,4 @@
+---
+title: Provides a sensible default message when adding a README to a project
+merge_request: 7903
+author:
diff --git a/changelogs/unreleased/process-commit-worker-improvements.yml b/changelogs/unreleased/process-commit-worker-improvements.yml
deleted file mode 100644
index 0038c6e34e6..00000000000
--- a/changelogs/unreleased/process-commit-worker-improvements.yml
+++ /dev/null
@@ -1,4 +0,0 @@
----
-title: Pass commit data to ProcessCommitWorker to reduce Git overhead
-merge_request: 7744
-author:
diff --git a/changelogs/unreleased/refactor-create-service-spec.yml b/changelogs/unreleased/refactor-create-service-spec.yml
new file mode 100644
index 00000000000..148a0fee02c
--- /dev/null
+++ b/changelogs/unreleased/refactor-create-service-spec.yml
@@ -0,0 +1,4 @@
+---
+title: Refactor create service spec
+merge_request: 7609
+author: Semyon Pupkov
diff --git a/changelogs/unreleased/remove-has-visible-content-caching.yml b/changelogs/unreleased/remove-has-visible-content-caching.yml
new file mode 100644
index 00000000000..e2940c60443
--- /dev/null
+++ b/changelogs/unreleased/remove-has-visible-content-caching.yml
@@ -0,0 +1,4 @@
+---
+title: Remove visible content caching
+merge_request:
+author:
diff --git a/changelogs/unreleased/validate-state-param-when-filtering-issuables.yml b/changelogs/unreleased/validate-state-param-when-filtering-issuables.yml
new file mode 100644
index 00000000000..3fb025806b0
--- /dev/null
+++ b/changelogs/unreleased/validate-state-param-when-filtering-issuables.yml
@@ -0,0 +1,4 @@
+---
+title: Validate state param when filtering issuables
+merge_request:
+author:
diff --git a/changelogs/unreleased/zj-guest-reads-public-builds.yml b/changelogs/unreleased/zj-guest-reads-public-builds.yml
new file mode 100644
index 00000000000..1859addd606
--- /dev/null
+++ b/changelogs/unreleased/zj-guest-reads-public-builds.yml
@@ -0,0 +1,4 @@
+---
+title: Guests can read builds when public
+merge_request: 6842
+author:
diff --git a/changelogs/unreleased/zj-issue-new-over-issue-create.yml b/changelogs/unreleased/zj-issue-new-over-issue-create.yml
new file mode 100644
index 00000000000..9dd463e4efa
--- /dev/null
+++ b/changelogs/unreleased/zj-issue-new-over-issue-create.yml
@@ -0,0 +1,4 @@
+---
+title: Accept issue new as command to create an issue
+merge_request:
+author:
diff --git a/changelogs/unreleased/zj-use-ruby-2-3-3.yml b/changelogs/unreleased/zj-use-ruby-2-3-3.yml
new file mode 100644
index 00000000000..0d1a0fcd79d
--- /dev/null
+++ b/changelogs/unreleased/zj-use-ruby-2-3-3.yml
@@ -0,0 +1,4 @@
+---
+title: Bump ruby version to 2.3.3
+merge_request: 7904
+author:
diff --git a/config/routes/group.rb b/config/routes/group.rb
index 9fe72990994..776c31c9dac 100644
--- a/config/routes/group.rb
+++ b/config/routes/group.rb
@@ -1,15 +1,5 @@
resources :groups, only: [:index, :new, :create]
-scope(path: 'groups/*id',
- controller: :groups,
- constraints: { id: Gitlab::Regex.namespace_route_regex }) do
- get :edit, as: :edit_group
- get :issues, as: :issues_group
- get :merge_requests, as: :merge_requests_group
- get :projects, as: :projects_group
- get :activity, as: :activity_group
-end
-
scope(path: 'groups/*group_id',
module: :groups,
as: :group,
@@ -22,10 +12,20 @@ scope(path: 'groups/*group_id',
resource :avatar, only: [:destroy]
resources :milestones, constraints: { id: /[^\/]+/ }, only: [:index, :show, :update, :new, :create]
- resources :labels, except: [:show], constraints: { id: /\d+/ } do
+ resources :labels, except: [:show] do
post :toggle_subscription, on: :member
end
end
+scope(path: 'groups/*id',
+ controller: :groups,
+ constraints: { id: Gitlab::Regex.namespace_route_regex }) do
+ get :edit, as: :edit_group
+ get :issues, as: :issues_group
+ get :merge_requests, as: :merge_requests_group
+ get :projects, as: :projects_group
+ get :activity, as: :activity_group
+end
+
# Must be last route in this file
get 'groups/*id' => 'groups#show', as: :group_canonical, constraints: { id: Gitlab::Regex.namespace_route_regex }
diff --git a/doc/administration/custom_hooks.md b/doc/administration/custom_hooks.md
index 0387d730489..06291705702 100644
--- a/doc/administration/custom_hooks.md
+++ b/doc/administration/custom_hooks.md
@@ -42,6 +42,25 @@ Follow the steps below to set up a custom hook:
That's it! Assuming the hook code is properly implemented the hook will fire
as appropriate.
+## Chained hooks support
+
+> [Introduced][93] in GitLab Shell 4.1.0.
+
+The hooks could be also placed in `hooks/<hook_name>.d` (global) or `custom_hooks/<hook_name>.d` (per project)
+directories supporting chained execution of the hooks.
+
+The hooks are searched and executed in this order:
+1. `<project>.git/hooks/` - symlink to `gitlab-shell/hooks` global dir
+1. `<project>.git/hooks/<hook_name>` - executed by `git` itself, this is `gitlab-shell/hooks/<hook_name>`
+1. `<project>.git/custom_hooks/<hook_name>` - per project hook (this is already existing behavior)
+1. `<project>.git/custom_hooks/<hook_name>.d/*` - per project hooks
+1. `<project>.git/hooks/<hook_name>.d/*` - global hooks: all executable files (minus editor backup files)
+
+Files in `.d` directories need to be executable and not match the backup file pattern (`*~`).
+
+The hooks of the same type are executed in order and execution stops on the first
+script exiting with non-zero value.
+
## Custom error messages
> [Introduced][5073] in GitLab 8.10.
@@ -54,3 +73,4 @@ STDERR takes precedence over STDOUT.
[hooks]: https://git-scm.com/book/en/v2/Customizing-Git-Git-Hooks#Server-Side-Hooks
[5073]: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/5073
+[93]: https://gitlab.com/gitlab-org/gitlab-shell/merge_requests/93
diff --git a/doc/api/commits.md b/doc/api/commits.md
index e1ed99d98d3..0170af00e0e 100644
--- a/doc/api/commits.md
+++ b/doc/api/commits.md
@@ -29,6 +29,8 @@ Example response:
"title": "Replace sanitize with escape once",
"author_name": "Dmitriy Zaporozhets",
"author_email": "dzaporozhets@sphereconsultinginc.com",
+ "committer_name": "Administrator",
+ "committer_email": "admin@example.com",
"created_at": "2012-09-20T11:50:22+03:00",
"message": "Replace sanitize with escape once",
"allow_failure": false
@@ -39,6 +41,8 @@ Example response:
"title": "Sanitize for network graph",
"author_name": "randx",
"author_email": "dmitriy.zaporozhets@gmail.com",
+ "committer_name": "Dmitriy",
+ "committer_email": "dmitriy.zaporozhets@gmail.com",
"created_at": "2012-09-20T09:06:12+03:00",
"message": "Sanitize for network graph",
"allow_failure": false
@@ -115,6 +119,8 @@ Example response:
"title": "some commit message",
"author_name": "Dmitriy Zaporozhets",
"author_email": "dzaporozhets@sphereconsultinginc.com",
+ "committer_name": "Dmitriy Zaporozhets",
+ "committer_email": "dzaporozhets@sphereconsultinginc.com",
"created_at": "2016-09-20T09:26:24.000-07:00",
"message": "some commit message",
"parent_ids": [
@@ -159,6 +165,8 @@ Example response:
"title": "Sanitize for network graph",
"author_name": "randx",
"author_email": "dmitriy.zaporozhets@gmail.com",
+ "committer_name": "Dmitriy",
+ "committer_email": "dmitriy.zaporozhets@gmail.com",
"created_at": "2012-09-20T09:06:12+03:00",
"message": "Sanitize for network graph",
"committed_date": "2012-09-20T09:06:12+03:00",
diff --git a/doc/api/issues.md b/doc/api/issues.md
index 16f8e32c82a..119125bcd3d 100644
--- a/doc/api/issues.md
+++ b/doc/api/issues.md
@@ -330,6 +330,7 @@ POST /projects/:id/issues
| `labels` | string | no | Comma-separated label names for an issue |
| `created_at` | string | no | Date time string, ISO 8601 formatted, e.g. `2016-03-11T03:45:40Z` (requires admin or project owner rights) |
| `due_date` | string | no | Date time string in the format YEAR-MONTH-DAY, e.g. `2016-03-11` |
+| `merge_request_for_resolving_discussions` | integer | no | The IID of a merge request in which to resolve all issues. This will fill the issue with a default description and mark all discussions as resolved. When passing a description or title, these values will take precedence over the default values. |
```bash
curl --request POST --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" https://gitlab.example.com/api/v3/projects/4/issues?title=Issues%20with%20auth&labels=bug
@@ -506,7 +507,7 @@ Example response:
## Subscribe to an issue
-Subscribes the authenticated user to an issue to receive notifications.
+Subscribes the authenticated user to an issue to receive notifications.
If the user is already subscribed to the issue, the status code `304`
is returned.
diff --git a/doc/api/merge_requests.md b/doc/api/merge_requests.md
index 12d24543bbe..9460b3f73b1 100644
--- a/doc/api/merge_requests.md
+++ b/doc/api/merge_requests.md
@@ -510,7 +510,7 @@ Parameters:
}
```
-## Cancel Merge When Build Succeeds
+## Cancel Merge When Pipeline Succeeds
If you don't have permissions to accept this merge request - you'll get a `401`
diff --git a/doc/api/projects.md b/doc/api/projects.md
index 132be644b59..0bc2a5210aa 100644
--- a/doc/api/projects.md
+++ b/doc/api/projects.md
@@ -347,7 +347,8 @@ Parameters:
### Get single project
Get a specific project, identified by project ID or NAMESPACE/PROJECT_NAME, which is owned by the authenticated user.
-If using namespaced projects call make sure that the NAMESPACE/PROJECT_NAME is URL-encoded, eg. `/api/v3/projects/diaspora%2Fdiaspora` (where `/` is represented by `%2F`).
+If using namespaced projects call make sure that the NAMESPACE/PROJECT_NAME is URL-encoded, eg. `/api/v3/projects/diaspora%2Fdiaspora` (where `/` is represented by `%2F`). This endpoint can be accessed without authentication if
+the project is publicly accessible.
```
GET /projects/:id
@@ -436,10 +437,47 @@ Parameters:
}
```
+## Get project users
+
+Get the users list of a project.
+
+
+Parameters:
+
+| Attribute | Type | Required | Description |
+| --------- | ---- | -------- | ----------- |
+| `search` | string | no | Search for specific users |
+
+```
+GET /projects/:id/users
+```
+
+```json
+[
+ {
+ "id": 1,
+ "username": "john_smith",
+ "name": "John Smith",
+ "state": "active",
+ "avatar_url": "http://localhost:3000/uploads/user/avatar/1/cd8.jpeg",
+ "web_url": "http://localhost:3000/john_smith"
+ },
+ {
+ "id": 2,
+ "username": "jack_smith",
+ "name": "Jack Smith",
+ "state": "blocked",
+ "avatar_url": "http://gravatar.com/../e32131cd8.jpeg",
+ "web_url": "http://localhost:3000/jack_smith"
+ }
+]
+```
+
### Get project events
-Get the events for the specified project.
-Sorted from newest to oldest
+Get the events for the specified project sorted from newest to oldest. This
+endpoint can be accessed without authentication if the project is publicly
+accessible.
```
GET /projects/:id/events
@@ -1344,7 +1382,9 @@ Parameter:
## Search for projects by name
-Search for projects by name which are accessible to the authenticated user.
+Search for projects by name which are accessible to the authenticated user. This
+endpoint can be accessed without authentication if the project is publicly
+accessible.
```
GET /projects/search/:query
diff --git a/doc/ci/README.md b/doc/ci/README.md
index db236ce2a66..73bd2516d46 100644
--- a/doc/ci/README.md
+++ b/doc/ci/README.md
@@ -11,7 +11,8 @@
- [Configure a Runner, the application that runs your builds](runners/README.md)
- [Use Docker images with GitLab Runner](docker/using_docker_images.md)
- [Use CI to build Docker images](docker/using_docker_build.md)
-- [Use variables in your `.gitlab-ci.yml`](variables/README.md)
+- [CI Variables](variables/README.md) - Learn how to use variables defined in
+ your `.gitlab-ci.yml` or secured ones defined in your project's settings
- [Use SSH keys in your build environment](ssh_keys/README.md)
- [Trigger builds through the API](triggers/README.md)
- [Build artifacts](../user/project/builds/artifacts.md)
@@ -25,4 +26,6 @@
## Breaking changes
-- [New CI build permissions model](../user/project/new_ci_build_permissions_model.md) Read about what changed in GitLab 8.12 and how that affects your builds. There's a new way to access your Git submodules and LFS objects in builds.
+- [New CI build permissions model](../user/project/new_ci_build_permissions_model.md)
+ Read about what changed in GitLab 8.12 and how that affects your builds.
+ There's a new way to access your Git submodules and LFS objects in builds.
diff --git a/doc/ci/examples/php.md b/doc/ci/examples/php.md
index 175e9d79904..82ffb841729 100644
--- a/doc/ci/examples/php.md
+++ b/doc/ci/examples/php.md
@@ -40,7 +40,7 @@ repository with the following content:
#!/bin/bash
# We need to install dependencies only for Docker
-[[ ! -e /.dockerenv ]] && [[ ! -e /.dockerinit ]] && exit 0
+[[ ! -e /.dockerenv ]] && exit 0
set -xe
diff --git a/doc/ci/variables/README.md b/doc/ci/variables/README.md
index a4c3a731a20..d142fe266a2 100644
--- a/doc/ci/variables/README.md
+++ b/doc/ci/variables/README.md
@@ -1,22 +1,30 @@
-## Variables
+# Variables
-When receiving a build from GitLab CI, the runner prepares the build environment.
-It starts by setting a list of **predefined variables** (Environment Variables) and a list of **user-defined variables**
+When receiving a build from GitLab CI, the [Runner] prepares the build environment.
+It starts by setting a list of **predefined variables** (environment variables)
+and a list of **user-defined variables**.
-The variables can be overwritten. They take precedence over each other in this order:
-1. Trigger variables
-1. Secure variables
-1. YAML-defined job-level variables
-1. YAML-defined global variables
-1. Predefined variables
+## Priority of variables
-For example, if you define:
-1. `API_TOKEN=SECURE` as Secure Variable
-1. `API_TOKEN=YAML` as YAML-defined variable
+The variables can be overwritten and they take precedence over each other in
+this order:
-The `API_TOKEN` will take the Secure Variable value: `SECURE`.
+1. [Trigger variables][triggers] (take precedence over all)
+1. [Secret variables](#secret-variables)
+1. YAML-defined [job-level variables](../yaml/README.md#job-variables)
+1. YAML-defined [global variables](../yaml/README.md#variables)
+1. [Predefined variables](#predefined-variables-environment-variables) (are the
+ lowest in the chain)
-### Predefined variables (Environment Variables)
+For example, if you define `API_TOKEN=secure` as a secret variable and
+`API_TOKEN=yaml` in your `.gitlab-ci.yml`, the `API_TOKEN` will take the value
+`secure` as the secret variables are higher in the chain.
+
+## Predefined variables (Environment variables)
+
+Some of the predefined environment variables are available only if a minimum
+version of [GitLab Runner][runner] is used. Consult the table below to find the
+version of Runner required.
| Variable | GitLab | Runner | Description |
|-------------------------|--------|--------|-------------|
@@ -52,7 +60,6 @@ The `API_TOKEN` will take the Secure Variable value: `SECURE`.
| **GITLAB_USER_ID** | 8.12 | all | The id of the user who started the build |
| **GITLAB_USER_EMAIL** | 8.12 | all | The email of the user who started the build |
-**Some of the variables are only available when using runner with at least defined version.**
Example values:
@@ -60,7 +67,7 @@ Example values:
export CI_BUILD_ID="50"
export CI_BUILD_REF="1ecfd275763eff1d6b4844ea3168962458c9f27a"
export CI_BUILD_REF_NAME="master"
-export CI_BUILD_REPO="https://gitab-ci-token:abcde-1234ABCD5678ef@gitlab.com/gitlab-org/gitlab-ce.git"
+export CI_BUILD_REPO="https://gitab-ci-token:abcde-1234ABCD5678ef@example.com/gitlab-org/gitlab-ce.git"
export CI_BUILD_TAG="1.0.0"
export CI_BUILD_NAME="spec:other"
export CI_BUILD_STAGE="test"
@@ -73,9 +80,9 @@ export CI_PROJECT_DIR="/builds/gitlab-org/gitlab-ce"
export CI_PROJECT_NAME="gitlab-ce"
export CI_PROJECT_NAMESPACE="gitlab-org"
export CI_PROJECT_PATH="gitlab-org/gitlab-ce"
-export CI_PROJECT_URL="https://gitlab.com/gitlab-org/gitlab-ce"
-export CI_REGISTRY="registry.gitlab.com"
-export CI_REGISTRY_IMAGE="registry.gitlab.com/gitlab-org/gitlab-ce"
+export CI_PROJECT_URL="https://example.com/gitlab-org/gitlab-ce"
+export CI_REGISTRY="registry.example.com"
+export CI_REGISTRY_IMAGE="registry.example.com/gitlab-org/gitlab-ce"
export CI_RUNNER_ID="10"
export CI_RUNNER_DESCRIPTION="my runner"
export CI_RUNNER_TAGS="docker, linux"
@@ -84,32 +91,66 @@ export CI_SERVER_NAME="GitLab"
export CI_SERVER_REVISION="70606bf"
export CI_SERVER_VERSION="8.9.0"
export GITLAB_USER_ID="42"
-export GITLAB_USER_EMAIL="alexzander@sporer.com"
+export GITLAB_USER_EMAIL="user@example.com"
```
-### YAML-defined variables
-**This feature requires GitLab Runner 0.5.0 or higher and GitLab CI 7.14 or higher **
+## `.gitlab-ci.yaml` defined variables
+
+>**Note:**
+This feature requires GitLab Runner 0.5.0 or higher and GitLab CI 7.14 or higher.
+
+GitLab CI allows you to add to `.gitlab-ci.yml` variables that are set in the
+build environment. The variables are hence saved in the repository, and they
+are meant to store non-sensitive project configuration, e.g., `RAILS_ENV` or
+`DATABASE_URL`.
-GitLab CI allows you to add to `.gitlab-ci.yml` variables that are set in build environment.
-The variables are stored in repository and are meant to store non-sensitive project configuration, ie. RAILS_ENV or DATABASE_URL.
+For example, if you set the variable below globally (not inside a job), it will
+be used in all executed commands and scripts:
```yaml
variables:
DATABASE_URL: "postgres://postgres@postgres/my_database"
```
-These variables can be later used in all executed commands and scripts.
+The YAML-defined variables are also set to all created
+[service containers](../docker/using_docker_images.md), thus allowing to fine
+tune them.
+
+Variables can be defined at a global level, but also at a job level. To turn off
+global defined variables in your job, define an empty array:
+
+```yaml
+job_name:
+ variables: []
+```
+
+## Secret variables
-The YAML-defined variables are also set to all created service containers, thus allowing to fine tune them.
+>**Notes:**
+- This feature requires GitLab Runner 0.4.0 or higher.
+- Be aware that secret variables are not masked, and their values can be shown
+ in the build logs if explicitly asked to do so. If your project is public or
+ internal, you can set the pipelines private from your project's Pipelines
+ settings. Follow the discussion in issue [#13784][ce-13784] for masking the
+ secret variables.
-Variables can be defined at a global level, but also at a job level.
+GitLab CI allows you to define per-project **secret variables** that are set in
+the build environment. The secret variables are stored out of the repository
+(`.gitlab-ci.yml`) and are securely passed to GitLab Runner making them
+available in the build environment. It's the recommended method to use for
+storing things like passwords, secret keys and credentials.
-More information about Docker integration can be found in [Using Docker Images](../docker/using_docker_images.md).
+Secret variables can be added by going to your project's
+**Settings âž” Variables âž” Add variable**.
-#### Debug tracing
+Once you set them, they will be available for all subsequent builds.
+## Debug tracing
+
+> Introduced in GitLab Runner 1.7.
+>
> **WARNING:** Enabling debug tracing can have severe security implications. The
- output **will** contain the content of all your secure variables and any other
+ output **will** contain the content of all your secret variables and any other
secrets! The output **will** be uploaded to the GitLab server and made visible
in build traces!
@@ -124,55 +165,162 @@ trace, resulting in a verbose build trace listing all commands that were run,
variables that were set, etc.
Before enabling this, you should ensure builds are visible to
-[team members only](../../../user/permissions.md#project-features). You should
-also [erase](../pipelines.md#seeing-build-traces) all generated build traces
+[team members only](../../user/permissions.md#project-features). You should
+also [erase](../pipelines.md#seeing-build-status) all generated build traces
before making them visible again.
To enable debug traces, set the `CI_DEBUG_TRACE` variable to `true`:
```yaml
-job1:
+job_name:
variables:
CI_DEBUG_TRACE: "true"
```
-The [example project](https://gitlab.com/gitlab-examples/ci-debug-trace)
-demonstrates a working configuration, including build trace examples.
+Example truncated output with debug trace set to true:
-### User-defined variables (Secure Variables)
-**This feature requires GitLab Runner 0.4.0 or higher**
-
-GitLab CI allows you to define per-project **Secure Variables** that are set in
-the build environment.
-The secure variables are stored out of the repository (the `.gitlab-ci.yml`).
-The variables are securely passed to GitLab Runner and are available in the
-build environment.
-It's desired method to use them for storing passwords, secret keys or whatever
-you want.
+```bash
+...
+
+export CI_SERVER_TLS_CA_FILE="/builds/gitlab-examples/ci-debug-trace.tmp/CI_SERVER_TLS_CA_FILE"
+if [[ -d "/builds/gitlab-examples/ci-debug-trace/.git" ]]; then
+ echo $'\''\x1b[32;1mFetching changes...\x1b[0;m'\''
+ $'\''cd'\'' "/builds/gitlab-examples/ci-debug-trace"
+ $'\''git'\'' "config" "fetch.recurseSubmodules" "false"
+ $'\''rm'\'' "-f" ".git/index.lock"
+ $'\''git'\'' "clean" "-ffdx"
+ $'\''git'\'' "reset" "--hard"
+ $'\''git'\'' "remote" "set-url" "origin" "https://gitlab-ci-token:xxxxxxxxxxxxxxxxxxxx@example.com/gitlab-examples/ci-debug-trace.git"
+ $'\''git'\'' "fetch" "origin" "--prune" "+refs/heads/*:refs/remotes/origin/*" "+refs/tags/*:refs/tags/*"
+else
+ $'\''mkdir'\'' "-p" "/builds/gitlab-examples/ci-debug-trace.tmp/git-template"
+ $'\''rm'\'' "-r" "-f" "/builds/gitlab-examples/ci-debug-trace"
+ $'\''git'\'' "config" "-f" "/builds/gitlab-examples/ci-debug-trace.tmp/git-template/config" "fetch.recurseSubmodules" "false"
+ echo $'\''\x1b[32;1mCloning repository...\x1b[0;m'\''
+ $'\''git'\'' "clone" "--no-checkout" "https://gitlab-ci-token:xxxxxxxxxxxxxxxxxxxx@example.com/gitlab-examples/ci-debug-trace.git" "/builds/gitlab-examples/ci-debug-trace" "--template" "/builds/gitlab-examples/ci-debug-trace.tmp/git-template"
+ $'\''cd'\'' "/builds/gitlab-examples/ci-debug-trace"
+fi
+echo $'\''\x1b[32;1mChecking out dd648b2e as master...\x1b[0;m'\''
+$'\''git'\'' "checkout" "-f" "-q" "dd648b2e48ce6518303b0bb580b2ee32fadaf045"
+'
++++ hostname
+++ echo 'Running on runner-8a2f473d-project-1796893-concurrent-0 via runner-8a2f473d-machine-1480971377-317a7d0f-digital-ocean-4gb...'
+Running on runner-8a2f473d-project-1796893-concurrent-0 via runner-8a2f473d-machine-1480971377-317a7d0f-digital-ocean-4gb...
+++ export CI=true
+++ CI=true
+++ export CI_DEBUG_TRACE=false
+++ CI_DEBUG_TRACE=false
+++ export CI_BUILD_REF=dd648b2e48ce6518303b0bb580b2ee32fadaf045
+++ CI_BUILD_REF=dd648b2e48ce6518303b0bb580b2ee32fadaf045
+++ export CI_BUILD_BEFORE_SHA=dd648b2e48ce6518303b0bb580b2ee32fadaf045
+++ CI_BUILD_BEFORE_SHA=dd648b2e48ce6518303b0bb580b2ee32fadaf045
+++ export CI_BUILD_REF_NAME=master
+++ CI_BUILD_REF_NAME=master
+++ export CI_BUILD_ID=7046507
+++ CI_BUILD_ID=7046507
+++ export CI_BUILD_REPO=https://gitlab-ci-token:xxxxxxxxxxxxxxxxxxxx@example.com/gitlab-examples/ci-debug-trace.git
+++ CI_BUILD_REPO=https://gitlab-ci-token:xxxxxxxxxxxxxxxxxxxx@example.com/gitlab-examples/ci-debug-trace.git
+++ export CI_BUILD_TOKEN=xxxxxxxxxxxxxxxxxxxx
+++ CI_BUILD_TOKEN=xxxxxxxxxxxxxxxxxxxx
+++ export CI_PROJECT_ID=1796893
+++ CI_PROJECT_ID=1796893
+++ export CI_PROJECT_DIR=/builds/gitlab-examples/ci-debug-trace
+++ CI_PROJECT_DIR=/builds/gitlab-examples/ci-debug-trace
+++ export CI_SERVER=yes
+++ CI_SERVER=yes
+++ export 'CI_SERVER_NAME=GitLab CI'
+++ CI_SERVER_NAME='GitLab CI'
+++ export CI_SERVER_VERSION=
+++ CI_SERVER_VERSION=
+++ export CI_SERVER_REVISION=
+++ CI_SERVER_REVISION=
+++ export GITLAB_CI=true
+++ GITLAB_CI=true
+++ export CI=true
+++ CI=true
+++ export GITLAB_CI=true
+++ GITLAB_CI=true
+++ export CI_BUILD_ID=7046507
+++ CI_BUILD_ID=7046507
+++ export CI_BUILD_TOKEN=xxxxxxxxxxxxxxxxxxxx
+++ CI_BUILD_TOKEN=xxxxxxxxxxxxxxxxxxxx
+++ export CI_BUILD_REF=dd648b2e48ce6518303b0bb580b2ee32fadaf045
+++ CI_BUILD_REF=dd648b2e48ce6518303b0bb580b2ee32fadaf045
+++ export CI_BUILD_BEFORE_SHA=dd648b2e48ce6518303b0bb580b2ee32fadaf045
+++ CI_BUILD_BEFORE_SHA=dd648b2e48ce6518303b0bb580b2ee32fadaf045
+++ export CI_BUILD_REF_NAME=master
+++ CI_BUILD_REF_NAME=master
+++ export CI_BUILD_NAME=debug_trace
+++ CI_BUILD_NAME=debug_trace
+++ export CI_BUILD_STAGE=test
+++ CI_BUILD_STAGE=test
+++ export CI_SERVER_NAME=GitLab
+++ CI_SERVER_NAME=GitLab
+++ export CI_SERVER_VERSION=8.14.3-ee
+++ CI_SERVER_VERSION=8.14.3-ee
+++ export CI_SERVER_REVISION=82823
+++ CI_SERVER_REVISION=82823
+++ export CI_PROJECT_ID=17893
+++ CI_PROJECT_ID=17893
+++ export CI_PROJECT_NAME=ci-debug-trace
+++ CI_PROJECT_NAME=ci-debug-trace
+++ export CI_PROJECT_PATH=gitlab-examples/ci-debug-trace
+++ CI_PROJECT_PATH=gitlab-examples/ci-debug-trace
+++ export CI_PROJECT_NAMESPACE=gitlab-examples
+++ CI_PROJECT_NAMESPACE=gitlab-examples
+++ export CI_PROJECT_URL=https://example.com/gitlab-examples/ci-debug-trace
+++ CI_PROJECT_URL=https://example.com/gitlab-examples/ci-debug-trace
+++ export CI_PIPELINE_ID=52666
+++ CI_PIPELINE_ID=52666
+++ export CI_RUNNER_ID=1337
+++ CI_RUNNER_ID=1337
+++ export CI_RUNNER_DESCRIPTION=shared-runners-manager-1.example.com
+++ CI_RUNNER_DESCRIPTION=shared-runners-manager-1.example.com
+++ export 'CI_RUNNER_TAGS=shared, docker, linux, ruby, mysql, postgres, mongo, git-annex'
+++ CI_RUNNER_TAGS='shared, docker, linux, ruby, mysql, postgres, mongo, git-annex'
+++ export CI_REGISTRY=registry.example.com
+++ CI_REGISTRY=registry.example.com
+++ export CI_DEBUG_TRACE=true
+++ CI_DEBUG_TRACE=true
+++ export GITLAB_USER_ID=42
+++ GITLAB_USER_ID=42
+++ export GITLAB_USER_EMAIL=user@example.com
+++ GITLAB_USER_EMAIL=axilleas@axilleas.me
+++ export VERY_SECURE_VARIABLE=imaverysecurevariable
+++ VERY_SECURE_VARIABLE=imaverysecurevariable
+++ mkdir -p /builds/gitlab-examples/ci-debug-trace.tmp
+++ echo -n '-----BEGIN CERTIFICATE-----
+MIIFQzCCBCugAwIBAgIRAL/ElDjuf15xwja1ZnCocWAwDQYJKoZIhvcNAQELBQAw'
+
+...
+```
-**The value of the variable can be shown in build log if explicitly asked to do so.**
-If your project is public or internal you can make the builds private.
+## Using the CI variables in your job scripts
-Secure Variables can added by going to `Project > Variables > Add Variable`.
+All variables are set as environment variables in the build environment, and
+they are accessible with normal methods that are used to access such variables.
+In most cases `bash` or `sh` is used to execute the build script.
-They will be available for all subsequent builds.
+To access the variables (predefined and user-defined) in a `bash`/`sh` environment,
+prefix the variable name with the dollar sign (`$`):
-### Use variables
-The variables are set as environment variables in build environment and are accessible with normal methods that are used to access such variables.
-In most cases the **bash** is used to execute build script.
-To access variables (predefined and user-defined) in bash environment, prefix the variable name with `$`:
```
job_name:
script:
- echo $CI_BUILD_ID
```
-You can also list all environment variables with `export` command,
-but be aware that this will also expose value of all **Secure Variables** in build log:
+You can also list all environment variables with the `export` command,
+but be aware that this will also expose the values of all the secret variables
+you set, in the build log:
+
```
job_name:
script:
- export
```
+[ce-13784]: https://gitlab.com/gitlab-org/gitlab-ce/issues/13784
+[runner]: https://docs.gitlab.com/runner/
[triggered]: ../triggers/README.md
+[triggers]: ../triggers/README.md#pass-build-variables-to-a-trigger
diff --git a/doc/ci/yaml/README.md b/doc/ci/yaml/README.md
index 338c9a27789..5f88974d360 100644
--- a/doc/ci/yaml/README.md
+++ b/doc/ci/yaml/README.md
@@ -406,14 +406,20 @@ except master.
### job variables
It is possible to define build variables using a `variables` keyword on a job
-level. It works basically the same way as its global-level equivalent but
-allows you to define job-specific build variables.
+level. It works basically the same way as its [global-level equivalent](#variables)
+but allows you to define job-specific build variables.
When the `variables` keyword is used on a job level, it overrides global YAML
-build variables and predefined variables.
+build variables and predefined variables. To turn off global defined variables
+in your job, define an empty array:
-Build variables priority is defined in
-[variables documentation](../variables/README.md).
+```yaml
+job_name:
+ variables: []
+```
+
+Build variables priority is defined in the
+[variables documentation][variables].
### tags
diff --git a/doc/development/code_review.md b/doc/development/code_review.md
index e1fb8102b67..1ef34c79971 100644
--- a/doc/development/code_review.md
+++ b/doc/development/code_review.md
@@ -70,8 +70,8 @@ experience, refactors the existing code). Then:
- After a round of line notes, it can be helpful to post a summary note such as
"LGTM :thumbsup:", or "Just a couple things to address."
- Avoid accepting a merge request before the build succeeds. Of course, "Merge
- When Build Succeeds" (MWBS) is fine.
-- If you set the MR to "Merge When Build Succeeds", you should take over
+ When Pipeline Succeeds" (MWPS) is fine.
+- If you set the MR to "Merge When Pipeline Succeeds", you should take over
subsequent revisions for anything that would be spotted after that.
## The right balance
diff --git a/doc/development/ux_guide/basics.md b/doc/development/ux_guide/basics.md
index 62ac56a6bce..a29cfa096b2 100644
--- a/doc/development/ux_guide/basics.md
+++ b/doc/development/ux_guide/basics.md
@@ -35,26 +35,15 @@ This is the typeface used for code blocks. GitLab uses the OS default font.
## Icons
GitLab uses Font Awesome icons throughout our interface.
-![Trash icon](img/icon-trash.png)
-The trash icon is used for destructive actions that deletes information.
-
-![Edit icon](img/icon-edit.png)
-The pencil icon is used for editing content such as comments.
-
-![Notification icon](img/icon-notification.png)
-The bell icon is for notifications, such as Todos.
-
-![Subscribe icon](img/icon-subscribe.png)
-The eye icon is for subscribing to updates. For example, you can subscribe to a label and get updated on issues with that label.
-
-![RSS icon](img/icon-rss.png)
-The standard RSS icon is used for linking to RSS/atom feeds.
-
-![Close icon](img/icon-close.png)
-An 'x' is used for closing UI elements such as dropdowns.
-
-![Add icon](img/icon-add.png)
-A plus is used when creating new objects, such as issues, projects, etc.
+| | |
+| :-----------: | :---- |
+| ![Trash icon](img/icon-trash.png) | The trash icon is used for destructive actions that deletes information. |
+| ![Edit icon](img/icon-edit.png) | The pencil icon is used for editing content such as comments.|
+| ![Notification icon](img/icon-notification.png) | The bell icon is for notifications, such as Todos. |
+| ![Subscribe icon](img/icon-subscribe.png) | The eye icon is for subscribing to updates. For example, you can subscribe to a label and get updated on issues with that label. |
+| ![RSS icon](img/icon-rss.png) | The standard RSS icon is used for linking to RSS/atom feeds. |
+| ![Close icon](img/icon-close.png) | An 'x' is used for closing UI elements such as dropdowns. |
+| ![Add icon](img/icon-add.png) | A plus is used when creating new objects, such as issues, projects, etc. |
> TODO: update this section, add more general guidance to icon usage and personality, etc.
@@ -62,20 +51,13 @@ A plus is used when creating new objects, such as issues, projects, etc.
## Color
-![Blue](img/color-blue.png)
-Blue is used to highlight primary active elements (such as current tab), as well as other organization and managing commands.
-
-![Green](img/color-green.png)
-Green is for actions that create new objects.
-
-![Orange](img/color-orange.png)
-Orange is used for warnings
-
-![Red](img/color-red.png)
-Red is reserved for delete and other destructive commands
-
-![Grey](img/color-grey.png)
-Grey, and white (depending on context) is used for netral, secondary elements
+| | |
+| :------: | :------- |
+| ![Blue](img/color-blue.png) | Blue is used to highlight primary active elements (such as the current tab), as well as other organizational and managing commands.|
+| ![Green](img/color-green.png) | Green is for actions that create new objects. |
+| ![Orange](img/color-orange.png) | Orange is used for warnings |
+| ![Red](img/color-red.png) | Red is reserved for delete and other destructive commands |
+| ![Grey](img/color-grey.png) | Grey is used for neutral secondary elements. Depending on context, white is sometimes used instead. |
> TODO: Establish a perspective for color in terms of our personality and rationalize with Marketing usage.
diff --git a/doc/development/ux_guide/components.md b/doc/development/ux_guide/components.md
index 8e51edd23ef..28383ad7dfc 100644
--- a/doc/development/ux_guide/components.md
+++ b/doc/development/ux_guide/components.md
@@ -75,10 +75,29 @@ Text should be in sentence case, where only the first word is capitalized. "Crea
> TODO: Rationalize this. Ensure that we still believe this.
### Colors
-Follow the color guidance on the [basics](basics.md#color) page. The default color treatment is the white/grey button.
+The default color treatment is the white/grey button. Follow the guidance on the [basics](basics.md#color) page to add meaningful color to a button.
+
+### Secondary states
+
+Primary buttons darken the color of their background and border for hover, focus and active states. An inner shadow is added to the active state to denote the button being pressed.
+
+| Values | Info | Success | Warning | Danger |
+| :------ | :------: | :------: | :------: | :------: |
+| Background: `$color-light` <br> Border: `$border-color-light` | ![](img/button-info--resting.png) | ![](img/button-success--resting.png) | ![](img/button-warning--resting.png) | ![](img/button-danger--resting.png) |
+| Background: `$color-normal` <br> Border: `$border-color-normal` | ![](img/button-info--hover.png) | ![](img/button-success--hover.png) | ![](img/button-warning--hover.png) | ![](img/button-danger--hover.png) |
+| Background: `$color-dark` <br> Border: `$border-color-dark` | ![](img/button-info--active.png) | ![](img/button-success--active.png) | ![](img/button-warning--active.png) | ![](img/button-danger--active.png) |
+
+Since secondary buttons only have a border on their resting state, their hover and focus states add a background color, which gets darkened on active.
+
+| Values | Success Secondary | Close | Spam |
+| :------ | :------: | :------: | :------: |
+| Font: `$border-color-light` <br> Border: `$border-color-light` | ![](img/button-success-secondary--resting.png) | ![](img/button-close--resting.png) | ![](img/button-spam--resting.png) |
+| Background: `$color-light` <br> Border: `$border-color-light` | ![](img/button-success-secondary--hover.png) | ![](img/button-close--hover.png) | ![](img/button-spam--hover.png) |
+| Background: `$color-normal` <br> Border: `$border-color-normal` | ![](img/button-success-secondary--active.png) | ![](img/button-close--active.png) | ![](img/button-spam--active.png) |
---
+
## Dropdowns
Dropdowns are used to allow users to choose one (or many) options from a list of options. If this list of options is more 20, there should generally be a way to search through and filter the options (see the complex filter dropdowns below.)
diff --git a/doc/development/ux_guide/img/button-close--active.png b/doc/development/ux_guide/img/button-close--active.png
new file mode 100644
index 00000000000..824bfc8f31b
--- /dev/null
+++ b/doc/development/ux_guide/img/button-close--active.png
Binary files differ
diff --git a/doc/development/ux_guide/img/button-close--hover.png b/doc/development/ux_guide/img/button-close--hover.png
new file mode 100644
index 00000000000..0291e121894
--- /dev/null
+++ b/doc/development/ux_guide/img/button-close--hover.png
Binary files differ
diff --git a/doc/development/ux_guide/img/button-close--resting.png b/doc/development/ux_guide/img/button-close--resting.png
new file mode 100644
index 00000000000..986d7174ce7
--- /dev/null
+++ b/doc/development/ux_guide/img/button-close--resting.png
Binary files differ
diff --git a/doc/development/ux_guide/img/button-danger--active.png b/doc/development/ux_guide/img/button-danger--active.png
new file mode 100644
index 00000000000..d3c64424b26
--- /dev/null
+++ b/doc/development/ux_guide/img/button-danger--active.png
Binary files differ
diff --git a/doc/development/ux_guide/img/button-danger--hover.png b/doc/development/ux_guide/img/button-danger--hover.png
new file mode 100644
index 00000000000..8506e093306
--- /dev/null
+++ b/doc/development/ux_guide/img/button-danger--hover.png
Binary files differ
diff --git a/doc/development/ux_guide/img/button-danger--resting.png b/doc/development/ux_guide/img/button-danger--resting.png
new file mode 100644
index 00000000000..69ad6bb796b
--- /dev/null
+++ b/doc/development/ux_guide/img/button-danger--resting.png
Binary files differ
diff --git a/doc/development/ux_guide/img/button-info--active.png b/doc/development/ux_guide/img/button-info--active.png
new file mode 100644
index 00000000000..23be20b225c
--- /dev/null
+++ b/doc/development/ux_guide/img/button-info--active.png
Binary files differ
diff --git a/doc/development/ux_guide/img/button-info--hover.png b/doc/development/ux_guide/img/button-info--hover.png
new file mode 100644
index 00000000000..4cb4e38558c
--- /dev/null
+++ b/doc/development/ux_guide/img/button-info--hover.png
Binary files differ
diff --git a/doc/development/ux_guide/img/button-info--resting.png b/doc/development/ux_guide/img/button-info--resting.png
new file mode 100644
index 00000000000..5883340aa83
--- /dev/null
+++ b/doc/development/ux_guide/img/button-info--resting.png
Binary files differ
diff --git a/doc/development/ux_guide/img/button-spam--active.png b/doc/development/ux_guide/img/button-spam--active.png
new file mode 100644
index 00000000000..55b44898684
--- /dev/null
+++ b/doc/development/ux_guide/img/button-spam--active.png
Binary files differ
diff --git a/doc/development/ux_guide/img/button-spam--hover.png b/doc/development/ux_guide/img/button-spam--hover.png
new file mode 100644
index 00000000000..3dc8ed34c54
--- /dev/null
+++ b/doc/development/ux_guide/img/button-spam--hover.png
Binary files differ
diff --git a/doc/development/ux_guide/img/button-spam--resting.png b/doc/development/ux_guide/img/button-spam--resting.png
new file mode 100644
index 00000000000..b6bf10a5b64
--- /dev/null
+++ b/doc/development/ux_guide/img/button-spam--resting.png
Binary files differ
diff --git a/doc/development/ux_guide/img/button-success--active.png b/doc/development/ux_guide/img/button-success--active.png
new file mode 100644
index 00000000000..895a52831cb
--- /dev/null
+++ b/doc/development/ux_guide/img/button-success--active.png
Binary files differ
diff --git a/doc/development/ux_guide/img/button-success--hover.png b/doc/development/ux_guide/img/button-success--hover.png
new file mode 100644
index 00000000000..e4c74bd9778
--- /dev/null
+++ b/doc/development/ux_guide/img/button-success--hover.png
Binary files differ
diff --git a/doc/development/ux_guide/img/button-success--resting.png b/doc/development/ux_guide/img/button-success--resting.png
new file mode 100644
index 00000000000..2fa971b5347
--- /dev/null
+++ b/doc/development/ux_guide/img/button-success--resting.png
Binary files differ
diff --git a/doc/development/ux_guide/img/button-success-secondary--active.png b/doc/development/ux_guide/img/button-success-secondary--active.png
new file mode 100644
index 00000000000..e7383b36946
--- /dev/null
+++ b/doc/development/ux_guide/img/button-success-secondary--active.png
Binary files differ
diff --git a/doc/development/ux_guide/img/button-success-secondary--hover.png b/doc/development/ux_guide/img/button-success-secondary--hover.png
new file mode 100644
index 00000000000..4af2a68cf1b
--- /dev/null
+++ b/doc/development/ux_guide/img/button-success-secondary--hover.png
Binary files differ
diff --git a/doc/development/ux_guide/img/button-success-secondary--resting.png b/doc/development/ux_guide/img/button-success-secondary--resting.png
new file mode 100644
index 00000000000..a5a4ec512c8
--- /dev/null
+++ b/doc/development/ux_guide/img/button-success-secondary--resting.png
Binary files differ
diff --git a/doc/development/ux_guide/img/button-warning--active.png b/doc/development/ux_guide/img/button-warning--active.png
new file mode 100644
index 00000000000..5877d46c94d
--- /dev/null
+++ b/doc/development/ux_guide/img/button-warning--active.png
Binary files differ
diff --git a/doc/development/ux_guide/img/button-warning--hover.png b/doc/development/ux_guide/img/button-warning--hover.png
new file mode 100644
index 00000000000..308e1adc8a3
--- /dev/null
+++ b/doc/development/ux_guide/img/button-warning--hover.png
Binary files differ
diff --git a/doc/development/ux_guide/img/button-warning--resting.png b/doc/development/ux_guide/img/button-warning--resting.png
new file mode 100644
index 00000000000..28e5e601520
--- /dev/null
+++ b/doc/development/ux_guide/img/button-warning--resting.png
Binary files differ
diff --git a/doc/development/ux_guide/img/color-blue.png b/doc/development/ux_guide/img/color-blue.png
index 2ca360173eb..844e926f1f5 100644
--- a/doc/development/ux_guide/img/color-blue.png
+++ b/doc/development/ux_guide/img/color-blue.png
Binary files differ
diff --git a/doc/development/ux_guide/img/color-green.png b/doc/development/ux_guide/img/color-green.png
index 489db8f4343..5c4c23c7067 100644
--- a/doc/development/ux_guide/img/color-green.png
+++ b/doc/development/ux_guide/img/color-green.png
Binary files differ
diff --git a/doc/development/ux_guide/img/color-grey.png b/doc/development/ux_guide/img/color-grey.png
index 58c474d5ce9..5247649a0ce 100644
--- a/doc/development/ux_guide/img/color-grey.png
+++ b/doc/development/ux_guide/img/color-grey.png
Binary files differ
diff --git a/doc/development/ux_guide/img/color-orange.png b/doc/development/ux_guide/img/color-orange.png
index 4c4b772d438..1103c715225 100644
--- a/doc/development/ux_guide/img/color-orange.png
+++ b/doc/development/ux_guide/img/color-orange.png
Binary files differ
diff --git a/doc/development/ux_guide/img/color-red.png b/doc/development/ux_guide/img/color-red.png
index 3440ad48f05..77ecbbc0a20 100644
--- a/doc/development/ux_guide/img/color-red.png
+++ b/doc/development/ux_guide/img/color-red.png
Binary files differ
diff --git a/doc/development/ux_guide/img/icon-add.png b/doc/development/ux_guide/img/icon-add.png
index 0d4c1a7692a..bcad5e84591 100644
--- a/doc/development/ux_guide/img/icon-add.png
+++ b/doc/development/ux_guide/img/icon-add.png
Binary files differ
diff --git a/doc/development/ux_guide/img/icon-close.png b/doc/development/ux_guide/img/icon-close.png
index 88d2b3b0c6d..dfe1495f5fa 100644
--- a/doc/development/ux_guide/img/icon-close.png
+++ b/doc/development/ux_guide/img/icon-close.png
Binary files differ
diff --git a/doc/development/ux_guide/img/icon-edit.png b/doc/development/ux_guide/img/icon-edit.png
index f73be7a10fb..50f6f841868 100644
--- a/doc/development/ux_guide/img/icon-edit.png
+++ b/doc/development/ux_guide/img/icon-edit.png
Binary files differ
diff --git a/doc/development/ux_guide/img/icon-notification.png b/doc/development/ux_guide/img/icon-notification.png
index 4758632edd7..6ddfaa44f66 100644
--- a/doc/development/ux_guide/img/icon-notification.png
+++ b/doc/development/ux_guide/img/icon-notification.png
Binary files differ
diff --git a/doc/development/ux_guide/img/icon-rss.png b/doc/development/ux_guide/img/icon-rss.png
index c7ac9fb1349..b766488b32d 100644
--- a/doc/development/ux_guide/img/icon-rss.png
+++ b/doc/development/ux_guide/img/icon-rss.png
Binary files differ
diff --git a/doc/development/ux_guide/img/icon-subscribe.png b/doc/development/ux_guide/img/icon-subscribe.png
index 5cb277bfd5d..650168296c6 100644
--- a/doc/development/ux_guide/img/icon-subscribe.png
+++ b/doc/development/ux_guide/img/icon-subscribe.png
Binary files differ
diff --git a/doc/development/ux_guide/img/icon-trash.png b/doc/development/ux_guide/img/icon-trash.png
index 357289a6fff..b02178ca992 100644
--- a/doc/development/ux_guide/img/icon-trash.png
+++ b/doc/development/ux_guide/img/icon-trash.png
Binary files differ
diff --git a/doc/install/installation.md b/doc/install/installation.md
index 4b0c585e51e..5099d639347 100644
--- a/doc/install/installation.md
+++ b/doc/install/installation.md
@@ -123,9 +123,9 @@ Remove the old Ruby 1.8 if present:
Download Ruby and compile it:
mkdir /tmp/ruby && cd /tmp/ruby
- curl --remote-name --progress https://cache.ruby-lang.org/pub/ruby/2.3/ruby-2.3.1.tar.gz
- echo 'c39b4001f7acb4e334cb60a0f4df72d434bef711 ruby-2.3.1.tar.gz' | shasum -c - && tar xzf ruby-2.3.1.tar.gz
- cd ruby-2.3.1
+ curl --remote-name --progress https://cache.ruby-lang.org/pub/ruby/2.3/ruby-2.3.3.tar.gz
+ echo 'a8db9ce7f9110320f33b8325200e3ecfbd2b534b ruby-2.3.3.tar.gz' | shasum -c - && tar xzf ruby-2.3.3.tar.gz
+ cd ruby-2.3.3
./configure --disable-install-rdoc
make
sudo make install
diff --git a/doc/integration/shibboleth.md b/doc/integration/shibboleth.md
index eb9bbb67e7d..696c1011eeb 100644
--- a/doc/integration/shibboleth.md
+++ b/doc/integration/shibboleth.md
@@ -2,7 +2,7 @@
This documentation is for enabling shibboleth with omnibus-gitlab package.
-In order to enable Shibboleth support in gitlab we need to use Apache instead of Nginx (It may be possible to use Nginx, however this is difficult to configure using the bundled NIGNX provided in the omnibus-gitlab package). Apache uses mod_shib2 module for shibboleth authentication and can pass attributes as headers to omniauth-shibboleth provider.
+In order to enable Shibboleth support in gitlab we need to use Apache instead of Nginx (It may be possible to use Nginx, however this is difficult to configure using the bundled Nginx provided in the omnibus-gitlab package). Apache uses mod_shib2 module for shibboleth authentication and can pass attributes as headers to omniauth-shibboleth provider.
To enable the Shibboleth OmniAuth provider you must:
diff --git a/doc/intro/README.md b/doc/intro/README.md
index 1790b2b761f..1df6a52ce8a 100644
--- a/doc/intro/README.md
+++ b/doc/intro/README.md
@@ -23,7 +23,7 @@ Create merge requests and review code.
- [Fork a project and contribute to it](../workflow/forking_workflow.md)
- [Create a new merge request](../gitlab-basics/add-merge-request.md)
- [Automatically close issues from merge requests](../user/project/issues/automatic_issue_closing.md)
-- [Automatically merge when your builds succeed](../user/project/merge_requests/merge_when_build_succeeds.md)
+- [Automatically merge when pipeline succeeds](../user/project/merge_requests/merge_when_pipeline_succeeds.md)
- [Revert any commit](../user/project/merge_requests/revert_changes.md)
- [Cherry-pick any commit](../user/project/merge_requests/cherry_pick_changes.md)
diff --git a/doc/update/patch_versions.md b/doc/update/patch_versions.md
index e98c40ca4c0..685972cfb41 100644
--- a/doc/update/patch_versions.md
+++ b/doc/update/patch_versions.md
@@ -1,7 +1,10 @@
# Universal update guide for patch versions
-*Make sure you view this [upgrade guide](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/doc/update/patch_versions.md) from the `master` branch for the most up to date instructions.*
-For example from 7.14.0 to 7.14.3, also see the [semantic versioning specification](http://semver.org/).
+## Select Version to Install
+
+Make sure you view [this update guide](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/doc/update/patch_versions.md) from the tag (version) of GitLab you would like to install.
+In most cases this should be the highest numbered production tag (without rc in it).
+You can select the tag in the version dropdown in the top left corner of GitLab (below the menu bar).
### 0. Backup
diff --git a/doc/user/markdown.md b/doc/user/markdown.md
index 162d1bd7ed4..4d24eb21976 100644
--- a/doc/user/markdown.md
+++ b/doc/user/markdown.md
@@ -267,6 +267,18 @@ GFM also recognizes certain cross-project references:
| `namespace/project@9ba12248...b19a04f5` | commit range comparison |
| `namespace/project~"Some label"` | issues with given label |
+It also has a shorthand version to reference other projects from the same namespace:
+
+| input | references |
+|:------------------------------|:------------------------|
+| `project#123` | issue |
+| `project!123` | merge request |
+| `project%123` | milestone |
+| `project$123` | snippet |
+| `project@9ba12248` | specific commit |
+| `project@9ba12248...b19a04f5` | commit range comparison |
+| `project~"Some label"` | issues with given label |
+
### Task Lists
> If this is not rendered correctly, see
@@ -604,7 +616,7 @@ This line is separated from the one above by two newlines, so it will be a *sepa
This line is also a separate paragraph, but...
This line is only separated by a single newline, so it's a separate line in the *same paragraph*.
-This line is also a separate paragraph, and...
+This line is also a separate paragraph, and...
This line is on its own line, because the previous line ends with two
spaces.
```
@@ -616,7 +628,7 @@ This line is separated from the one above by two newlines, so it will be a *sepa
This line is also begins a separate paragraph, but...
This line is only separated by a single newline, so it's a separate line in the *same paragraph*.
-This line is also a separate paragraph, and...
+This line is also a separate paragraph, and...
This line is on its own line, because the previous line ends with two
spaces.
diff --git a/doc/user/project/merge_requests.md b/doc/user/project/merge_requests.md
index 5af9a5d049c..be09337319f 100644
--- a/doc/user/project/merge_requests.md
+++ b/doc/user/project/merge_requests.md
@@ -19,14 +19,14 @@ in a merged merge requests or a commit.
[Learn more about cherry-picking changes.](merge_requests/cherry_pick_changes.md)
-## Merge when build succeeds
+## Merge when pipeline succeeds
When reviewing a merge request that looks ready to merge but still has one or
-more CI builds running, you can set it to be merged automatically when all
-builds succeed. This way, you don't have to wait for the builds to finish and
-remember to merge the request manually.
+more CI builds running, you can set it to be merged automatically when CI
+pipeline succeeds. This way, you don't have to wait for the pipeline to finish
+and remember to merge the request manually.
-[Learn more about merging when build succeeds.](merge_requests/merge_when_build_succeeds.md)
+[Learn more about merging when pipeline succeeds.](merge_requests/merge_when_pipeline_succeeds.md)
## Resolve discussion comments in merge requests reviews
diff --git a/doc/user/project/merge_requests/img/preview_issue_for_discussions.png b/doc/user/project/merge_requests/img/preview_issue_for_discussions.png
new file mode 100644
index 00000000000..9fdd387676c
--- /dev/null
+++ b/doc/user/project/merge_requests/img/preview_issue_for_discussions.png
Binary files differ
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 285b1798ac5..f37f1ce4d21 100644
--- a/doc/user/project/merge_requests/merge_request_discussion_resolution.md
+++ b/doc/user/project/merge_requests/merge_request_discussion_resolution.md
@@ -37,7 +37,8 @@ resolved discussions tracker.
> [Introduced][ce-7125] in GitLab 8.14.
-You can prevent merge requests from being merged until all discussions are resolved.
+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
@@ -50,8 +51,26 @@ 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-7180] (Currently on Backlog)
+
+To delegate unresolved discussions to a new issue you can click the link **open
+an issue to resolve them later**.
+
+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.
+
+You can now proceed to merge the merge request from the UI.
+
[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
[resolve-discussion-button]: img/resolve_discussion_button.png
[resolve-comment-button]: img/resolve_comment_button.png
[discussion-view]: img/discussion_view.png
diff --git a/doc/user/project/merge_requests/merge_when_build_succeeds.md b/doc/user/project/merge_requests/merge_when_build_succeeds.md
index d4e5b5de685..2167fdfbf7e 100644
--- a/doc/user/project/merge_requests/merge_when_build_succeeds.md
+++ b/doc/user/project/merge_requests/merge_when_build_succeeds.md
@@ -1,46 +1,5 @@
-# Merge When Build Succeeds
+This document was moved to [merge_when_pipeline_succeeds](merge_when_pipeline_succeeds.md).
-When reviewing a merge request that looks ready to merge but still has one or
-more CI builds running, you can set it to be merged automatically when the
-builds pipeline succeed. This way, you don't have to wait for the builds to
-finish and remember to merge the request manually.
+>[Introduced][ce-7135] by the "Rename MWBS service to Merge When Pipeline Succeeds" change.
-![Enable](img/merge_when_build_succeeds_enable.png)
-
-When you hit the "Merge When Build Succeeds" button, the status of the merge
-request will be updated to represent the impending merge. If you cannot wait
-for the pipeline to succeed and want to merge immediately, this option is
-available in the dropdown menu on the right of the main button.
-
-Both team developers and the author of the merge request have the option to
-cancel the automatic merge if they find a reason why it shouldn't be merged
-after all.
-
-![Status](img/merge_when_build_succeeds_status.png)
-
-When the pipeline succeeds, the merge request will automatically be merged.
-When the pipeline fails, the author gets a chance to retry any failed builds,
-or to push new commits to fix the failure.
-
-When the builds are retried and succeed on the second try, the merge request
-will automatically be merged after all. When the merge request is updated with
-new commits, the automatic merge is automatically canceled to allow the new
-changes to be reviewed.
-
-## Only allow merge requests to be merged if the build succeeds
-
-> **Note:**
-You need to have builds configured to enable this feature.
-
-You can prevent merge requests from being merged if their build did not succeed.
-
-Navigate to your project's settings page, select the
-**Only allow merge requests to be merged if the build succeeds** check box and
-hit **Save** for the changes to take effect.
-
-![Only allow merge if build succeeds settings](img/merge_when_build_succeeds_only_if_succeeds_settings.png)
-
-From now on, every time the pipeline fails you will not be able to merge the
-merge request from the UI, until you make all relevant builds pass.
-
-![Only allow merge if build succeeds message](img/merge_when_build_succeeds_only_if_succeeds_msg.png)
+[ce-7135]: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/7135
diff --git a/doc/user/project/merge_requests/merge_when_pipeline_succeeds.md b/doc/user/project/merge_requests/merge_when_pipeline_succeeds.md
new file mode 100644
index 00000000000..75ad18b28cf
--- /dev/null
+++ b/doc/user/project/merge_requests/merge_when_pipeline_succeeds.md
@@ -0,0 +1,46 @@
+# Merge When Pipeline Succeeds
+
+When reviewing a merge request that looks ready to merge but still has one or
+more CI builds running, you can set it to be merged automatically when the
+builds pipeline succeeds. This way, you don't have to wait for the builds to
+finish and remember to merge the request manually.
+
+![Enable](img/merge_when_build_succeeds_enable.png)
+
+When you hit the "Merge When Pipeline Succeeds" button, the status of the merge
+request will be updated to represent the impending merge. If you cannot wait
+for the pipeline to succeed and want to merge immediately, this option is
+available in the dropdown menu on the right of the main button.
+
+Both team developers and the author of the merge request have the option to
+cancel the automatic merge if they find a reason why it shouldn't be merged
+after all.
+
+![Status](img/merge_when_build_succeeds_status.png)
+
+When the pipeline succeeds, the merge request will automatically be merged.
+When the pipeline fails, the author gets a chance to retry any failed builds,
+or to push new commits to fix the failure.
+
+When the builds are retried and succeed on the second try, the merge request
+will automatically be merged after all. When the merge request is updated with
+new commits, the automatic merge is automatically canceled to allow the new
+changes to be reviewed.
+
+## Only allow merge requests to be merged if the pipeline succeeds
+
+> **Note:**
+You need to have builds configured to enable this feature.
+
+You can prevent merge requests from being merged if their pipeline did not succeed.
+
+Navigate to your project's settings page, select the
+**Only allow merge requests to be merged if the pipeline succeeds** check box and
+hit **Save** for the changes to take effect.
+
+![Only allow merge if pipeline succeeds settings](img/merge_when_build_succeeds_only_if_succeeds_settings.png)
+
+From now on, every time the pipeline fails you will not be able to merge the
+merge request from the UI, until you make all relevant builds pass.
+
+![Only allow merge if pipeline succeeds message](img/merge_when_build_succeeds_only_if_succeeds_msg.png)
diff --git a/doc/workflow/README.md b/doc/workflow/README.md
index 2d9bfbc0629..59a806de210 100644
--- a/doc/workflow/README.md
+++ b/doc/workflow/README.md
@@ -25,12 +25,12 @@
- [Merge Requests](../user/project/merge_requests.md)
- [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 build succeeds](../user/project/merge_requests/merge_when_build_succeeds.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 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)
- ["Work In Progress" merge requests](../user/project/merge_requests/work_in_progress_merge_requests.md)
- [Manage large binaries with Git LFS](lfs/manage_large_binaries_with_git_lfs.md)
-- [Importing from SVN, GitHub, BitBucket, etc](importing/README.md)
+- [Importing from SVN, GitHub, Bitbucket, etc](importing/README.md)
- [Todos](todos.md)
diff --git a/doc/workflow/merge_when_build_succeeds.md b/doc/workflow/merge_when_build_succeeds.md
index 95afd12ebdb..b4f6d6117de 100644
--- a/doc/workflow/merge_when_build_succeeds.md
+++ b/doc/workflow/merge_when_build_succeeds.md
@@ -1 +1 @@
-This document was moved to [user/project/merge_requests/merge_when_build_succeeds](../user/project/merge_requests/merge_when_build_succeeds.md).
+This document was moved to [merge_when_pipeline_succeeds](../user/project/merge_requests/merge_when_pipeline_succeeds.md).
diff --git a/features/steps/shared/project.rb b/features/steps/shared/project.rb
index cab85a48396..b51152c79c6 100644
--- a/features/steps/shared/project.rb
+++ b/features/steps/shared/project.rb
@@ -9,7 +9,7 @@ module SharedProject
step "project exists in some group namespace" do
@group = create(:group, name: 'some group')
- @project = create(:project, namespace: @group)
+ @project = create(:project, namespace: @group, public_builds: false)
end
# Create a specific project called "Shop"
diff --git a/lib/api/access_requests.rb b/lib/api/access_requests.rb
index ed723b94cfd..789f45489eb 100644
--- a/lib/api/access_requests.rb
+++ b/lib/api/access_requests.rb
@@ -1,5 +1,7 @@
module API
class AccessRequests < Grape::API
+ include PaginationParams
+
before { authenticate! }
helpers ::API::Helpers::MembersHelpers
@@ -13,6 +15,9 @@ module API
detail 'This feature was introduced in GitLab 8.11.'
success Entities::AccessRequester
end
+ params do
+ use :pagination
+ end
get ":id/access_requests" do
source = find_source(source_type, params[:id])
diff --git a/lib/api/award_emoji.rb b/lib/api/award_emoji.rb
index e9ccba3b465..58a4df54bea 100644
--- a/lib/api/award_emoji.rb
+++ b/lib/api/award_emoji.rb
@@ -1,5 +1,7 @@
module API
class AwardEmoji < Grape::API
+ include PaginationParams
+
before { authenticate! }
AWARDABLES = %w[issue merge_request snippet]
@@ -21,6 +23,9 @@ module API
detail 'This feature was introduced in 8.9'
success Entities::AwardEmoji
end
+ params do
+ use :pagination
+ end
get endpoint do
if can_read_awardable?
awards = paginate(awardable.award_emoji)
diff --git a/lib/api/builds.rb b/lib/api/builds.rb
index 67adca6605f..af61be343be 100644
--- a/lib/api/builds.rb
+++ b/lib/api/builds.rb
@@ -1,6 +1,7 @@
module API
- # Projects builds API
class Builds < Grape::API
+ include PaginationParams
+
before { authenticate! }
params do
@@ -28,6 +29,7 @@ module API
end
params do
use :optional_scope
+ use :pagination
end
get ':id/builds' do
builds = user_project.builds.order('id DESC')
@@ -41,8 +43,9 @@ module API
success Entities::Build
end
params do
- requires :sha, type: String, desc: 'The SHA id of a commit'
+ requires :sha, type: String, desc: 'The SHA id of a commit'
use :optional_scope
+ use :pagination
end
get ':id/repository/commits/:sha/builds' do
authorize_read_builds!
diff --git a/lib/api/commit_statuses.rb b/lib/api/commit_statuses.rb
index 492884d162b..4bbdf06a49c 100644
--- a/lib/api/commit_statuses.rb
+++ b/lib/api/commit_statuses.rb
@@ -1,9 +1,10 @@
require 'mime/types'
module API
- # Project commit statuses API
class CommitStatuses < Grape::API
resource :projects do
+ include PaginationParams
+
before { authenticate! }
desc "Get a commit's statuses" do
@@ -16,6 +17,7 @@ module API
optional :stage, type: String, desc: 'The stage'
optional :name, type: String, desc: 'The name'
optional :all, type: String, desc: 'Show all statuses, default: false'
+ use :pagination
end
get ':id/repository/commits/:sha/statuses' do
authorize!(:read_commit_status, user_project)
diff --git a/lib/api/entities.rb b/lib/api/entities.rb
index d5dfb8d00be..899d68bc6c7 100644
--- a/lib/api/entities.rb
+++ b/lib/api/entities.rb
@@ -174,6 +174,7 @@ module API
class RepoCommit < Grape::Entity
expose :id, :short_id, :title, :author_name, :author_email, :created_at
+ expose :committer_name, :committer_email
expose :safe_message, as: :message
end
diff --git a/lib/api/groups.rb b/lib/api/groups.rb
index 5315c22e1e4..fbf7513302b 100644
--- a/lib/api/groups.rb
+++ b/lib/api/groups.rb
@@ -1,5 +1,7 @@
module API
class Groups < Grape::API
+ include PaginationParams
+
before { authenticate! }
helpers do
@@ -21,6 +23,7 @@ module API
optional :search, type: String, desc: 'Search for a specific group'
optional :order_by, type: String, values: %w[name path], default: 'name', desc: 'Order by name or path'
optional :sort, type: String, values: %w[asc desc], default: 'asc', desc: 'Sort by asc (ascending) or desc (descending)'
+ use :pagination
end
get do
groups = if current_user.admin
@@ -41,6 +44,9 @@ module API
desc 'Get list of owned groups for authenticated user' do
success Entities::Group
end
+ params do
+ use :pagination
+ end
get '/owned' do
groups = current_user.owned_groups
present paginate(groups), with: Entities::Group, user: current_user
@@ -110,11 +116,13 @@ module API
desc 'Get a list of projects in this group.' do
success Entities::Project
end
+ params do
+ use :pagination
+ end
get ":id/projects" do
group = find_group!(params[:id])
projects = GroupProjectsFinder.new(group).execute(current_user)
- projects = paginate projects
- present projects, with: Entities::Project, user: current_user
+ present paginate(projects), with: Entities::Project, user: current_user
end
desc 'Transfer a project to the group namespace. Available only for admin.' do
diff --git a/lib/api/issues.rb b/lib/api/issues.rb
index 049b4fb214c..26c8f2fecd0 100644
--- a/lib/api/issues.rb
+++ b/lib/api/issues.rb
@@ -151,24 +151,33 @@ module API
# Create a new project issue
#
# Parameters:
- # id (required) - The ID of a project
- # title (required) - The title of an issue
- # description (optional) - The description of an issue
- # assignee_id (optional) - The ID of a user to assign issue
- # milestone_id (optional) - The ID of a milestone to assign issue
- # labels (optional) - The labels of an issue
- # created_at (optional) - Date time string, ISO 8601 formatted
- # due_date (optional) - Date time string in the format YEAR-MONTH-DAY
- # confidential (optional) - Boolean parameter if the issue should be confidential
+ # id (required) - The ID of a project
+ # title (required) - The title of an issue
+ # description (optional) - The description of an issue
+ # assignee_id (optional) - The ID of a user to assign issue
+ # milestone_id (optional) - The ID of a milestone to assign issue
+ # labels (optional) - The labels of an issue
+ # created_at (optional) - Date time string, ISO 8601 formatted
+ # due_date (optional) - Date time string in the format YEAR-MONTH-DAY
+ # confidential (optional) - Boolean parameter if the issue should be confidential
+ # merge_request_for_resolving_discussions (optional) - The IID of a merge request for which to resolve discussions
# Example Request:
# POST /projects/:id/issues
post ':id/issues' do
required_attributes! [:title]
- keys = [:title, :description, :assignee_id, :milestone_id, :due_date, :confidential, :labels]
+ keys = [:title, :description, :assignee_id, :milestone_id, :due_date, :confidential, :labels, :merge_request_for_resolving_discussions]
keys << :created_at if current_user.admin? || user_project.owner == current_user
attrs = attributes_for_keys(keys)
+ attrs[:labels] = params[:labels] if params[:labels]
+
+ if merge_request_iid = params[:merge_request_for_resolving_discussions]
+ attrs[:merge_request_for_resolving_discussions] = MergeRequestsFinder.new(current_user, project_id: user_project.id).
+ execute.
+ find_by(iid: merge_request_iid)
+ end
+
# Convert and filter out invalid confidential flags
attrs['confidential'] = to_boolean(attrs['confidential'])
attrs.delete('confidential') if attrs['confidential'].nil?
diff --git a/lib/api/members.rb b/lib/api/members.rb
index 2d4d5cedf20..d85f1f78cd6 100644
--- a/lib/api/members.rb
+++ b/lib/api/members.rb
@@ -1,5 +1,7 @@
module API
class Members < Grape::API
+ include PaginationParams
+
before { authenticate! }
helpers ::API::Helpers::MembersHelpers
@@ -14,15 +16,15 @@ module API
end
params do
optional :query, type: String, desc: 'A query string to search for members'
+ use :pagination
end
get ":id/members" do
source = find_source(source_type, params[:id])
users = source.users
users = users.merge(User.search(params[:query])) if params[:query]
- users = paginate(users)
- present users, with: Entities::Member, source: source
+ present paginate(users), with: Entities::Member, source: source
end
desc 'Gets a member of a group or project.' do
diff --git a/lib/api/merge_requests.rb b/lib/api/merge_requests.rb
index 97baebc1d27..253460830ff 100644
--- a/lib/api/merge_requests.rb
+++ b/lib/api/merge_requests.rb
@@ -1,5 +1,7 @@
module API
class MergeRequests < Grape::API
+ include PaginationParams
+
DEPRECATION_MESSAGE = 'This endpoint is deprecated and will be removed in GitLab 9.0.'.freeze
before { authenticate! }
@@ -42,6 +44,7 @@ module API
optional :sort, type: String, values: %w[asc desc], default: 'desc',
desc: 'Return merge requests sorted in `asc` or `desc` order.'
optional :iid, type: Array[Integer], desc: 'The IID of the merge requests'
+ use :pagination
end
get ":id/merge_requests" do
authorize! :read_merge_request, user_project
@@ -169,7 +172,7 @@ module API
optional :should_remove_source_branch, type: Boolean,
desc: 'When true, the source branch will be deleted if possible'
optional :merge_when_build_succeeds, type: Boolean,
- desc: 'When true, this merge request will be merged when the build succeeds'
+ desc: 'When true, this merge request will be merged when the pipeline succeeds'
optional :sha, type: String, desc: 'When present, must have the HEAD SHA of the source branch'
end
put "#{path}/merge" do
@@ -193,17 +196,19 @@ module API
}
if params[:merge_when_build_succeeds] && merge_request.head_pipeline && merge_request.head_pipeline.active?
- ::MergeRequests::MergeWhenBuildSucceedsService.new(merge_request.target_project, current_user, merge_params).
- execute(merge_request)
+ ::MergeRequests::MergeWhenPipelineSucceedsService
+ .new(merge_request.target_project, current_user, merge_params)
+ .execute(merge_request)
else
- ::MergeRequests::MergeService.new(merge_request.target_project, current_user, merge_params).
- execute(merge_request)
+ ::MergeRequests::MergeService
+ .new(merge_request.target_project, current_user, merge_params)
+ .execute(merge_request)
end
present merge_request, with: Entities::MergeRequest, current_user: current_user, project: user_project
end
- desc 'Cancel merge if "Merge when build succeeds" is enabled' do
+ desc 'Cancel merge if "Merge When Pipeline Succeeds" is enabled' do
success Entities::MergeRequest
end
post "#{path}/cancel_merge_when_build_succeeds" do
@@ -211,13 +216,18 @@ module API
unauthorized! unless merge_request.can_cancel_merge_when_build_succeeds?(current_user)
- ::MergeRequest::MergeWhenBuildSucceedsService.new(merge_request.target_project, current_user).cancel(merge_request)
+ ::MergeRequest::MergeWhenPipelineSucceedsService
+ .new(merge_request.target_project, current_user)
+ .cancel(merge_request)
end
desc 'Get the comments of a merge request' do
detail 'Duplicate. DEPRECATED and WILL BE REMOVED in 9.0'
success Entities::MRNote
end
+ params do
+ use :pagination
+ end
get "#{path}/comments" do
merge_request = user_project.merge_requests.find(params[:merge_request_id])
@@ -255,6 +265,9 @@ module API
desc 'List issues that will be closed on merge' do
success Entities::MRNote
end
+ params do
+ use :pagination
+ end
get "#{path}/closes_issues" do
merge_request = user_project.merge_requests.find(params[:merge_request_id])
issues = ::Kaminari.paginate_array(merge_request.closes_issues(current_user))
diff --git a/lib/api/milestones.rb b/lib/api/milestones.rb
index 50d6109be3d..3c373a84ec5 100644
--- a/lib/api/milestones.rb
+++ b/lib/api/milestones.rb
@@ -1,6 +1,7 @@
module API
- # Milestones API
class Milestones < Grape::API
+ include PaginationParams
+
before { authenticate! }
helpers do
@@ -30,6 +31,7 @@ module API
optional :state, type: String, values: %w[active closed all], default: 'all',
desc: 'Return "active", "closed", or "all" milestones'
optional :iid, type: Array[Integer], desc: 'The IID of the milestone'
+ use :pagination
end
get ":id/milestones" do
authorize! :read_milestone, user_project
@@ -103,6 +105,7 @@ module API
end
params do
requires :milestone_id, type: Integer, desc: 'The ID of a project milestone'
+ use :pagination
end
get ":id/milestones/:milestone_id/issues" do
authorize! :read_milestone, user_project
diff --git a/lib/api/namespaces.rb b/lib/api/namespaces.rb
index fe981d7b9fa..30761cb9b55 100644
--- a/lib/api/namespaces.rb
+++ b/lib/api/namespaces.rb
@@ -1,6 +1,7 @@
module API
- # namespaces API
class Namespaces < Grape::API
+ include PaginationParams
+
before { authenticate! }
resource :namespaces do
@@ -9,6 +10,7 @@ module API
end
params do
optional :search, type: String, desc: "Search query for namespaces"
+ use :pagination
end
get do
namespaces = current_user.admin ? Namespace.all : current_user.namespaces
diff --git a/lib/api/notes.rb b/lib/api/notes.rb
index b255b47742b..d0faf17714b 100644
--- a/lib/api/notes.rb
+++ b/lib/api/notes.rb
@@ -1,6 +1,7 @@
module API
- # Notes API
class Notes < Grape::API
+ include PaginationParams
+
before { authenticate! }
NOTEABLE_TYPES = [Issue, MergeRequest, Snippet]
@@ -17,6 +18,7 @@ module API
end
params do
requires :noteable_id, type: Integer, desc: 'The ID of the noteable'
+ use :pagination
end
get ":id/#{noteables_str}/:noteable_id/notes" do
noteable = user_project.send(noteables_str.to_sym).find(params[:noteable_id])
diff --git a/lib/api/project_hooks.rb b/lib/api/project_hooks.rb
index 2b36ef7c426..dcc0fb7a911 100644
--- a/lib/api/project_hooks.rb
+++ b/lib/api/project_hooks.rb
@@ -1,6 +1,10 @@
module API
- # Projects API
class ProjectHooks < Grape::API
+ include PaginationParams
+
+ before { authenticate! }
+ before { authorize_admin_project }
+
helpers do
params :project_hook_properties do
requires :url, type: String, desc: "The URL to send the request to"
@@ -17,9 +21,6 @@ module API
end
end
- before { authenticate! }
- before { authorize_admin_project }
-
params do
requires :id, type: String, desc: 'The ID of a project'
end
@@ -27,6 +28,9 @@ module API
desc 'Get project hooks' do
success Entities::ProjectHook
end
+ params do
+ use :pagination
+ end
get ":id/hooks" do
hooks = paginate user_project.hooks
diff --git a/lib/api/project_snippets.rb b/lib/api/project_snippets.rb
index d0ee9c9a5b2..9d8c5b63685 100644
--- a/lib/api/project_snippets.rb
+++ b/lib/api/project_snippets.rb
@@ -1,6 +1,7 @@
module API
- # Projects API
class ProjectSnippets < Grape::API
+ include PaginationParams
+
before { authenticate! }
params do
@@ -24,6 +25,9 @@ module API
desc 'Get all project snippets' do
success Entities::ProjectSnippet
end
+ params do
+ use :pagination
+ end
get ":id/snippets" do
present paginate(snippets_for_current_user), with: Entities::ProjectSnippet
end
diff --git a/lib/api/runners.rb b/lib/api/runners.rb
index b145cce7e3e..4816b5ed1b7 100644
--- a/lib/api/runners.rb
+++ b/lib/api/runners.rb
@@ -1,5 +1,7 @@
module API
class Runners < Grape::API
+ include PaginationParams
+
before { authenticate! }
resource :runners do
@@ -9,6 +11,7 @@ module API
params do
optional :scope, type: String, values: %w[active paused online],
desc: 'The scope of specific runners to show'
+ use :pagination
end
get do
runners = filter_runners(current_user.ci_authorized_runners, params[:scope], without: ['specific', 'shared'])
@@ -21,6 +24,7 @@ module API
params do
optional :scope, type: String, values: %w[active paused online specific shared],
desc: 'The scope of specific runners to show'
+ use :pagination
end
get 'all' do
authenticated_as_admin!
@@ -91,6 +95,7 @@ module API
params do
optional :scope, type: String, values: %w[active paused online specific shared],
desc: 'The scope of specific runners to show'
+ use :pagination
end
get ':id/runners' do
runners = filter_runners(Ci::Runner.owned_or_shared(user_project.id), params[:scope])
diff --git a/lib/api/todos.rb b/lib/api/todos.rb
index 832b04a3bb1..ed8f48aa1e3 100644
--- a/lib/api/todos.rb
+++ b/lib/api/todos.rb
@@ -1,6 +1,7 @@
module API
- # Todos API
class Todos < Grape::API
+ include PaginationParams
+
before { authenticate! }
ISSUABLE_TYPES = {
@@ -44,10 +45,11 @@ module API
desc 'Get a todo list' do
success Entities::Todo
end
+ params do
+ use :pagination
+ end
get do
- todos = find_todos
-
- present paginate(todos), with: Entities::Todo, current_user: current_user
+ present paginate(find_todos), with: Entities::Todo, current_user: current_user
end
desc 'Mark a todo as done' do
diff --git a/lib/api/triggers.rb b/lib/api/triggers.rb
index bb4de39def1..87a717ba751 100644
--- a/lib/api/triggers.rb
+++ b/lib/api/triggers.rb
@@ -1,5 +1,7 @@
module API
class Triggers < Grape::API
+ include PaginationParams
+
params do
requires :id, type: String, desc: 'The ID of a project'
end
@@ -42,6 +44,9 @@ module API
desc 'Get triggers list' do
success Entities::Trigger
end
+ params do
+ use :pagination
+ end
get ':id/triggers' do
authenticate!
authorize! :admin_build, user_project
diff --git a/lib/api/users.rb b/lib/api/users.rb
index a73650dc361..bc2362aa72e 100644
--- a/lib/api/users.rb
+++ b/lib/api/users.rb
@@ -1,6 +1,7 @@
module API
- # Users API
class Users < Grape::API
+ include PaginationParams
+
before { authenticate! }
resource :users, requirements: { uid: /[0-9]*/, id: /[0-9]*/ } do
@@ -33,6 +34,7 @@ module API
optional :active, type: Boolean, default: false, desc: 'Filters only active users'
optional :external, type: Boolean, default: false, desc: 'Filters only external users'
optional :blocked, type: Boolean, default: false, desc: 'Filters only blocked users'
+ use :pagination
end
get do
unless can?(current_user, :read_users_list, nil)
@@ -330,6 +332,7 @@ module API
end
params do
requires :id, type: Integer, desc: 'The ID of the user'
+ use :pagination
end
get ':id/events' do
user = User.find_by(id: params[:id])
diff --git a/lib/banzai/filter/abstract_reference_filter.rb b/lib/banzai/filter/abstract_reference_filter.rb
index 3740d4fb4cd..d904a8bd4ae 100644
--- a/lib/banzai/filter/abstract_reference_filter.rb
+++ b/lib/banzai/filter/abstract_reference_filter.rb
@@ -33,7 +33,7 @@ module Banzai
# Returns a String replaced with the return of the block.
def self.references_in(text, pattern = object_class.reference_pattern)
text.gsub(pattern) do |match|
- yield match, $~[object_sym].to_i, $~[:project], $~
+ yield match, $~[object_sym].to_i, $~[:project], $~[:namespace], $~
end
end
@@ -145,8 +145,9 @@ module Banzai
# Returns a String with references replaced with links. All links
# have `gfm` and `gfm-OBJECT_NAME` class names attached for styling.
def object_link_filter(text, pattern, link_content: nil)
- references_in(text, pattern) do |match, id, project_ref, matches|
- project = project_from_ref_cached(project_ref)
+ references_in(text, pattern) do |match, id, project_ref, namespace_ref, matches|
+ project_path = full_project_path(namespace_ref, project_ref)
+ project = project_from_ref_cached(project_path)
if project && object = find_object_cached(project, id)
title = object_link_title(object)
@@ -217,10 +218,9 @@ module Banzai
nodes.each do |node|
node.to_html.scan(regex) do
- project = $~[:project] || current_project_path
+ project_path = full_project_path($~[:namespace], $~[:project])
symbol = $~[object_sym]
-
- refs[project] << symbol if object_class.reference_valid?(symbol)
+ refs[project_path] << symbol if object_class.reference_valid?(symbol)
end
end
@@ -272,8 +272,19 @@ module Banzai
@current_project_path ||= project.path_with_namespace
end
+ def current_project_namespace_path
+ @current_project_namespace_path ||= project.namespace.path
+ end
+
private
+ def full_project_path(namespace, project_ref)
+ return current_project_path unless project_ref
+
+ namespace_ref = namespace || current_project_namespace_path
+ "#{namespace_ref}/#{project_ref}"
+ end
+
def project_refs_cache
RequestStore[:banzai_project_refs] ||= {}
end
diff --git a/lib/banzai/filter/commit_range_reference_filter.rb b/lib/banzai/filter/commit_range_reference_filter.rb
index 4358bf45549..eaacb9591b1 100644
--- a/lib/banzai/filter/commit_range_reference_filter.rb
+++ b/lib/banzai/filter/commit_range_reference_filter.rb
@@ -12,7 +12,7 @@ module Banzai
def self.references_in(text, pattern = CommitRange.reference_pattern)
text.gsub(pattern) do |match|
- yield match, $~[:commit_range], $~[:project], $~
+ yield match, $~[:commit_range], $~[:project], $~[:namespace], $~
end
end
diff --git a/lib/banzai/filter/commit_reference_filter.rb b/lib/banzai/filter/commit_reference_filter.rb
index a26dd09c25a..69c06117eda 100644
--- a/lib/banzai/filter/commit_reference_filter.rb
+++ b/lib/banzai/filter/commit_reference_filter.rb
@@ -12,7 +12,7 @@ module Banzai
def self.references_in(text, pattern = Commit.reference_pattern)
text.gsub(pattern) do |match|
- yield match, $~[:commit], $~[:project], $~
+ yield match, $~[:commit], $~[:project], $~[:namespace], $~
end
end
diff --git a/lib/banzai/filter/label_reference_filter.rb b/lib/banzai/filter/label_reference_filter.rb
index 9f9a96cdc65..a605dea149e 100644
--- a/lib/banzai/filter/label_reference_filter.rb
+++ b/lib/banzai/filter/label_reference_filter.rb
@@ -14,16 +14,18 @@ module Banzai
def self.references_in(text, pattern = Label.reference_pattern)
unescape_html_entities(text).gsub(pattern) do |match|
- yield match, $~[:label_id].to_i, $~[:label_name], $~[:project], $~
+ yield match, $~[:label_id].to_i, $~[:label_name], $~[:project], $~[:namespace], $~
end
end
def references_in(text, pattern = Label.reference_pattern)
unescape_html_entities(text).gsub(pattern) do |match|
- label = find_label($~[:project], $~[:label_id], $~[:label_name])
+ namespace, project = $~[:namespace], $~[:project]
+ project_path = full_project_path(namespace, project)
+ label = find_label(project_path, $~[:label_id], $~[:label_name])
if label
- yield match, label.id, $~[:project], $~
+ yield match, label.id, project, namespace, $~
else
match
end
@@ -64,48 +66,12 @@ module Banzai
end
def object_link_text(object, matches)
- if same_group?(object) && namespace_match?(matches)
- render_same_project_label(object)
- elsif same_project?(object)
- render_same_project_label(object)
- else
- render_cross_project_label(object, matches)
- end
- end
-
- def same_group?(object)
- object.is_a?(GroupLabel) && object.group == project.group
- end
-
- def namespace_match?(matches)
- matches[:project].blank? || matches[:project] == project.path_with_namespace
- end
-
- def same_project?(object)
- object.is_a?(ProjectLabel) && object.project == project
- end
-
- def user
- context[:current_user] || context[:author]
- end
-
- def project
- context[:project]
- end
-
- def render_same_project_label(object)
- LabelsHelper.render_colored_label(object)
- end
-
- def render_cross_project_label(object, matches)
- source_project =
- if matches[:project]
- Project.find_with_namespace(matches[:project])
- else
- object.project
- end
+ project_path = full_project_path(matches[:namespace], matches[:project])
+ project_from_ref = project_from_ref_cached(project_path)
+ reference = project_from_ref.to_human_reference(project)
+ label_suffix = " <i>in #{reference}</i>" if reference.present?
- LabelsHelper.render_colored_cross_project_label(object, source_project)
+ LabelsHelper.render_colored_label(object, label_suffix)
end
def unescape_html_entities(text)
diff --git a/lib/banzai/filter/milestone_reference_filter.rb b/lib/banzai/filter/milestone_reference_filter.rb
index 58fff496d00..f12014e191f 100644
--- a/lib/banzai/filter/milestone_reference_filter.rb
+++ b/lib/banzai/filter/milestone_reference_filter.rb
@@ -19,18 +19,20 @@ module Banzai
return super(text, pattern) if pattern != Milestone.reference_pattern
text.gsub(pattern) do |match|
- milestone = find_milestone($~[:project], $~[:milestone_iid], $~[:milestone_name])
+ milestone = find_milestone($~[:project], $~[:namespace], $~[:milestone_iid], $~[:milestone_name])
if milestone
- yield match, milestone.iid, $~[:project], $~
+ yield match, milestone.iid, $~[:project], $~[:namespace], $~
else
match
end
end
end
- def find_milestone(project_ref, milestone_id, milestone_name)
- project = project_from_ref(project_ref)
+ def find_milestone(project_ref, namespace_ref, milestone_id, milestone_name)
+ project_path = full_project_path(namespace_ref, project_ref)
+ project = project_from_ref(project_path)
+
return unless project
milestone_params = milestone_params(milestone_id, milestone_name)
@@ -52,11 +54,13 @@ module Banzai
end
def object_link_text(object, matches)
- if context[:project] == object.project
- super
+ milestone_link = escape_once(super)
+ reference = object.project.to_reference(project)
+
+ if reference.present?
+ "#{milestone_link} <i>in #{reference}</i>".html_safe
else
- "#{escape_once(super)} <i>in #{escape_once(object.project.path_with_namespace)}</i>".
- html_safe
+ milestone_link
end
end
diff --git a/lib/gitlab/chat_commands/issue_create.rb b/lib/gitlab/chat_commands/issue_create.rb
index 99c1382af44..1dba85c1b51 100644
--- a/lib/gitlab/chat_commands/issue_create.rb
+++ b/lib/gitlab/chat_commands/issue_create.rb
@@ -4,11 +4,11 @@ module Gitlab
def self.match(text)
# we can not match \n with the dot by passing the m modifier as than
# the title and description are not seperated
- /\Aissue\s+create\s+(?<title>[^\n]*)\n*(?<description>(.|\n)*)/.match(text)
+ /\Aissue\s+(new|create)\s+(?<title>[^\n]*)\n*(?<description>(.|\n)*)/.match(text)
end
def self.help_message
- 'issue create <title>\n<description>'
+ 'issue new <title>\n<description>'
end
def self.allowed?(project, user)
diff --git a/lib/gitlab/ci/status/canceled.rb b/lib/gitlab/ci/status/canceled.rb
new file mode 100644
index 00000000000..dd6d99e9075
--- /dev/null
+++ b/lib/gitlab/ci/status/canceled.rb
@@ -0,0 +1,19 @@
+module Gitlab
+ module Ci
+ module Status
+ class Canceled < Status::Core
+ def text
+ 'canceled'
+ end
+
+ def label
+ 'canceled'
+ end
+
+ def icon
+ 'icon_status_canceled'
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/ci/status/core.rb b/lib/gitlab/ci/status/core.rb
new file mode 100644
index 00000000000..ce4108fdcf2
--- /dev/null
+++ b/lib/gitlab/ci/status/core.rb
@@ -0,0 +1,58 @@
+module Gitlab
+ module Ci
+ module Status
+ # Base abstract class fore core status
+ #
+ class Core
+ include Gitlab::Routing.url_helpers
+
+ def initialize(subject)
+ @subject = subject
+ end
+
+ def icon
+ raise NotImplementedError
+ end
+
+ def label
+ raise NotImplementedError
+ end
+
+ def title
+ "#{@subject.class.name.demodulize}: #{label}"
+ end
+
+ # Deprecation warning: this method is here because we need to maintain
+ # backwards compatibility with legacy statuses. We often do something
+ # like "ci-status ci-status-#{status}" to set CSS class.
+ #
+ # `to_s` method should be renamed to `group` at some point, after
+ # phasing legacy satuses out.
+ #
+ def to_s
+ self.class.name.demodulize.downcase.underscore
+ end
+
+ def has_details?
+ raise NotImplementedError
+ end
+
+ def details_path
+ raise NotImplementedError
+ end
+
+ def has_action?
+ raise NotImplementedError
+ end
+
+ def action_icon
+ raise NotImplementedError
+ end
+
+ def action_path
+ raise NotImplementedError
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/ci/status/created.rb b/lib/gitlab/ci/status/created.rb
new file mode 100644
index 00000000000..6596d7e01ca
--- /dev/null
+++ b/lib/gitlab/ci/status/created.rb
@@ -0,0 +1,19 @@
+module Gitlab
+ module Ci
+ module Status
+ class Created < Status::Core
+ def text
+ 'created'
+ end
+
+ def label
+ 'created'
+ end
+
+ def icon
+ 'icon_status_created'
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/ci/status/extended.rb b/lib/gitlab/ci/status/extended.rb
new file mode 100644
index 00000000000..6bfb5d38c1f
--- /dev/null
+++ b/lib/gitlab/ci/status/extended.rb
@@ -0,0 +1,11 @@
+module Gitlab
+ module Ci
+ module Status
+ module Extended
+ def matches?(_subject)
+ raise NotImplementedError
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/ci/status/failed.rb b/lib/gitlab/ci/status/failed.rb
new file mode 100644
index 00000000000..c5b5e3203ad
--- /dev/null
+++ b/lib/gitlab/ci/status/failed.rb
@@ -0,0 +1,19 @@
+module Gitlab
+ module Ci
+ module Status
+ class Failed < Status::Core
+ def text
+ 'failed'
+ end
+
+ def label
+ 'failed'
+ end
+
+ def icon
+ 'icon_status_failed'
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/ci/status/pending.rb b/lib/gitlab/ci/status/pending.rb
new file mode 100644
index 00000000000..d30f35a59a2
--- /dev/null
+++ b/lib/gitlab/ci/status/pending.rb
@@ -0,0 +1,19 @@
+module Gitlab
+ module Ci
+ module Status
+ class Pending < Status::Core
+ def text
+ 'pending'
+ end
+
+ def label
+ 'pending'
+ end
+
+ def icon
+ 'icon_status_pending'
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/ci/status/pipeline/common.rb b/lib/gitlab/ci/status/pipeline/common.rb
new file mode 100644
index 00000000000..25e52bec3da
--- /dev/null
+++ b/lib/gitlab/ci/status/pipeline/common.rb
@@ -0,0 +1,23 @@
+module Gitlab
+ module Ci
+ module Status
+ module Pipeline
+ module Common
+ def has_details?
+ true
+ end
+
+ def details_path
+ namespace_project_pipeline_path(@subject.project.namespace,
+ @subject.project,
+ @subject)
+ end
+
+ def has_action?
+ false
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/ci/status/pipeline/factory.rb b/lib/gitlab/ci/status/pipeline/factory.rb
new file mode 100644
index 00000000000..71d27bf7cf5
--- /dev/null
+++ b/lib/gitlab/ci/status/pipeline/factory.rb
@@ -0,0 +1,39 @@
+module Gitlab
+ module Ci
+ module Status
+ module Pipeline
+ class Factory
+ EXTENDED_STATUSES = [Pipeline::SuccessWithWarnings]
+
+ def initialize(pipeline)
+ @pipeline = pipeline
+ @status = pipeline.status || :created
+ end
+
+ def fabricate!
+ if extended_status
+ extended_status.new(core_status)
+ else
+ core_status
+ end
+ end
+
+ private
+
+ def core_status
+ Gitlab::Ci::Status
+ .const_get(@status.capitalize)
+ .new(@pipeline)
+ .extend(Status::Pipeline::Common)
+ end
+
+ def extended_status
+ @extended ||= EXTENDED_STATUSES.find do |status|
+ status.matches?(@pipeline)
+ end
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/ci/status/pipeline/success_with_warnings.rb b/lib/gitlab/ci/status/pipeline/success_with_warnings.rb
new file mode 100644
index 00000000000..4b040d60df8
--- /dev/null
+++ b/lib/gitlab/ci/status/pipeline/success_with_warnings.rb
@@ -0,0 +1,31 @@
+module Gitlab
+ module Ci
+ module Status
+ module Pipeline
+ class SuccessWithWarnings < SimpleDelegator
+ extend Status::Extended
+
+ def text
+ 'passed'
+ end
+
+ def label
+ 'passed with warnings'
+ end
+
+ def icon
+ 'icon_status_warning'
+ end
+
+ def to_s
+ 'success_with_warnings'
+ end
+
+ def self.matches?(pipeline)
+ pipeline.success? && pipeline.has_warnings?
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/ci/status/running.rb b/lib/gitlab/ci/status/running.rb
new file mode 100644
index 00000000000..2aba3c373c7
--- /dev/null
+++ b/lib/gitlab/ci/status/running.rb
@@ -0,0 +1,19 @@
+module Gitlab
+ module Ci
+ module Status
+ class Running < Status::Core
+ def text
+ 'running'
+ end
+
+ def label
+ 'running'
+ end
+
+ def icon
+ 'icon_status_running'
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/ci/status/skipped.rb b/lib/gitlab/ci/status/skipped.rb
new file mode 100644
index 00000000000..16282aefd03
--- /dev/null
+++ b/lib/gitlab/ci/status/skipped.rb
@@ -0,0 +1,19 @@
+module Gitlab
+ module Ci
+ module Status
+ class Skipped < Status::Core
+ def text
+ 'skipped'
+ end
+
+ def label
+ 'skipped'
+ end
+
+ def icon
+ 'icon_status_skipped'
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/ci/status/success.rb b/lib/gitlab/ci/status/success.rb
new file mode 100644
index 00000000000..c09c5f006e3
--- /dev/null
+++ b/lib/gitlab/ci/status/success.rb
@@ -0,0 +1,19 @@
+module Gitlab
+ module Ci
+ module Status
+ class Success < Status::Core
+ def text
+ 'passed'
+ end
+
+ def label
+ 'passed'
+ end
+
+ def icon
+ 'icon_status_success'
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/diff/file_collection/merge_request_diff.rb b/lib/gitlab/diff/file_collection/merge_request_diff.rb
index 26bb0bc16f5..56530448f36 100644
--- a/lib/gitlab/diff/file_collection/merge_request_diff.rb
+++ b/lib/gitlab/diff/file_collection/merge_request_diff.rb
@@ -61,7 +61,7 @@ module Gitlab
end
def cacheable?(diff_file)
- @merge_request_diff.present? && diff_file.blob.text?
+ @merge_request_diff.present? && diff_file.blob && diff_file.blob.text?
end
def cache_key
diff --git a/scripts/lint-doc.sh b/scripts/lint-doc.sh
index 7c4e8276902..62236ed539a 100755
--- a/scripts/lint-doc.sh
+++ b/scripts/lint-doc.sh
@@ -3,7 +3,7 @@
cd "$(dirname "$0")/.."
# Use long options (e.g. --header instead of -H) for curl examples in documentation.
-grep --perl-regexp --recursive --color=auto 'curl (.+ )?-[^- ].*' doc/
+grep --extended-regexp --recursive --color=auto 'curl (.+ )?-[^- ].*' doc/
if [ $? == 0 ]
then
echo '✖ ERROR: Short options should not be used in documentation!' >&2
diff --git a/spec/controllers/projects/issues_controller_spec.rb b/spec/controllers/projects/issues_controller_spec.rb
index 90419368f22..dbe5ddccbcf 100644
--- a/spec/controllers/projects/issues_controller_spec.rb
+++ b/spec/controllers/projects/issues_controller_spec.rb
@@ -55,6 +55,30 @@ describe Projects::IssuesController do
end
describe 'GET #new' do
+ context 'internal issue tracker' do
+ before do
+ sign_in(user)
+ project.team << [user, :developer]
+ end
+
+ it 'builds a new issue' do
+ get :new, namespace_id: project.namespace.path, project_id: project
+
+ expect(assigns(:issue)).to be_a_new(Issue)
+ end
+
+ it 'fills in an issue for a merge request' do
+ project_with_repository = create(:project)
+ project_with_repository.team << [user, :developer]
+ mr = create(:merge_request_with_diff_notes, source_project: project_with_repository)
+
+ get :new, namespace_id: project_with_repository.namespace.path, project_id: project_with_repository, merge_request_for_resolving_discussions: mr.iid
+
+ expect(assigns(:issue).title).not_to be_empty
+ expect(assigns(:issue).description).not_to be_empty
+ end
+ end
+
context 'external issue tracker' do
it 'redirects to the external issue tracker' do
external = double(new_issue_path: 'https://example.com/issues/new')
@@ -272,6 +296,42 @@ describe Projects::IssuesController do
end
describe 'POST #create' do
+ context 'resolving discussions in MergeRequest' do
+ let(:discussion) { Discussion.for_diff_notes([create(:diff_note_on_merge_request)]).first }
+ let(:merge_request) { discussion.noteable }
+ let(:project) { merge_request.source_project }
+
+ before do
+ project.team << [user, :master]
+ sign_in user
+ end
+
+ let(:merge_request_params) do
+ { merge_request_for_resolving_discussions: merge_request.iid }
+ end
+
+ def post_issue(issue_params)
+ post :create, namespace_id: project.namespace.to_param, project_id: project.to_param, issue: issue_params, merge_request_for_resolving_discussions: merge_request.iid
+ end
+
+ it 'creates an issue for the project' do
+ expect { post_issue({ title: 'Hello' }) }.to change { project.issues.reload.size }.by(1)
+ end
+
+ it "doesn't overwrite given params" do
+ post_issue(description: 'Manually entered description')
+
+ expect(assigns(:issue).description).to eq('Manually entered description')
+ end
+
+ it 'resolves the discussion in the merge_request' do
+ post_issue(title: 'Hello')
+ discussion.first_note.reload
+
+ expect(discussion.resolved?).to eq(true)
+ end
+ end
+
context 'Akismet is enabled' do
before do
allow_any_instance_of(SpamService).to receive(:check_for_spam?).and_return(true)
diff --git a/spec/controllers/projects/merge_requests_controller_spec.rb b/spec/controllers/projects/merge_requests_controller_spec.rb
index 1d0750d1719..9e0b80205d8 100644
--- a/spec/controllers/projects/merge_requests_controller_spec.rb
+++ b/spec/controllers/projects/merge_requests_controller_spec.rb
@@ -292,7 +292,9 @@ describe Projects::MergeRequestsController do
it 'sets the MR to merge when the build succeeds' do
service = double(:merge_when_build_succeeds_service)
- expect(MergeRequests::MergeWhenBuildSucceedsService).to receive(:new).with(project, anything, anything).and_return(service)
+ expect(MergeRequests::MergeWhenPipelineSucceedsService)
+ .to receive(:new).with(project, anything, anything)
+ .and_return(service)
expect(service).to receive(:execute).with(merge_request)
merge_when_build_succeeds
diff --git a/spec/features/admin/admin_users_spec.rb b/spec/features/admin/admin_users_spec.rb
index cb3191dfdde..e31325ce47b 100644
--- a/spec/features/admin/admin_users_spec.rb
+++ b/spec/features/admin/admin_users_spec.rb
@@ -225,4 +225,32 @@ describe "Admin::Users", feature: true do
end
end
end
+
+ describe "GET /admin/users/:id/projects" do
+ before do
+ @group = create(:group)
+ @project = create(:project, group: @group)
+ @simple_user = create(:user)
+ @group.add_developer(@simple_user)
+
+ visit projects_admin_user_path(@simple_user)
+ end
+
+ it "lists group projects" do
+ within(:css, '.append-bottom-default + .panel') do
+ expect(page).to have_content 'Group projects'
+ expect(page).to have_link @group.name, admin_group_path(@group)
+ end
+ end
+
+ it 'allows navigation to the group details' do
+ within(:css, '.append-bottom-default + .panel') do
+ click_link @group.name
+ end
+ within(:css, 'h3.page-title') do
+ expect(page).to have_content "Group: #{@group.name}"
+ end
+ expect(page).to have_content @project.name
+ end
+ end
end
diff --git a/spec/features/commits_spec.rb b/spec/features/commits_spec.rb
index 44646ffc602..23a504ff965 100644
--- a/spec/features/commits_spec.rb
+++ b/spec/features/commits_spec.rb
@@ -177,4 +177,23 @@ describe 'Commits' do
end
end
end
+
+ context 'viewing commits for a branch' do
+ let(:branch_name) { 'master' }
+ let(:user) { create(:user) }
+
+ before do
+ project.team << [user, :master]
+ login_with(user)
+ visit namespace_project_commits_path(project.namespace, project, branch_name)
+ end
+
+ it 'includes the committed_date for each commit' do
+ commits = project.repository.commits(branch_name)
+
+ commits.each do |commit|
+ expect(page).to have_content("committed #{commit.committed_date}")
+ end
+ end
+ end
end
diff --git a/spec/features/groups/labels/edit_spec.rb b/spec/features/groups/labels/edit_spec.rb
new file mode 100644
index 00000000000..69281cecb7b
--- /dev/null
+++ b/spec/features/groups/labels/edit_spec.rb
@@ -0,0 +1,21 @@
+require 'spec_helper'
+
+feature 'Edit group label', feature: true do
+ given(:user) { create(:user) }
+ given(:group) { create(:group) }
+ given(:label) { create(:group_label, group: group) }
+
+ background do
+ group.add_owner(user)
+ login_as(user)
+ visit edit_group_label_path(group, label)
+ end
+
+ scenario 'update label with new title' do
+ fill_in 'label_title', with: 'new label name'
+ click_button 'Save changes'
+
+ expect(current_path).to eq(root_path)
+ expect(label.reload.title).to eq('new label name')
+ end
+end
diff --git a/spec/features/groups/merge_requests_spec.rb b/spec/features/groups/merge_requests_spec.rb
index a2791b57544..30b80aa82b0 100644
--- a/spec/features/groups/merge_requests_spec.rb
+++ b/spec/features/groups/merge_requests_spec.rb
@@ -2,7 +2,35 @@ require 'spec_helper'
feature 'Group merge requests page', feature: true do
let(:path) { merge_requests_group_path(group) }
- let(:issuable) { create(:merge_request, source_project: project, target_project: project, title: "this is my created issuable")}
+ let(:issuable) { create(:merge_request, source_project: project, target_project: project, title: 'this is my created issuable') }
include_examples 'project features apply to issuables', MergeRequest
+
+ context 'archived issuable' do
+ let(:project_archived) { create(:project, group: group, merge_requests_access_level: ProjectFeature::ENABLED, archived: true) }
+ let(:issuable_archived) { create(:merge_request, source_project: project_archived, target_project: project_archived, title: 'issuable of an archived project') }
+ let(:access_level) { ProjectFeature::ENABLED }
+ let(:user) { user_in_group }
+
+ before do
+ issuable_archived
+ visit path
+ end
+
+ it 'hides archived merge requests' do
+ expect(page).to have_content(issuable.title)
+ expect(page).not_to have_content(issuable_archived.title)
+ end
+
+ it 'ignores archived merge request count badges in navbar' do
+ expect( page.find('[title="Merge Requests"] span.badge.count').text).to eq("1")
+ end
+
+ it 'ignores archived merge request count badges in state-filters' do
+ expect(page.find('#state-opened span.badge').text).to eq("1")
+ expect(page.find('#state-merged span.badge').text).to eq("0")
+ expect(page.find('#state-closed span.badge').text).to eq("0")
+ expect(page.find('#state-all span.badge').text).to eq("1")
+ end
+ end
end
diff --git a/spec/features/issues/create_issue_for_discussions_in_merge_request_spec.rb b/spec/features/issues/create_issue_for_discussions_in_merge_request_spec.rb
new file mode 100644
index 00000000000..762cab0c0e1
--- /dev/null
+++ b/spec/features/issues/create_issue_for_discussions_in_merge_request_spec.rb
@@ -0,0 +1,76 @@
+require 'rails_helper'
+
+feature 'Resolving all open discussions in a merge request from an issue', feature: true do
+ 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 }
+
+ before do
+ project.team << [user, :master]
+ login_as user
+ end
+
+ context 'with the internal tracker disabled' do
+ before do
+ project.project_feature.update_attribute(:issues_access_level, ProjectFeature::DISABLED)
+ visit namespace_project_merge_request_path(project.namespace, project, merge_request)
+ end
+
+ it 'does not show a link to create a new issue' do
+ expect(page).not_to have_link 'open an issue to resolve them later'
+ end
+ end
+
+ context 'merge request has discussions that need to be resolved' do
+ before do
+ visit namespace_project_merge_request_path(project.namespace, project, merge_request)
+ end
+
+ it 'shows a warning that the merge request contains unresolved discussions' do
+ expect(page).to have_content 'This merge request has unresolved discussions'
+ end
+
+ it 'has a link to resolve all discussions by creating an issue' do
+ page.within '.mr-widget-body' do
+ expect(page).to have_link 'open an issue to resolve them later', href: new_namespace_project_issue_path(project.namespace, project, merge_request_for_resolving_discussions: merge_request.iid)
+ end
+ end
+
+ context 'creating an issue for discussions' do
+ before do
+ page.click_link 'open an issue to resolve them later', href: new_namespace_project_issue_path(project.namespace, project, merge_request_for_resolving_discussions: merge_request.iid)
+ end
+
+ it 'shows an issue with the title filled in' do
+ title_field = page.find_field('issue[title]')
+
+ expect(title_field.value).to include(merge_request.title)
+ end
+
+ it 'has a mention of the discussion in the description' do
+ description_field = page.find_field('issue[description]')
+
+ expect(description_field.value).to include(discussion.first_note.note)
+ end
+
+ it 'has a hidden field for the merge request' do
+ merge_request_field = find('#merge_request_for_resolving_discussions', visible: false)
+
+ expect(merge_request_field.value).to eq(merge_request.iid.to_s)
+ end
+
+ it 'can create a new issue for the project' do
+ expect { click_button 'Submit issue' }.to change { project.issues.reload.size }.by(1)
+ end
+
+ it 'resolves the discussion in the merge request' do
+ click_button 'Submit issue'
+
+ discussion.first_note.reload
+
+ expect(discussion.resolved?).to eq(true)
+ end
+ end
+ end
+end
diff --git a/spec/features/issues/move_spec.rb b/spec/features/issues/move_spec.rb
index c9bec05a9da..f89b4db9e62 100644
--- a/spec/features/issues/move_spec.rb
+++ b/spec/features/issues/move_spec.rb
@@ -28,7 +28,7 @@ feature 'issue move to another project' do
let(:new_project) { create(:project) }
let(:new_project_search) { create(:project) }
let(:text) { "Text with #{mr.to_reference}" }
- let(:cross_reference) { old_project.to_reference }
+ let(:cross_reference) { old_project.to_reference(new_project) }
background do
old_project.team << [user, :reporter]
diff --git a/spec/features/merge_requests/conflicts_spec.rb b/spec/features/merge_requests/conflicts_spec.rb
index d258ff52bbb..5bc4ab2dfe5 100644
--- a/spec/features/merge_requests/conflicts_spec.rb
+++ b/spec/features/merge_requests/conflicts_spec.rb
@@ -20,7 +20,7 @@ feature 'Merge request conflict resolution', js: true, feature: true do
within find('.files-wrapper .diff-file', text: 'files/ruby/regex.rb') do
all('button', text: 'Use ours').each do |button|
- button.click
+ button.trigger('click')
end
end
diff --git a/spec/features/merge_requests/create_new_mr_spec.rb b/spec/features/merge_requests/create_new_mr_spec.rb
index 702869b6e8b..f1b68a39343 100644
--- a/spec/features/merge_requests/create_new_mr_spec.rb
+++ b/spec/features/merge_requests/create_new_mr_spec.rb
@@ -40,7 +40,7 @@ feature 'Create New Merge Request', feature: true, js: true do
visit new_namespace_project_merge_request_path(project.namespace, project, merge_request: { target_project_id: private_project.id })
- expect(page).not_to have_content private_project.to_reference
+ expect(page).not_to have_content private_project.path_with_namespace
end
end
diff --git a/spec/features/merge_requests/deleted_source_branch_spec.rb b/spec/features/merge_requests/deleted_source_branch_spec.rb
index 778b3a90cf3..d5c9ed8a3b7 100644
--- a/spec/features/merge_requests/deleted_source_branch_spec.rb
+++ b/spec/features/merge_requests/deleted_source_branch_spec.rb
@@ -1,5 +1,8 @@
require 'spec_helper'
+# This test serves as a regression test for a bug that caused an error
+# 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
let(:user) { create(:user) }
let(:merge_request) { create(:merge_request) }
diff --git a/spec/features/merge_requests/merge_when_build_succeeds_spec.rb b/spec/features/merge_requests/merge_when_pipeline_succeeds_spec.rb
index 9ad225e3a1b..aa24a905001 100644
--- a/spec/features/merge_requests/merge_when_build_succeeds_spec.rb
+++ b/spec/features/merge_requests/merge_when_pipeline_succeeds_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-feature 'Merge When Build Succeeds', feature: true, js: true do
+feature 'Merge When Pipeline Succeeds', :feature, :js do
let(:user) { create(:user) }
let(:project) { create(:project, :public) }
@@ -18,7 +18,7 @@ feature 'Merge When Build Succeeds', feature: true, js: true do
before { project.team << [user, :master] }
- context 'when there is active build for merge request' do
+ context 'when there is active pipeline for merge request' do
background do
create(:ci_build, pipeline: pipeline)
end
@@ -28,28 +28,28 @@ feature 'Merge When Build Succeeds', feature: true, js: true do
visit_merge_request(merge_request)
end
- it 'displays the Merge When Build Succeeds button' do
- expect(page).to have_button "Merge When Build Succeeds"
+ it 'displays the Merge When Pipeline Succeeds button' do
+ expect(page).to have_button "Merge When Pipeline Succeeds"
end
- context "Merge When Build succeeds enabled" do
+ context "Merge When Pipeline Succeeds enabled" do
before do
- click_button "Merge When Build Succeeds"
+ click_button "Merge When Pipeline Succeeds"
end
- it 'activates Merge When Build Succeeds feature' do
+ it 'activates Merge When Pipeline Succeeds feature' do
expect(page).to have_link "Cancel Automatic Merge"
- expect(page).to have_content "Set by #{user.name} to be merged automatically when the build succeeds."
+ expect(page).to have_content "Set by #{user.name} to be merged automatically when the pipeline succeeds."
expect(page).to have_content "The source branch will not be removed."
visit_merge_request(merge_request) # Needed to refresh the page
- expect(page).to have_content /enabled an automatic merge when the build for \h{8} succeeds/i
+ expect(page).to have_content /enabled an automatic merge when the pipeline for \h{8} succeeds/i
end
end
end
- context 'when merge when build succeeds is enabled' do
+ context 'when merge when pipeline succeeds is enabled' do
let(:merge_request) do
create(:merge_request_with_diffs, :simple, source_project: project,
author: user,
@@ -70,7 +70,7 @@ feature 'Merge When Build Succeeds', feature: true, js: true do
it 'allows to cancel the automatic merge' do
click_link "Cancel Automatic Merge"
- expect(page).to have_button "Merge When Build Succeeds"
+ expect(page).to have_button "Merge When Pipeline Succeeds"
visit_merge_request(merge_request) # refresh the page
expect(page).to have_content "canceled the automatic merge"
@@ -83,7 +83,7 @@ feature 'Merge When Build Succeeds', feature: true, js: true do
expect(page).to have_content "The source branch will be removed"
end
- context 'when build succeeds' do
+ context 'when pipeline succeeds' do
background { build.success }
it 'merges merge request' do
@@ -95,10 +95,11 @@ feature 'Merge When Build Succeeds', feature: true, js: true do
end
end
- context 'when build is not active' do
- it "does not allow to enable merge when build succeeds" do
+ context 'when pipeline is not active' do
+ it "does not allow to enable merge when pipeline succeeds" do
visit_merge_request(merge_request)
- expect(page).not_to have_link "Merge When Build Succeeds"
+
+ expect(page).not_to have_link 'Merge When Pipeline Succeeds'
end
end
diff --git a/spec/features/merge_requests/only_allow_merge_if_build_succeeds_spec.rb b/spec/features/merge_requests/only_allow_merge_if_build_succeeds_spec.rb
index 1ec3103feef..7e2907cd26f 100644
--- a/spec/features/merge_requests/only_allow_merge_if_build_succeeds_spec.rb
+++ b/spec/features/merge_requests/only_allow_merge_if_build_succeeds_spec.rb
@@ -38,7 +38,7 @@ feature 'Only allow merge requests to be merged if the build succeeds', feature:
it 'does not allow to merge immediately' do
visit_merge_request(merge_request)
- expect(page).to have_button 'Merge When Build Succeeds'
+ expect(page).to have_button 'Merge When Pipeline Succeeds'
expect(page).not_to have_button 'Select Merge Moment'
end
end
@@ -97,7 +97,7 @@ feature 'Only allow merge requests to be merged if the build succeeds', feature:
it 'allows MR to be merged immediately', js: true do
visit_merge_request(merge_request)
- expect(page).to have_button 'Merge When Build Succeeds'
+ expect(page).to have_button 'Merge When Pipeline Succeeds'
click_button 'Select Merge Moment'
expect(page).to have_content 'Merge Immediately'
diff --git a/spec/features/projects/guest_navigation_menu_spec.rb b/spec/features/projects/guest_navigation_menu_spec.rb
index c22441f8929..8120a51c515 100644
--- a/spec/features/projects/guest_navigation_menu_spec.rb
+++ b/spec/features/projects/guest_navigation_menu_spec.rb
@@ -1,8 +1,8 @@
require 'spec_helper'
describe "Guest navigation menu" do
- let(:project) { create :empty_project, :private }
- let(:guest) { create :user }
+ let(:project) { create(:empty_project, :private, public_builds: false) }
+ let(:guest) { create(:user) }
before do
project.team << [guest, :guest]
diff --git a/spec/features/security/project/private_access_spec.rb b/spec/features/security/project/private_access_spec.rb
index 290ddb4c6dd..f52e23f9433 100644
--- a/spec/features/security/project/private_access_spec.rb
+++ b/spec/features/security/project/private_access_spec.rb
@@ -3,7 +3,7 @@ require 'spec_helper'
describe "Private Project Access", feature: true do
include AccessMatchers
- let(:project) { create(:project, :private) }
+ let(:project) { create(:project, :private, public_builds: false) }
describe "Project should be private" do
describe '#private?' do
@@ -260,6 +260,18 @@ describe "Private Project Access", feature: true do
it { is_expected.to be_denied_for(:user) }
it { is_expected.to be_denied_for(:external) }
it { is_expected.to be_denied_for(:visitor) }
+
+ context 'when public builds is enabled' do
+ before do
+ project.update(public_builds: true)
+ end
+
+ it { is_expected.to be_allowed_for(:guest).of(project) }
+ end
+
+ context 'when public buils are disabled' do
+ it { is_expected.to be_denied_for(:guest).of(project) }
+ end
end
describe "GET /:project_path/pipelines/:id" do
@@ -275,6 +287,18 @@ describe "Private Project Access", feature: true do
it { is_expected.to be_denied_for(:user) }
it { is_expected.to be_denied_for(:external) }
it { is_expected.to be_denied_for(:visitor) }
+
+ context 'when public builds is enabled' do
+ before do
+ project.update(public_builds: true)
+ end
+
+ it { is_expected.to be_allowed_for(:guest).of(project) }
+ end
+
+ context 'when public buils are disabled' do
+ it { is_expected.to be_denied_for(:guest).of(project) }
+ end
end
describe "GET /:project_path/builds" do
@@ -289,6 +313,18 @@ describe "Private Project Access", feature: true do
it { is_expected.to be_denied_for(:user) }
it { is_expected.to be_denied_for(:external) }
it { is_expected.to be_denied_for(:visitor) }
+
+ context 'when public builds is enabled' do
+ before do
+ project.update(public_builds: true)
+ end
+
+ it { is_expected.to be_allowed_for(:guest).of(project) }
+ end
+
+ context 'when public buils are disabled' do
+ it { is_expected.to be_denied_for(:guest).of(project) }
+ end
end
describe "GET /:project_path/builds/:id" do
@@ -305,6 +341,23 @@ describe "Private Project Access", feature: true do
it { is_expected.to be_denied_for(:user) }
it { is_expected.to be_denied_for(:external) }
it { is_expected.to be_denied_for(:visitor) }
+
+ context 'when public builds is enabled' do
+ before do
+ project.update(public_builds: true)
+ end
+
+ it { is_expected.to be_allowed_for(:guest).of(project) }
+ end
+
+ context 'when public buils are disabled' do
+ before do
+ project.public_builds = false
+ project.save
+ end
+
+ it { is_expected.to be_denied_for(:guest).of(project) }
+ end
end
describe "GET /:project_path/environments" do
diff --git a/spec/finders/issues_finder_spec.rb b/spec/finders/issues_finder_spec.rb
index 40bccb8e50b..7f69e888f32 100644
--- a/spec/finders/issues_finder_spec.rb
+++ b/spec/finders/issues_finder_spec.rb
@@ -10,6 +10,7 @@ describe IssuesFinder do
let(:issue1) { create(:issue, author: user, assignee: user, project: project1, milestone: milestone, title: 'gitlab') }
let(:issue2) { create(:issue, author: user, assignee: user, project: project2, description: 'gitlab') }
let(:issue3) { create(:issue, author: user2, assignee: user2, project: project2) }
+ let(:closed_issue) { create(:issue, author: user2, assignee: user2, project: project2, state: 'closed') }
let!(:label_link) { create(:label_link, label: label, target: issue2) }
before do
@@ -25,7 +26,7 @@ describe IssuesFinder do
describe '#execute' do
let(:search_user) { user }
let(:params) { {} }
- let(:issues) { IssuesFinder.new(search_user, params.merge(scope: scope, state: 'opened')).execute }
+ let(:issues) { IssuesFinder.new(search_user, params.reverse_merge(scope: scope, state: 'opened')).execute }
context 'scope: all' do
let(:scope) { 'all' }
@@ -143,6 +144,40 @@ describe IssuesFinder do
end
end
+ context 'filtering by state' do
+ context 'with opened' do
+ let(:params) { { state: 'opened' } }
+
+ it 'returns only opened issues' do
+ expect(issues).to contain_exactly(issue1, issue2, issue3)
+ end
+ end
+
+ context 'with closed' do
+ let(:params) { { state: 'closed' } }
+
+ it 'returns only closed issues' do
+ expect(issues).to contain_exactly(closed_issue)
+ end
+ end
+
+ context 'with all' do
+ let(:params) { { state: 'all' } }
+
+ it 'returns all issues' do
+ expect(issues).to contain_exactly(issue1, issue2, issue3, closed_issue)
+ end
+ end
+
+ context 'with invalid state' do
+ let(:params) { { state: 'invalid_state' } }
+
+ it 'returns all issues' do
+ expect(issues).to contain_exactly(issue1, issue2, issue3, closed_issue)
+ end
+ end
+ end
+
context 'when the user is unauthorized' do
let(:search_user) { nil }
diff --git a/spec/finders/merge_requests_finder_spec.rb b/spec/finders/merge_requests_finder_spec.rb
index 535aabfc18d..88361e27102 100644
--- a/spec/finders/merge_requests_finder_spec.rb
+++ b/spec/finders/merge_requests_finder_spec.rb
@@ -6,14 +6,17 @@ describe MergeRequestsFinder do
let(:project1) { create(:project) }
let(:project2) { create(:project, forked_from_project: project1) }
+ let(:project3) { create(:project, forked_from_project: project1, archived: true) }
let!(:merge_request1) { create(:merge_request, :simple, author: user, source_project: project2, target_project: project1) }
let!(:merge_request2) { create(:merge_request, :simple, author: user, source_project: project2, target_project: project1, state: 'closed') }
let!(:merge_request3) { create(:merge_request, :simple, author: user, source_project: project2, target_project: project2) }
+ let!(:merge_request4) { create(:merge_request, :simple, author: user, source_project: project3, target_project: project3) }
before do
project1.team << [user, :master]
project2.team << [user, :developer]
+ project3.team << [user, :developer]
project2.team << [user2, :developer]
end
@@ -21,7 +24,7 @@ describe MergeRequestsFinder do
it 'filters by scope' do
params = { scope: 'authored', state: 'opened' }
merge_requests = MergeRequestsFinder.new(user, params).execute
- expect(merge_requests.size).to eq(2)
+ expect(merge_requests.size).to eq(3)
end
it 'filters by project' do
@@ -29,5 +32,11 @@ describe MergeRequestsFinder do
merge_requests = MergeRequestsFinder.new(user, params).execute
expect(merge_requests.size).to eq(1)
end
+
+ it 'filters by non_archived' do
+ params = { non_archived: true }
+ merge_requests = MergeRequestsFinder.new(user, params).execute
+ expect(merge_requests.size).to eq(3)
+ end
end
end
diff --git a/spec/helpers/labels_helper_spec.rb b/spec/helpers/labels_helper_spec.rb
index d30daf47543..7cf535fadae 100644
--- a/spec/helpers/labels_helper_spec.rb
+++ b/spec/helpers/labels_helper_spec.rb
@@ -7,7 +7,7 @@ describe LabelsHelper do
context 'without subject' do
it "uses the label's project" do
- expect(link_to_label(label)).to match %r{<a href="/#{label.project.to_reference}/issues\?label_name%5B%5D=#{label.name}">.*</a>}
+ expect(link_to_label(label)).to match %r{<a href="/#{label.project.path_with_namespace}/issues\?label_name%5B%5D=#{label.name}">.*</a>}
end
end
@@ -32,7 +32,7 @@ describe LabelsHelper do
['issue', :issue, 'merge_request', :merge_request].each do |type|
context "set to #{type}" do
it 'links to correct page' do
- expect(link_to_label(label, type: type)).to match %r{<a href="/#{label.project.to_reference}/#{type.to_s.pluralize}\?label_name%5B%5D=#{label.name}">.*</a>}
+ expect(link_to_label(label, type: type)).to match %r{<a href="/#{label.project.path_with_namespace}/#{type.to_s.pluralize}\?label_name%5B%5D=#{label.name}">.*</a>}
end
end
end
diff --git a/spec/javascripts/application_spec.js b/spec/javascripts/application_spec.js
deleted file mode 100644
index 7e38abc608e..00000000000
--- a/spec/javascripts/application_spec.js
+++ /dev/null
@@ -1,37 +0,0 @@
-/* eslint-disable space-before-function-paren, one-var, no-var, one-var-declaration-per-line, no-return-assign, padded-blocks, max-len */
-
-/*= require lib/utils/common_utils */
-
-(function() {
- describe('Application', function() {
- return describe('disable buttons', function() {
- fixture.preload('application.html');
- beforeEach(function() {
- return fixture.load('application.html');
- });
- it('should prevent default action for disabled buttons', function() {
- var $button, isClicked;
- gl.utils.preventDisabledButtons();
- isClicked = false;
- $button = $('#test-button');
- expect($button).toExist();
- $button.click(function() {
- return isClicked = true;
- });
- $button.trigger('click');
- return expect(isClicked).toBe(false);
- });
-
- it('should be on the same page if a disabled link clicked', function() {
- var locationBeforeLinkClick, $link;
- locationBeforeLinkClick = window.location.href;
- gl.utils.preventDisabledButtons();
- $link = $('#test-link');
- expect($link).toExist();
- $link.click();
- return expect(window.location.href).toBe(locationBeforeLinkClick);
- });
- });
- });
-
-}).call(this);
diff --git a/spec/javascripts/bootstrap_linked_tabs_spec.js.es6 b/spec/javascripts/bootstrap_linked_tabs_spec.js.es6
index 9aa3c50611d..133712debab 100644
--- a/spec/javascripts/bootstrap_linked_tabs_spec.js.es6
+++ b/spec/javascripts/bootstrap_linked_tabs_spec.js.es6
@@ -9,6 +9,10 @@
});
describe('when is initialized', () => {
+ beforeEach(() => {
+ spyOn(window.history, 'replaceState').and.callFake(function () {});
+ });
+
it('should activate the tab correspondent to the given action', () => {
const linkedTabs = new window.gl.LinkedTabs({ // eslint-disable-line
action: 'tab1',
diff --git a/spec/javascripts/extensions/element_spec.js.es6 b/spec/javascripts/extensions/element_spec.js.es6
new file mode 100644
index 00000000000..c5b86d35204
--- /dev/null
+++ b/spec/javascripts/extensions/element_spec.js.es6
@@ -0,0 +1,38 @@
+/*= require extensions/element */
+
+(() => {
+ describe('Element extensions', function () {
+ beforeEach(() => {
+ this.element = document.createElement('ul');
+ });
+
+ describe('matches', () => {
+ it('returns true if element matches the selector', () => {
+ expect(this.element.matches('ul')).toBeTruthy();
+ });
+
+ it("returns false if element doesn't match the selector", () => {
+ expect(this.element.matches('.not-an-element')).toBeFalsy();
+ });
+ });
+
+ describe('closest', () => {
+ beforeEach(() => {
+ this.childElement = document.createElement('li');
+ this.element.appendChild(this.childElement);
+ });
+
+ it('returns the closest parent that matches the selector', () => {
+ expect(this.childElement.closest('ul').toString()).toBe(this.element.toString());
+ });
+
+ it('returns itself if it matches the selector', () => {
+ expect(this.childElement.closest('li').toString()).toBe(this.childElement.toString());
+ });
+
+ it('returns undefined if nothing matches the selector', () => {
+ expect(this.childElement.closest('.no-an-element')).toBeFalsy();
+ });
+ });
+ });
+})();
diff --git a/spec/javascripts/fixtures/application.html.haml b/spec/javascripts/fixtures/application.html.haml
deleted file mode 100644
index 3fc6114407d..00000000000
--- a/spec/javascripts/fixtures/application.html.haml
+++ /dev/null
@@ -1,2 +0,0 @@
-%a#test-link.btn.disabled{:href => "/foo"} Test link
-%button#test-button.btn.disabled Test Button
diff --git a/spec/javascripts/lib/utils/common_utils_spec.js.es6 b/spec/javascripts/lib/utils/common_utils_spec.js.es6
new file mode 100644
index 00000000000..ef75f600898
--- /dev/null
+++ b/spec/javascripts/lib/utils/common_utils_spec.js.es6
@@ -0,0 +1,32 @@
+//= require lib/utils/common_utils
+
+(() => {
+ describe('common_utils', () => {
+ describe('gl.utils.parseUrl', () => {
+ it('returns an anchor tag with url', () => {
+ expect(gl.utils.parseUrl('/some/absolute/url').pathname).toContain('some/absolute/url');
+ });
+ it('url is escaped', () => {
+ // IE11 will return a relative pathname while other browsers will return a full pathname.
+ // parseUrl uses an anchor element for parsing an url. With relative urls, the anchor
+ // element will create an absolute url relative to the current execution context.
+ // The JavaScript test suite is executed at '/teaspoon' which will lead to an absolute
+ // url starting with '/teaspoon'.
+ expect(gl.utils.parseUrl('" test="asf"').pathname).toEqual('/teaspoon/%22%20test=%22asf%22');
+ });
+ });
+ describe('gl.utils.parseUrlPathname', () => {
+ beforeEach(() => {
+ spyOn(gl.utils, 'parseUrl').and.callFake(url => ({
+ pathname: url,
+ }));
+ });
+ it('returns an absolute url when given an absolute url', () => {
+ expect(gl.utils.parseUrlPathname('/some/absolute/url')).toEqual('/some/absolute/url');
+ });
+ it('returns an absolute url when given a relative url', () => {
+ expect(gl.utils.parseUrlPathname('some/relative/url')).toEqual('/some/relative/url');
+ });
+ });
+ });
+})();
diff --git a/spec/javascripts/merge_request_tabs_spec.js b/spec/javascripts/merge_request_tabs_spec.js
index 971222c44e1..130d391bfab 100644
--- a/spec/javascripts/merge_request_tabs_spec.js
+++ b/spec/javascripts/merge_request_tabs_spec.js
@@ -1,108 +1,122 @@
-/* eslint-disable space-before-function-paren, no-var, comma-dangle, dot-notation, quotes, no-undef, no-return-assign, no-underscore-dangle, camelcase, padded-blocks, max-len */
+/* eslint-disable no-var, comma-dangle, object-shorthand */
/*= require merge_request_tabs */
//= require breakpoints
+//= require lib/utils/common_utils
+//= require jquery.scrollTo
-(function() {
- describe('MergeRequestTabs', function() {
- var stubLocation;
- stubLocation = function(stubs) {
- var defaults;
- defaults = {
+(function () {
+ describe('MergeRequestTabs', function () {
+ var stubLocation = {};
+ var setLocation = function (stubs) {
+ var defaults = {
pathname: '',
search: '',
hash: ''
};
- return $.extend(defaults, stubs);
+ $.extend(stubLocation, defaults, stubs || {});
};
fixture.preload('merge_request_tabs.html');
- beforeEach(function() {
- this["class"] = new MergeRequestTabs();
- return this.spies = {
- ajax: spyOn($, 'ajax').and.callFake(function() {}),
- history: spyOn(history, 'replaceState').and.callFake(function() {})
+
+ beforeEach(function () {
+ this.class = new gl.MergeRequestTabs({ stubLocation: stubLocation });
+ setLocation();
+
+ this.spies = {
+ history: spyOn(window.history, 'replaceState').and.callFake(function () {})
};
});
- describe('#activateTab', function() {
- beforeEach(function() {
+
+ describe('#activateTab', function () {
+ beforeEach(function () {
+ spyOn($, 'ajax').and.callFake(function () {});
fixture.load('merge_request_tabs.html');
- return this.subject = this["class"].activateTab;
+ this.subject = this.class.activateTab;
});
- it('shows the first tab when action is show', function() {
+ it('shows the first tab when action is show', function () {
this.subject('show');
- return expect($('#notes')).toHaveClass('active');
+ expect($('#notes')).toHaveClass('active');
});
- it('shows the notes tab when action is notes', function() {
+ it('shows the notes tab when action is notes', function () {
this.subject('notes');
- return expect($('#notes')).toHaveClass('active');
+ expect($('#notes')).toHaveClass('active');
});
- it('shows the commits tab when action is commits', function() {
+ it('shows the commits tab when action is commits', function () {
this.subject('commits');
- return expect($('#commits')).toHaveClass('active');
+ expect($('#commits')).toHaveClass('active');
});
- return it('shows the diffs tab when action is diffs', function() {
+ it('shows the diffs tab when action is diffs', function () {
this.subject('diffs');
- return expect($('#diffs')).toHaveClass('active');
+ expect($('#diffs')).toHaveClass('active');
});
});
- return describe('#setCurrentAction', function() {
- beforeEach(function() {
- return this.subject = this["class"].setCurrentAction;
+
+ describe('#setCurrentAction', function () {
+ beforeEach(function () {
+ spyOn($, 'ajax').and.callFake(function () {});
+ this.subject = this.class.setCurrentAction;
});
- it('changes from commits', function() {
- this["class"]._location = stubLocation({
+ it('changes from commits', function () {
+ setLocation({
pathname: '/foo/bar/merge_requests/1/commits'
});
expect(this.subject('notes')).toBe('/foo/bar/merge_requests/1');
- return expect(this.subject('diffs')).toBe('/foo/bar/merge_requests/1/diffs');
+ expect(this.subject('diffs')).toBe('/foo/bar/merge_requests/1/diffs');
});
- it('changes from diffs', function() {
- this["class"]._location = stubLocation({
+ it('changes from diffs', function () {
+ setLocation({
pathname: '/foo/bar/merge_requests/1/diffs'
});
expect(this.subject('notes')).toBe('/foo/bar/merge_requests/1');
- return expect(this.subject('commits')).toBe('/foo/bar/merge_requests/1/commits');
+ expect(this.subject('commits')).toBe('/foo/bar/merge_requests/1/commits');
});
- it('changes from diffs.html', function() {
- this["class"]._location = stubLocation({
+ it('changes from diffs.html', function () {
+ setLocation({
pathname: '/foo/bar/merge_requests/1/diffs.html'
});
expect(this.subject('notes')).toBe('/foo/bar/merge_requests/1');
- return expect(this.subject('commits')).toBe('/foo/bar/merge_requests/1/commits');
+ expect(this.subject('commits')).toBe('/foo/bar/merge_requests/1/commits');
});
- it('changes from notes', function() {
- this["class"]._location = stubLocation({
+ it('changes from notes', function () {
+ setLocation({
pathname: '/foo/bar/merge_requests/1'
});
expect(this.subject('diffs')).toBe('/foo/bar/merge_requests/1/diffs');
- return expect(this.subject('commits')).toBe('/foo/bar/merge_requests/1/commits');
+ expect(this.subject('commits')).toBe('/foo/bar/merge_requests/1/commits');
});
- it('includes search parameters and hash string', function() {
- this["class"]._location = stubLocation({
+ it('includes search parameters and hash string', function () {
+ setLocation({
pathname: '/foo/bar/merge_requests/1/diffs',
search: '?view=parallel',
hash: '#L15-35'
});
- return expect(this.subject('show')).toBe('/foo/bar/merge_requests/1?view=parallel#L15-35');
+ expect(this.subject('show')).toBe('/foo/bar/merge_requests/1?view=parallel#L15-35');
});
- it('replaces the current history state', function() {
- var new_state;
- this["class"]._location = stubLocation({
+ it('replaces the current history state', function () {
+ var newState;
+ setLocation({
pathname: '/foo/bar/merge_requests/1'
});
- new_state = this.subject('commits');
- return expect(this.spies.history).toHaveBeenCalledWith({
+ newState = this.subject('commits');
+ expect(this.spies.history).toHaveBeenCalledWith({
turbolinks: true,
- url: new_state
- }, document.title, new_state);
+ url: newState
+ }, document.title, newState);
});
- return it('treats "show" like "notes"', function() {
- this["class"]._location = stubLocation({
+ it('treats "show" like "notes"', function () {
+ setLocation({
pathname: '/foo/bar/merge_requests/1/commits'
});
- return expect(this.subject('show')).toBe('/foo/bar/merge_requests/1');
+ expect(this.subject('show')).toBe('/foo/bar/merge_requests/1');
+ });
+ });
+ describe('#loadDiff', function () {
+ it('requires an absolute pathname', function () {
+ spyOn($, 'ajax').and.callFake(function (options) {
+ expect(options.url).toEqual('/foo/bar/merge_requests/1/diffs.json');
+ });
+ this.class.loadDiff('/foo/bar/merge_requests/1/diffs');
});
});
});
-
}).call(this);
diff --git a/spec/javascripts/vue_common_components/commit_spec.js.es6 b/spec/javascripts/vue_common_components/commit_spec.js.es6
index b1dbc8bd5fa..d170517dd9b 100644
--- a/spec/javascripts/vue_common_components/commit_spec.js.es6
+++ b/spec/javascripts/vue_common_components/commit_spec.js.es6
@@ -10,7 +10,7 @@ describe('Commit component', () => {
el: document.querySelector('.test-commit-container'),
propsData: {
tag: false,
- ref: {
+ commit_ref: {
name: 'master',
ref_url: 'http://localhost/namespace2/gitlabhq/tree/master',
},
@@ -34,7 +34,7 @@ describe('Commit component', () => {
props = {
tag: true,
- ref: {
+ commit_ref: {
name: 'master',
ref_url: 'http://localhost/namespace2/gitlabhq/tree/master',
},
@@ -59,11 +59,11 @@ describe('Commit component', () => {
});
it('should render a link to the ref url', () => {
- expect(component.$el.querySelector('.branch-name').getAttribute('href')).toEqual(props.ref.ref_url);
+ expect(component.$el.querySelector('.branch-name').getAttribute('href')).toEqual(props.commit_ref.ref_url);
});
it('should render the ref name', () => {
- expect(component.$el.querySelector('.branch-name').textContent).toContain(props.ref.name);
+ expect(component.$el.querySelector('.branch-name').textContent).toContain(props.commit_ref.name);
});
it('should render the commit short sha with a link to the commit url', () => {
@@ -103,7 +103,7 @@ describe('Commit component', () => {
fixture.set('<div class="test-commit-container"></div>');
props = {
tag: false,
- ref: {
+ commit_ref: {
name: 'master',
ref_url: 'http://localhost/namespace2/gitlabhq/tree/master',
},
diff --git a/spec/lib/banzai/filter/abstract_link_filter_spec.rb b/spec/lib/banzai/filter/abstract_link_filter_spec.rb
index 1ee31a603e4..70a87fbc01e 100644
--- a/spec/lib/banzai/filter/abstract_link_filter_spec.rb
+++ b/spec/lib/banzai/filter/abstract_link_filter_spec.rb
@@ -5,7 +5,7 @@ describe Banzai::Filter::AbstractReferenceFilter do
describe '#references_per_project' do
it 'returns a Hash containing references grouped per project paths' do
- doc = Nokogiri::HTML.fragment("#1 #{project.to_reference}#2")
+ doc = Nokogiri::HTML.fragment("#1 #{project.path_with_namespace}#2")
filter = described_class.new(doc, project: project)
expect(filter).to receive(:object_class).exactly(4).times.and_return(Issue)
@@ -14,7 +14,7 @@ describe Banzai::Filter::AbstractReferenceFilter do
refs = filter.references_per_project
expect(refs).to be_an_instance_of(Hash)
- expect(refs[project.to_reference]).to eq(Set.new(%w[1 2]))
+ expect(refs[project.path_with_namespace]).to eq(Set.new(%w[1 2]))
end
end
diff --git a/spec/lib/banzai/filter/commit_range_reference_filter_spec.rb b/spec/lib/banzai/filter/commit_range_reference_filter_spec.rb
index e6c90ad87ee..9703e2315b8 100644
--- a/spec/lib/banzai/filter/commit_range_reference_filter_spec.rb
+++ b/spec/lib/banzai/filter/commit_range_reference_filter_spec.rb
@@ -59,9 +59,7 @@ describe Banzai::Filter::CommitRangeReferenceFilter, lib: true do
it 'ignores invalid commit IDs' do
exp = act = "See #{commit1.id.reverse}...#{commit2.id}"
- expect(project).to receive(:valid_repo?).and_return(true)
- expect(project.repository).to receive(:commit).with(commit1.id.reverse)
- expect(project.repository).to receive(:commit).with(commit2.id)
+ allow(project.repository).to receive(:commit).with(commit1.id.reverse)
expect(reference_filter(act).to_html).to eq exp
end
@@ -100,14 +98,44 @@ describe Banzai::Filter::CommitRangeReferenceFilter, lib: true do
end
end
- context 'cross-project reference' do
- let(:namespace) { create(:namespace, name: 'cross-reference') }
- let(:project2) { create(:project, :public, namespace: namespace) }
- let(:reference) { range.to_reference(project) }
+ context 'cross-project / cross-namespace complete reference' do
+ let(:project2) { create(:project, :public) }
+ let(:reference) { "#{project2.path_with_namespace}@#{commit1.id}...#{commit2.id}" }
- before do
- range.project = project2
+ it 'links to a valid reference' do
+ doc = reference_filter("See #{reference}")
+
+ expect(doc.css('a').first.attr('href')).
+ to eq urls.namespace_project_compare_url(project2.namespace, project2, range.to_param)
+ end
+
+ it 'link has valid text' do
+ doc = reference_filter("Fixed (#{reference}.)")
+
+ expect(doc.css('a').first.text).
+ to eql("#{project2.path_with_namespace}@#{commit1.short_id}...#{commit2.short_id}")
+ end
+
+ it 'has valid text' do
+ doc = reference_filter("Fixed (#{reference}.)")
+
+ expect(doc.text).to eql("Fixed (#{project2.path_with_namespace}@#{commit1.short_id}...#{commit2.short_id}.)")
+ end
+
+ it 'ignores invalid commit IDs on the referenced project' do
+ exp = act = "Fixed #{project2.path_with_namespace}@#{commit1.id.reverse}...#{commit2.id}"
+ expect(reference_filter(act).to_html).to eq exp
+
+ exp = act = "Fixed #{project2.path_with_namespace}@#{commit1.id}...#{commit2.id.reverse}"
+ expect(reference_filter(act).to_html).to eq exp
end
+ end
+
+ context 'cross-project / same-namespace complete reference' do
+ let(:namespace) { create(:namespace) }
+ let(:project) { create(:project, :public, namespace: namespace) }
+ let(:project2) { create(:project, :public, path: "same-namespace", namespace: namespace) }
+ let(:reference) { "#{project2.path}@#{commit1.id}...#{commit2.id}" }
it 'links to a valid reference' do
doc = reference_filter("See #{reference}")
@@ -116,24 +144,65 @@ describe Banzai::Filter::CommitRangeReferenceFilter, lib: true do
to eq urls.namespace_project_compare_url(project2.namespace, project2, range.to_param)
end
- it 'links with adjacent text' do
+ it 'link has valid text' do
doc = reference_filter("Fixed (#{reference}.)")
- exp = Regexp.escape("#{project2.to_reference}@#{range.reference_link_text}")
- expect(doc.to_html).to match(/\(<a.+>#{exp}<\/a>\.\)/)
+ expect(doc.css('a').first.text).
+ to eql("#{project2.path}@#{commit1.short_id}...#{commit2.short_id}")
+ end
+
+ it 'has valid text' do
+ doc = reference_filter("Fixed (#{reference}.)")
+
+ expect(doc.text).to eql("Fixed (#{project2.path}@#{commit1.short_id}...#{commit2.short_id}.)")
end
it 'ignores invalid commit IDs on the referenced project' do
- exp = act = "Fixed #{project2.to_reference}@#{commit1.id.reverse}...#{commit2.id}"
+ exp = act = "Fixed #{project2.path}@#{commit1.id.reverse}...#{commit2.id}"
expect(reference_filter(act).to_html).to eq exp
- exp = act = "Fixed #{project2.to_reference}@#{commit1.id}...#{commit2.id.reverse}"
+ exp = act = "Fixed #{project2.path}@#{commit1.id}...#{commit2.id.reverse}"
+ expect(reference_filter(act).to_html).to eq exp
+ end
+ end
+
+ context 'cross-project shorthand reference' do
+ let(:namespace) { create(:namespace) }
+ let(:project) { create(:project, :public, namespace: namespace) }
+ let(:project2) { create(:project, :public, path: "same-namespace", namespace: namespace) }
+ let(:reference) { "#{project2.path}@#{commit1.id}...#{commit2.id}" }
+
+ it 'links to a valid reference' do
+ doc = reference_filter("See #{reference}")
+
+ expect(doc.css('a').first.attr('href')).
+ to eq urls.namespace_project_compare_url(project2.namespace, project2, range.to_param)
+ end
+
+ it 'link has valid text' do
+ doc = reference_filter("Fixed (#{reference}.)")
+
+ expect(doc.css('a').first.text).
+ to eql("#{project2.path}@#{commit1.short_id}...#{commit2.short_id}")
+ end
+
+ it 'has valid text' do
+ doc = reference_filter("Fixed (#{reference}.)")
+
+ expect(doc.text).to eql("Fixed (#{project2.path}@#{commit1.short_id}...#{commit2.short_id}.)")
+ end
+
+ it 'ignores invalid commit IDs on the referenced project' do
+ exp = act = "Fixed #{project2.path}@#{commit1.id.reverse}...#{commit2.id}"
+ expect(reference_filter(act).to_html).to eq exp
+
+ exp = act = "Fixed #{project2.path}@#{commit1.id}...#{commit2.id.reverse}"
expect(reference_filter(act).to_html).to eq exp
end
end
context 'cross-project URL reference' do
- let(:namespace) { create(:namespace, name: 'cross-reference') }
+ let(:namespace) { create(:namespace) }
let(:project2) { create(:project, :public, namespace: namespace) }
let(:range) { CommitRange.new("#{commit1.id}...master", project) }
let(:reference) { urls.namespace_project_compare_url(project2.namespace, project2, from: commit1.id, to: 'master') }
diff --git a/spec/lib/banzai/filter/commit_reference_filter_spec.rb b/spec/lib/banzai/filter/commit_reference_filter_spec.rb
index e0f08282551..2e6dcc3a434 100644
--- a/spec/lib/banzai/filter/commit_reference_filter_spec.rb
+++ b/spec/lib/banzai/filter/commit_reference_filter_spec.rb
@@ -41,6 +41,7 @@ describe Banzai::Filter::CommitReferenceFilter, lib: true do
it 'links with adjacent text' do
doc = reference_filter("See (#{reference}.)")
+
expect(doc.to_html).to match(/\(<a.+>#{commit.short_id}<\/a>\.\)/)
end
@@ -48,8 +49,6 @@ describe Banzai::Filter::CommitReferenceFilter, lib: true do
invalid = invalidate_reference(reference)
exp = act = "See #{invalid}"
- expect(project).to receive(:valid_repo?).and_return(true)
- expect(project.repository).to receive(:commit).with(invalid)
expect(reference_filter(act).to_html).to eq exp
end
@@ -95,34 +94,85 @@ describe Banzai::Filter::CommitReferenceFilter, lib: true do
end
end
- context 'cross-project reference' do
- let(:namespace) { create(:namespace, name: 'cross-reference') }
+ context 'cross-project / cross-namespace complete reference' do
+ let(:namespace) { create(:namespace) }
let(:project2) { create(:project, :public, namespace: namespace) }
let(:commit) { project2.commit }
- let(:reference) { commit.to_reference(project) }
+ let(:reference) { "#{project2.path_with_namespace}@#{commit.short_id}" }
- it 'links to a valid reference' do
- doc = reference_filter("See #{reference}")
+ it 'link has valid text' do
+ doc = reference_filter("See (#{reference}.)")
- expect(doc.css('a').first.attr('href')).
- to eq urls.namespace_project_commit_url(project2.namespace, project2, commit.id)
+ expect(doc.css('a').first.text).to eql("#{project2.path_with_namespace}@#{commit.short_id}")
end
- it 'links with adjacent text' do
- doc = reference_filter("Fixed (#{reference}.)")
+ it 'has valid text' do
+ doc = reference_filter("See (#{reference}.)")
+
+ expect(doc.text).to eql("See (#{project2.path_with_namespace}@#{commit.short_id}.)")
+ end
+
+ it 'ignores invalid commit IDs on the referenced project' do
+ exp = act = "Committed #{invalidate_reference(reference)}"
+
+ expect(reference_filter(act).to_html).to eq exp
+ end
+ end
+
+ context 'cross-project / same-namespace complete reference' do
+ let(:namespace) { create(:namespace) }
+ let(:project) { create(:empty_project, namespace: namespace) }
+ let(:project2) { create(:project, :public, namespace: namespace) }
+ let(:commit) { project2.commit }
+ let(:reference) { "#{project2.path_with_namespace}@#{commit.short_id}" }
+
+ it 'link has valid text' do
+ doc = reference_filter("See (#{reference}.)")
- exp = Regexp.escape(project2.to_reference)
- expect(doc.to_html).to match(/\(<a.+>#{exp}@#{commit.short_id}<\/a>\.\)/)
+ expect(doc.css('a').first.text).to eql("#{project2.path}@#{commit.short_id}")
+ end
+
+ it 'has valid text' do
+ doc = reference_filter("See (#{reference}.)")
+
+ expect(doc.text).to eql("See (#{project2.path}@#{commit.short_id}.)")
end
it 'ignores invalid commit IDs on the referenced project' do
exp = act = "Committed #{invalidate_reference(reference)}"
+
+ expect(reference_filter(act).to_html).to eq exp
+ end
+ end
+
+ context 'cross-project shorthand reference' do
+ let(:namespace) { create(:namespace) }
+ let(:project) { create(:empty_project, namespace: namespace) }
+ let(:project2) { create(:project, :public, namespace: namespace) }
+ let(:commit) { project2.commit }
+ let(:reference) { "#{project2.path_with_namespace}@#{commit.short_id}" }
+
+ it 'link has valid text' do
+ doc = reference_filter("See (#{reference}.)")
+
+ expect(doc.css('a').first.text).to eql("#{project2.path}@#{commit.short_id}")
+ end
+
+ it 'has valid text' do
+ doc = reference_filter("See (#{reference}.)")
+
+ expect(doc.text).to eql("See (#{project2.path}@#{commit.short_id}.)")
+ end
+
+ it 'ignores invalid commit IDs on the referenced project' do
+ exp = act = "Committed #{invalidate_reference(reference)}"
+
expect(reference_filter(act).to_html).to eq exp
end
end
context 'cross-project URL reference' do
- let(:namespace) { create(:namespace, name: 'cross-reference') }
+ let(:namespace) { create(:namespace) }
let(:project2) { create(:project, :public, namespace: namespace) }
let(:commit) { project2.commit }
let(:reference) { urls.namespace_project_commit_url(project2.namespace, project2, commit.id) }
diff --git a/spec/lib/banzai/filter/issue_reference_filter_spec.rb b/spec/lib/banzai/filter/issue_reference_filter_spec.rb
index 8f0b2db3e8e..456dbac0698 100644
--- a/spec/lib/banzai/filter/issue_reference_filter_spec.rb
+++ b/spec/lib/banzai/filter/issue_reference_filter_spec.rb
@@ -8,7 +8,7 @@ describe Banzai::Filter::IssueReferenceFilter, lib: true do
end
let(:project) { create(:empty_project, :public) }
- let(:issue) { create(:issue, project: project) }
+ let(:issue) { create(:issue, project: project) }
it 'requires project context' do
expect { described_class.call('') }.to raise_error(ArgumentError, /:project/)
@@ -24,7 +24,7 @@ describe Banzai::Filter::IssueReferenceFilter, lib: true do
context 'internal reference' do
it_behaves_like 'a reference containing an element node'
- let(:reference) { issue.to_reference }
+ let(:reference) { "##{issue.iid}" }
it 'ignores valid references when using non-default tracker' do
allow(project).to receive(:default_issues_tracker?).and_return(false)
@@ -42,7 +42,7 @@ describe Banzai::Filter::IssueReferenceFilter, lib: true do
it 'links with adjacent text' do
doc = reference_filter("Fixed (#{reference}.)")
- expect(doc.to_html).to match(/\(<a.+>#{Regexp.escape(reference)}<\/a>\.\)/)
+ expect(doc.text).to eql("Fixed (#{reference}.)")
end
it 'ignores invalid issue IDs' do
@@ -116,13 +116,56 @@ describe Banzai::Filter::IssueReferenceFilter, lib: true do
end
end
- context 'cross-project reference' do
+ context 'cross-project / cross-namespace complete reference' do
it_behaves_like 'a reference containing an element node'
- let(:namespace) { create(:namespace, name: 'cross-reference') }
+ let(:project2) { create(:empty_project, :public) }
+ let(:issue) { create(:issue, project: project2) }
+ let(:reference) { "#{project2.path_with_namespace}##{issue.iid}" }
+
+ it 'ignores valid references when cross-reference project uses external tracker' do
+ expect_any_instance_of(described_class).to receive(:find_object).
+ with(project2, issue.iid).
+ and_return(nil)
+
+ exp = act = "Issue #{reference}"
+ expect(reference_filter(act).to_html).to eq exp
+ end
+
+ it 'links to a valid reference' do
+ doc = reference_filter("See #{reference}")
+
+ expect(doc.css('a').first.attr('href')).
+ to eq helper.url_for_issue(issue.iid, project2)
+ end
+
+ it 'link has valid text' do
+ doc = reference_filter("Fixed (#{reference}.)")
+
+ expect(doc.css('a').first.text).to eql("#{project2.path_with_namespace}##{issue.iid}")
+ end
+
+ it 'has valid text' do
+ doc = reference_filter("Fixed (#{reference}.)")
+
+ expect(doc.text).to eq("Fixed (#{project2.path_with_namespace}##{issue.iid}.)")
+ end
+
+ it 'ignores invalid issue IDs on the referenced project' do
+ exp = act = "Fixed #{invalidate_reference(reference)}"
+
+ expect(reference_filter(act).to_html).to eq exp
+ end
+ end
+
+ context 'cross-project / same-namespace complete reference' do
+ it_behaves_like 'a reference containing an element node'
+
+ let(:namespace) { create(:namespace) }
+ let(:project) { create(:empty_project, :public, namespace: namespace) }
let(:project2) { create(:empty_project, :public, namespace: namespace) }
let(:issue) { create(:issue, project: project2) }
- let(:reference) { issue.to_reference(project) }
+ let(:reference) { "#{project2.path_with_namespace}##{issue.iid}" }
it 'ignores valid references when cross-reference project uses external tracker' do
expect_any_instance_of(described_class).to receive(:find_object).
@@ -140,9 +183,16 @@ describe Banzai::Filter::IssueReferenceFilter, lib: true do
to eq helper.url_for_issue(issue.iid, project2)
end
- it 'links with adjacent text' do
+ it 'link has valid text' do
doc = reference_filter("Fixed (#{reference}.)")
- expect(doc.to_html).to match(/\(<a.+>#{Regexp.escape(reference)}<\/a>\.\)/)
+
+ expect(doc.css('a').first.text).to eql("#{project2.path}##{issue.iid}")
+ end
+
+ it 'has valid text' do
+ doc = reference_filter("Fixed (#{reference}.)")
+
+ expect(doc.text).to eq("Fixed (#{project2.path}##{issue.iid}.)")
end
it 'ignores invalid issue IDs on the referenced project' do
@@ -150,9 +200,47 @@ describe Banzai::Filter::IssueReferenceFilter, lib: true do
expect(reference_filter(act).to_html).to eq exp
end
+ end
+
+ context 'cross-project shorthand reference' do
+ it_behaves_like 'a reference containing an element node'
- it 'ignores out-of-bounds issue IDs on the referenced project' do
- exp = act = "Fixed ##{Gitlab::Database::MAX_INT_VALUE + 1}"
+ let(:namespace) { create(:namespace) }
+ let(:project) { create(:empty_project, :public, namespace: namespace) }
+ let(:project2) { create(:empty_project, :public, namespace: namespace) }
+ let(:issue) { create(:issue, project: project2) }
+ let(:reference) { "#{project2.path}##{issue.iid}" }
+
+ it 'ignores valid references when cross-reference project uses external tracker' do
+ expect_any_instance_of(described_class).to receive(:find_object).
+ with(project2, issue.iid).
+ and_return(nil)
+
+ exp = act = "Issue #{reference}"
+ expect(reference_filter(act).to_html).to eq exp
+ end
+
+ it 'links to a valid reference' do
+ doc = reference_filter("See #{reference}")
+
+ expect(doc.css('a').first.attr('href')).
+ to eq helper.url_for_issue(issue.iid, project2)
+ end
+
+ it 'link has valid text' do
+ doc = reference_filter("Fixed (#{reference}.)")
+
+ expect(doc.css('a').first.text).to eql("#{project2.path}##{issue.iid}")
+ end
+
+ it 'has valid text' do
+ doc = reference_filter("Fixed (#{reference}.)")
+
+ expect(doc.text).to eq("Fixed (#{project2.path}##{issue.iid}.)")
+ end
+
+ it 'ignores invalid issue IDs on the referenced project' do
+ exp = act = "Fixed #{invalidate_reference(reference)}"
expect(reference_filter(act).to_html).to eq exp
end
diff --git a/spec/lib/banzai/filter/label_reference_filter_spec.rb b/spec/lib/banzai/filter/label_reference_filter_spec.rb
index 9c09f00ae8a..284641fb20a 100644
--- a/spec/lib/banzai/filter/label_reference_filter_spec.rb
+++ b/spec/lib/banzai/filter/label_reference_filter_spec.rb
@@ -4,7 +4,7 @@ require 'html/pipeline'
describe Banzai::Filter::LabelReferenceFilter, lib: true do
include FilterSpecHelper
- let(:project) { create(:empty_project, :public) }
+ let(:project) { create(:empty_project, :public, name: 'sample-project') }
let(:label) { create(:label, project: project) }
let(:reference) { label.to_reference }
@@ -48,6 +48,14 @@ describe Banzai::Filter::LabelReferenceFilter, lib: true do
expect(link).to eq urls.namespace_project_issues_path(project.namespace, project, label_name: label.name)
end
+ context 'project that does not exist referenced' do
+ let(:result) { reference_filter('aaa/bbb~ccc') }
+
+ it 'does not link reference' do
+ expect(result.to_html).to eq 'aaa/bbb~ccc'
+ end
+ end
+
describe 'label span element' do
it 'includes default classes' do
doc = reference_filter("Label #{reference}")
@@ -334,14 +342,14 @@ describe Banzai::Filter::LabelReferenceFilter, lib: true do
end
context 'with project reference' do
- let(:reference) { project.to_reference + group_label.to_reference(format: :name) }
+ let(:reference) { "#{project.to_reference}#{group_label.to_reference(format: :name)}" }
it 'links to a valid reference' do
doc = reference_filter("See #{reference}", project: project)
expect(doc.css('a').first.attr('href')).to eq urls.
namespace_project_issues_url(project.namespace, project, label_name: group_label.name)
- expect(doc.text).to eq 'See gfm references'
+ expect(doc.text).to eq "See gfm references"
end
it 'links with adjacent text' do
@@ -357,68 +365,247 @@ describe Banzai::Filter::LabelReferenceFilter, lib: true do
end
end
- describe 'cross project label references' do
- context 'valid project referenced' do
- let(:another_project) { create(:empty_project, :public) }
- let(:project_name) { another_project.name_with_namespace }
- let(:label) { create(:label, project: another_project, color: '#00ff00') }
- let(:reference) { label.to_reference(project) }
+ describe 'cross-project / cross-namespace complete reference' do
+ let(:project2) { create(:empty_project) }
+ let(:label) { create(:label, project: project2, color: '#00ff00') }
+ let(:reference) { "#{project2.path_with_namespace}~#{label.name}" }
+ let!(:result) { reference_filter("See #{reference}") }
- let!(:result) { reference_filter("See #{reference}") }
+ it 'links to a valid reference' do
+ expect(result.css('a').first.attr('href'))
+ .to eq urls.namespace_project_issues_url(project2.namespace,
+ project2,
+ label_name: label.name)
+ end
- it 'points to referenced project issues page' do
- expect(result.css('a').first.attr('href'))
- .to eq urls.namespace_project_issues_url(another_project.namespace,
- another_project,
- label_name: label.name)
- end
+ it 'has valid color' do
+ expect(result.css('a span').first.attr('style')).to match /background-color: #00ff00/
+ end
- it 'has valid color' do
- expect(result.css('a span').first.attr('style'))
- .to match /background-color: #00ff00/
- end
+ it 'has valid link text' do
+ expect(result.css('a').first.text).to eq "#{label.name} in #{project2.name_with_namespace}"
+ end
- it 'contains cross project content' do
- expect(result.css('a').first.text).to eq "#{label.name} in #{project_name}"
- end
+ it 'has valid text' do
+ expect(result.text).to eq "See #{label.name} in #{project2.name_with_namespace}"
end
- context 'project that does not exist referenced' do
- let(:result) { reference_filter('aaa/bbb~ccc') }
+ it 'ignores invalid IDs on the referenced label' do
+ exp = act = "See #{invalidate_reference(reference)}"
- it 'does not link reference' do
- expect(result.to_html).to eq 'aaa/bbb~ccc'
- end
+ expect(reference_filter(act).to_html).to eq exp
+ end
+ end
+
+ describe 'cross-project / same-namespace complete reference' do
+ let(:namespace) { create(:namespace) }
+ let(:project) { create(:empty_project, namespace: namespace) }
+ let(:project2) { create(:empty_project, namespace: namespace) }
+ let(:label) { create(:label, project: project2, color: '#00ff00') }
+ let(:reference) { "#{project2.path_with_namespace}~#{label.name}" }
+ let!(:result) { reference_filter("See #{reference}") }
+
+ it 'links to a valid reference' do
+ expect(result.css('a').first.attr('href'))
+ .to eq urls.namespace_project_issues_url(project2.namespace,
+ project2,
+ label_name: label.name)
+ end
+
+ it 'has valid color' do
+ expect(result.css('a span').first.attr('style')).to match /background-color: #00ff00/
+ end
+
+ it 'has valid link text' do
+ expect(result.css('a').first.text).to eq "#{label.name} in #{project2.name}"
+ end
+
+ it 'has valid text' do
+ expect(result.text).to eq "See #{label.name} in #{project2.name}"
+ end
+
+ it 'ignores invalid IDs on the referenced label' do
+ exp = act = "See #{invalidate_reference(reference)}"
+
+ expect(reference_filter(act).to_html).to eq exp
+ end
+ end
+
+ describe 'cross-project shorthand reference' do
+ let(:namespace) { create(:namespace) }
+ let(:project) { create(:empty_project, namespace: namespace) }
+ let(:project2) { create(:empty_project, namespace: namespace) }
+ let(:label) { create(:label, project: project2, color: '#00ff00') }
+ let(:reference) { "#{project2.path}~#{label.name}" }
+ let!(:result) { reference_filter("See #{reference}") }
+
+ it 'links to a valid reference' do
+ expect(result.css('a').first.attr('href'))
+ .to eq urls.namespace_project_issues_url(project2.namespace,
+ project2,
+ label_name: label.name)
+ end
+
+ it 'has valid color' do
+ expect(result.css('a span').first.attr('style')).
+ to match /background-color: #00ff00/
+ end
+
+ it 'has valid link text' do
+ expect(result.css('a').first.text).to eq "#{label.name} in #{project2.name}"
+ end
+
+ it 'has valid text' do
+ expect(result.text).to eq "See #{label.name} in #{project2.name}"
+ end
+
+ it 'ignores invalid IDs on the referenced label' do
+ exp = act = "See #{invalidate_reference(reference)}"
+
+ expect(reference_filter(act).to_html).to eq exp
end
end
describe 'cross group label references' do
- context 'valid project referenced' do
- let(:group) { create(:group) }
- let(:project) { create(:empty_project, :public, namespace: group) }
- let(:another_group) { create(:group) }
- let(:another_project) { create(:empty_project, :public, namespace: another_group) }
- let(:project_name) { another_project.name_with_namespace }
- let(:group_label) { create(:group_label, group: another_group, color: '#00ff00') }
- let(:reference) { another_project.to_reference + group_label.to_reference }
-
- let!(:result) { reference_filter("See #{reference}", project: project) }
-
- it 'points to referenced project issues page' do
- expect(result.css('a').first.attr('href'))
- .to eq urls.namespace_project_issues_url(another_project.namespace,
- another_project,
- label_name: group_label.name)
- end
+ let(:group) { create(:group) }
+ let(:project) { create(:empty_project, :public, namespace: group) }
+ let(:another_group) { create(:group) }
+ let(:another_project) { create(:empty_project, :public, namespace: another_group) }
+ let(:group_label) { create(:group_label, group: another_group, color: '#00ff00') }
+ let(:reference) { "#{another_project.path_with_namespace}~#{group_label.name}" }
+ let!(:result) { reference_filter("See #{reference}", project: project) }
- it 'has valid color' do
- expect(result.css('a span').first.attr('style'))
- .to match /background-color: #00ff00/
- end
+ it 'points to referenced project issues page' do
+ expect(result.css('a').first.attr('href'))
+ .to eq urls.namespace_project_issues_url(another_project.namespace,
+ another_project,
+ label_name: group_label.name)
+ end
- it 'contains cross project content' do
- expect(result.css('a').first.text).to eq "#{group_label.name} in #{project_name}"
- end
+ it 'has valid color' do
+ expect(result.css('a span').first.attr('style')).
+ to match /background-color: #00ff00/
+ end
+
+ it 'has valid link text' do
+ expect(result.css('a').first.text).
+ to eq "#{group_label.name} in #{another_project.name_with_namespace}"
+ end
+
+ it 'has valid text' do
+ expect(result.text).
+ to eq "See #{group_label.name} in #{another_project.name_with_namespace}"
+ end
+
+ it 'ignores invalid IDs on the referenced label' do
+ exp = act = "See #{invalidate_reference(reference)}"
+
+ expect(reference_filter(act).to_html).to eq exp
+ end
+ end
+
+ describe 'cross-project / same-group_label complete reference' do
+ let(:group) { create(:group) }
+ let(:project) { create(:empty_project, :public, namespace: group) }
+ let(:another_project) { create(:empty_project, :public, namespace: group) }
+ let(:group_label) { create(:group_label, group: group, color: '#00ff00') }
+ let(:reference) { "#{another_project.path_with_namespace}~#{group_label.name}" }
+ let!(:result) { reference_filter("See #{reference}", project: project) }
+
+ it 'points to referenced project issues page' do
+ expect(result.css('a').first.attr('href')).
+ to eq urls.namespace_project_issues_url(another_project.namespace,
+ another_project,
+ label_name: group_label.name)
+ end
+
+ it 'has valid color' do
+ expect(result.css('a span').first.attr('style')).
+ to match /background-color: #00ff00/
+ end
+
+ it 'has valid link text' do
+ expect(result.css('a').first.text).
+ to eq "#{group_label.name} in #{another_project.name}"
+ end
+
+ it 'has valid text' do
+ expect(result.text).
+ to eq "See #{group_label.name} in #{another_project.name}"
+ end
+
+ it 'ignores invalid IDs on the referenced label' do
+ exp = act = "See #{invalidate_reference(reference)}"
+
+ expect(reference_filter(act).to_html).to eq exp
+ end
+ end
+
+ describe 'same project / same group_label complete reference' do
+ let(:group) { create(:group) }
+ let(:project) { create(:empty_project, :public, namespace: group) }
+ let(:group_label) { create(:group_label, group: group, color: '#00ff00') }
+ let(:reference) { "#{project.path_with_namespace}~#{group_label.name}" }
+ let!(:result) { reference_filter("See #{reference}", project: project) }
+
+ it 'points to referenced project issues page' do
+ expect(result.css('a').first.attr('href'))
+ .to eq urls.namespace_project_issues_url(project.namespace,
+ project,
+ label_name: group_label.name)
+ end
+
+ it 'has valid color' do
+ expect(result.css('a span').first.attr('style'))
+ .to match /background-color: #00ff00/
+ end
+
+ it 'has valid link text' do
+ expect(result.css('a').first.text).to eq group_label.name
+ end
+
+ it 'has valid text' do
+ expect(result.text).to eq "See #{group_label.name}"
+ end
+
+ it 'ignores invalid IDs on the referenced label' do
+ exp = act = "See #{invalidate_reference(reference)}"
+
+ expect(reference_filter(act).to_html).to eq exp
+ end
+ end
+
+ describe 'same project / same group_label shorthand reference' do
+ let(:group) { create(:group) }
+ let(:project) { create(:empty_project, :public, namespace: group) }
+ let(:group_label) { create(:group_label, group: group, color: '#00ff00') }
+ let(:reference) { "#{project.path}~#{group_label.name}" }
+ let!(:result) { reference_filter("See #{reference}", project: project) }
+
+ it 'points to referenced project issues page' do
+ expect(result.css('a').first.attr('href'))
+ .to eq urls.namespace_project_issues_url(project.namespace,
+ project,
+ label_name: group_label.name)
+ end
+
+ it 'has valid color' do
+ expect(result.css('a span').first.attr('style')).
+ to match /background-color: #00ff00/
+ end
+
+ it 'has valid link text' do
+ expect(result.css('a').first.text).to eq group_label.name
+ end
+
+ it 'has valid text' do
+ expect(result.text).to eq "See #{group_label.name}"
+ end
+
+ it 'ignores invalid IDs on the referenced label' do
+ exp = act = "See #{invalidate_reference(reference)}"
+
+ expect(reference_filter(act).to_html).to eq exp
end
end
end
diff --git a/spec/lib/banzai/filter/merge_request_reference_filter_spec.rb b/spec/lib/banzai/filter/merge_request_reference_filter_spec.rb
index 274258a045c..275010c1a2c 100644
--- a/spec/lib/banzai/filter/merge_request_reference_filter_spec.rb
+++ b/spec/lib/banzai/filter/merge_request_reference_filter_spec.rb
@@ -3,7 +3,7 @@ require 'spec_helper'
describe Banzai::Filter::MergeRequestReferenceFilter, lib: true do
include FilterSpecHelper
- let(:project) { create(:project, :public) }
+ let(:project) { create(:empty_project, :public) }
let(:merge) { create(:merge_request, source_project: project) }
it 'requires project context' do
@@ -86,23 +86,97 @@ describe Banzai::Filter::MergeRequestReferenceFilter, lib: true do
end
end
- context 'cross-project reference' do
- let(:namespace) { create(:namespace, name: 'cross-reference') }
- let(:project2) { create(:project, :public, namespace: namespace) }
- let(:merge) { create(:merge_request, source_project: project2) }
- let(:reference) { merge.to_reference(project) }
+ context 'cross-project / cross-namespace complete reference' do
+ let(:project2) { create(:empty_project, :public) }
+ let(:merge) { create(:merge_request, source_project: project2) }
+ let(:reference) { "#{project2.path_with_namespace}!#{merge.iid}" }
it 'links to a valid reference' do
doc = reference_filter("See #{reference}")
expect(doc.css('a').first.attr('href')).
to eq urls.namespace_project_merge_request_url(project2.namespace,
- project, merge)
+ project2, merge)
end
- it 'links with adjacent text' do
+ it 'link has valid text' do
doc = reference_filter("Merge (#{reference}.)")
- expect(doc.to_html).to match(/\(<a.+>#{Regexp.escape(reference)}<\/a>\.\)/)
+
+ expect(doc.css('a').first.text).to eq(reference)
+ end
+
+ it 'has valid text' do
+ doc = reference_filter("Merge (#{reference}.)")
+
+ expect(doc.text).to eq("Merge (#{reference}.)")
+ end
+
+ it 'ignores invalid merge IDs on the referenced project' do
+ exp = act = "Merge #{invalidate_reference(reference)}"
+
+ expect(reference_filter(act).to_html).to eq exp
+ end
+ end
+
+ context 'cross-project / same-namespace complete reference' do
+ let(:namespace) { create(:namespace) }
+ let(:project) { create(:empty_project, :public, namespace: namespace) }
+ let(:project2) { create(:empty_project, :public, namespace: namespace) }
+ let!(:merge) { create(:merge_request, source_project: project2) }
+ let(:reference) { "#{project2.path_with_namespace}!#{merge.iid}" }
+
+ it 'links to a valid reference' do
+ doc = reference_filter("See #{reference}")
+
+ expect(doc.css('a').first.attr('href')).
+ to eq urls.namespace_project_merge_request_url(project2.namespace,
+ project2, merge)
+ end
+
+ it 'link has valid text' do
+ doc = reference_filter("Merge (#{reference}.)")
+
+ expect(doc.css('a').first.text).to eq("#{project2.path}!#{merge.iid}")
+ end
+
+ it 'has valid text' do
+ doc = reference_filter("Merge (#{reference}.)")
+
+ expect(doc.text).to eq("Merge (#{project2.path}!#{merge.iid}.)")
+ end
+
+ it 'ignores invalid merge IDs on the referenced project' do
+ exp = act = "Merge #{invalidate_reference(reference)}"
+
+ expect(reference_filter(act).to_html).to eq exp
+ end
+ end
+
+ context 'cross-project shorthand reference' do
+ let(:namespace) { create(:namespace) }
+ let(:project) { create(:empty_project, :public, namespace: namespace) }
+ let(:project2) { create(:empty_project, :public, namespace: namespace) }
+ let!(:merge) { create(:merge_request, source_project: project2) }
+ let(:reference) { "#{project2.path}!#{merge.iid}" }
+
+ it 'links to a valid reference' do
+ doc = reference_filter("See #{reference}")
+
+ expect(doc.css('a').first.attr('href')).
+ to eq urls.namespace_project_merge_request_url(project2.namespace,
+ project2, merge)
+ end
+
+ it 'link has valid text' do
+ doc = reference_filter("Merge (#{reference}.)")
+
+ expect(doc.css('a').first.text).to eq("#{project2.path}!#{merge.iid}")
+ end
+
+ it 'has valid text' do
+ doc = reference_filter("Merge (#{reference}.)")
+
+ expect(doc.text).to eq("Merge (#{project2.path}!#{merge.iid}.)")
end
it 'ignores invalid merge IDs on the referenced project' do
diff --git a/spec/lib/banzai/filter/milestone_reference_filter_spec.rb b/spec/lib/banzai/filter/milestone_reference_filter_spec.rb
index 7419863d848..73b5edb99b3 100644
--- a/spec/lib/banzai/filter/milestone_reference_filter_spec.rb
+++ b/spec/lib/banzai/filter/milestone_reference_filter_spec.rb
@@ -148,13 +148,51 @@ describe Banzai::Filter::MilestoneReferenceFilter, lib: true do
end
end
- describe 'cross project milestone references' do
- let(:another_project) { create(:empty_project, :public) }
- let(:project_path) { another_project.path_with_namespace }
- let(:milestone) { create(:milestone, project: another_project) }
- let(:reference) { milestone.to_reference(project) }
+ describe 'cross-project / cross-namespace complete reference' do
+ let(:namespace) { create(:namespace) }
+ let(:another_project) { create(:empty_project, :public, namespace: namespace) }
+ let(:milestone) { create(:milestone, project: another_project) }
+ let(:reference) { "#{another_project.path_with_namespace}%#{milestone.iid}" }
+ let!(:result) { reference_filter("See #{reference}") }
- let!(:result) { reference_filter("See #{reference}") }
+ it 'points to referenced project milestone page' do
+ expect(result.css('a').first.attr('href')).to eq urls.
+ namespace_project_milestone_url(another_project.namespace,
+ another_project,
+ milestone)
+ end
+
+ it 'link has valid text' do
+ doc = reference_filter("See (#{reference}.)")
+
+ expect(doc.css('a').first.text).
+ to eq("#{milestone.name} in #{another_project.path_with_namespace}")
+ end
+
+ it 'has valid text' do
+ doc = reference_filter("See (#{reference}.)")
+
+ expect(doc.text).
+ to eq("See (#{milestone.name} in #{another_project.path_with_namespace}.)")
+ end
+
+ it 'escapes the name attribute' do
+ allow_any_instance_of(Milestone).to receive(:title).and_return(%{"></a>whatever<a title="})
+
+ doc = reference_filter("See #{reference}")
+
+ expect(doc.css('a').first.text).
+ to eq "#{milestone.name} in #{another_project.path_with_namespace}"
+ end
+ end
+
+ describe 'cross-project / same-namespace complete reference' do
+ let(:namespace) { create(:namespace) }
+ let(:project) { create(:empty_project, :public, namespace: namespace) }
+ let(:another_project) { create(:empty_project, :public, namespace: namespace) }
+ let(:milestone) { create(:milestone, project: another_project) }
+ let(:reference) { "#{another_project.path_with_namespace}%#{milestone.iid}" }
+ let!(:result) { reference_filter("See #{reference}") }
it 'points to referenced project milestone page' do
expect(result.css('a').first.attr('href')).to eq urls.
@@ -163,14 +201,66 @@ describe Banzai::Filter::MilestoneReferenceFilter, lib: true do
milestone)
end
- it 'contains cross project content' do
- expect(result.css('a').first.text).to eq "#{milestone.name} in #{project_path}"
+ it 'link has valid text' do
+ doc = reference_filter("See (#{reference}.)")
+
+ expect(doc.css('a').first.text).
+ to eq("#{milestone.name} in #{another_project.path}")
+ end
+
+ it 'has valid text' do
+ doc = reference_filter("See (#{reference}.)")
+
+ expect(doc.text).
+ to eq("See (#{milestone.name} in #{another_project.path}.)")
end
it 'escapes the name attribute' do
allow_any_instance_of(Milestone).to receive(:title).and_return(%{"></a>whatever<a title="})
+
+ doc = reference_filter("See #{reference}")
+
+ expect(doc.css('a').first.text).
+ to eq "#{milestone.name} in #{another_project.path}"
+ end
+ end
+
+ describe 'cross project shorthand reference' do
+ let(:namespace) { create(:namespace) }
+ let(:project) { create(:empty_project, :public, namespace: namespace) }
+ let(:another_project) { create(:empty_project, :public, namespace: namespace) }
+ let(:milestone) { create(:milestone, project: another_project) }
+ let(:reference) { "#{another_project.path}%#{milestone.iid}" }
+ let!(:result) { reference_filter("See #{reference}") }
+
+ it 'points to referenced project milestone page' do
+ expect(result.css('a').first.attr('href')).to eq urls.
+ namespace_project_milestone_url(another_project.namespace,
+ another_project,
+ milestone)
+ end
+
+ it 'link has valid text' do
+ doc = reference_filter("See (#{reference}.)")
+
+ expect(doc.css('a').first.text).
+ to eq("#{milestone.name} in #{another_project.path}")
+ end
+
+ it 'has valid text' do
+ doc = reference_filter("See (#{reference}.)")
+
+ expect(doc.text).
+ to eq("See (#{milestone.name} in #{another_project.path}.)")
+ end
+
+ it 'escapes the name attribute' do
+ allow_any_instance_of(Milestone).to receive(:title).and_return(%{"></a>whatever<a title="})
+
doc = reference_filter("See #{reference}")
- expect(doc.css('a').first.text).to eq "#{milestone.name} in #{project_path}"
+
+ expect(doc.css('a').first.text).
+ to eq "#{milestone.name} in #{another_project.path}"
end
end
end
diff --git a/spec/lib/banzai/filter/snippet_reference_filter_spec.rb b/spec/lib/banzai/filter/snippet_reference_filter_spec.rb
index 9b92d1a3926..e036514d283 100644
--- a/spec/lib/banzai/filter/snippet_reference_filter_spec.rb
+++ b/spec/lib/banzai/filter/snippet_reference_filter_spec.rb
@@ -79,11 +79,11 @@ describe Banzai::Filter::SnippetReferenceFilter, lib: true do
end
end
- context 'cross-project reference' do
- let(:namespace) { create(:namespace, name: 'cross-reference') }
+ context 'cross-project / cross-namespace complete reference' do
+ let(:namespace) { create(:namespace) }
let(:project2) { create(:empty_project, :public, namespace: namespace) }
- let(:snippet) { create(:project_snippet, project: project2) }
- let(:reference) { snippet.to_reference(project) }
+ let!(:snippet) { create(:project_snippet, project: project2) }
+ let(:reference) { "#{project2.path_with_namespace}$#{snippet.id}" }
it 'links to a valid reference' do
doc = reference_filter("See #{reference}")
@@ -92,9 +92,82 @@ describe Banzai::Filter::SnippetReferenceFilter, lib: true do
to eq urls.namespace_project_snippet_url(project2.namespace, project2, snippet)
end
- it 'links with adjacent text' do
+ it 'link has valid text' do
doc = reference_filter("See (#{reference}.)")
- expect(doc.to_html).to match(/\(<a.+>#{Regexp.escape(reference)}<\/a>\.\)/)
+
+ expect(doc.css('a').first.text).to eql(reference)
+ end
+
+ it 'has valid text' do
+ doc = reference_filter("See (#{reference}.)")
+
+ expect(doc.text).to eql("See (#{reference}.)")
+ end
+
+ it 'ignores invalid snippet IDs on the referenced project' do
+ exp = act = "See #{invalidate_reference(reference)}"
+
+ expect(reference_filter(act).to_html).to eq exp
+ end
+ end
+
+ context 'cross-project / same-namespace complete reference' do
+ let(:namespace) { create(:namespace) }
+ let(:project) { create(:empty_project, :public, namespace: namespace) }
+ let(:project2) { create(:empty_project, :public, namespace: namespace) }
+ let!(:snippet) { create(:project_snippet, project: project2) }
+ let(:reference) { "#{project2.path_with_namespace}$#{snippet.id}" }
+
+ it 'links to a valid reference' do
+ doc = reference_filter("See #{reference}")
+
+ expect(doc.css('a').first.attr('href')).
+ to eq urls.namespace_project_snippet_url(project2.namespace, project2, snippet)
+ end
+
+ it 'link has valid text' do
+ doc = reference_filter("See (#{project2.path}$#{snippet.id}.)")
+
+ expect(doc.css('a').first.text).to eql("#{project2.path}$#{snippet.id}")
+ end
+
+ it 'has valid text' do
+ doc = reference_filter("See (#{project2.path}$#{snippet.id}.)")
+
+ expect(doc.text).to eql("See (#{project2.path}$#{snippet.id}.)")
+ end
+
+ it 'ignores invalid snippet IDs on the referenced project' do
+ exp = act = "See #{invalidate_reference(reference)}"
+
+ expect(reference_filter(act).to_html).to eq exp
+ end
+ end
+
+ context 'cross-project shorthand reference' do
+ let(:namespace) { create(:namespace) }
+ let(:project) { create(:empty_project, :public, namespace: namespace) }
+ let(:project2) { create(:empty_project, :public, namespace: namespace) }
+ let!(:snippet) { create(:project_snippet, project: project2) }
+ let(:reference) { "#{project2.path}$#{snippet.id}" }
+
+ it 'links to a valid reference' do
+ doc = reference_filter("See #{reference}")
+
+ expect(doc.css('a').first.attr('href')).
+ to eq urls.namespace_project_snippet_url(project2.namespace, project2, snippet)
+ end
+
+ it 'link has valid text' do
+ doc = reference_filter("See (#{project2.path}$#{snippet.id}.)")
+
+ expect(doc.css('a').first.text).to eql("#{project2.path}$#{snippet.id}")
+ end
+
+ it 'has valid text' do
+ doc = reference_filter("See (#{project2.path}$#{snippet.id}.)")
+
+ expect(doc.text).to eql("See (#{project2.path}$#{snippet.id}.)")
end
it 'ignores invalid snippet IDs on the referenced project' do
diff --git a/spec/lib/gitlab/chat_commands/issue_create_spec.rb b/spec/lib/gitlab/chat_commands/issue_create_spec.rb
index dd07cff9243..6c71e79ff6d 100644
--- a/spec/lib/gitlab/chat_commands/issue_create_spec.rb
+++ b/spec/lib/gitlab/chat_commands/issue_create_spec.rb
@@ -57,5 +57,12 @@ describe Gitlab::ChatCommands::IssueCreate, service: true do
expect(match[:title]).to eq('my title')
expect(match[:description]).to eq('description')
end
+
+ it 'matches the alias new' do
+ match = described_class.match("issue new my title")
+
+ expect(match).not_to be_nil
+ expect(match[:title]).to eq('my title')
+ end
end
end
diff --git a/spec/lib/gitlab/ci/status/canceled_spec.rb b/spec/lib/gitlab/ci/status/canceled_spec.rb
new file mode 100644
index 00000000000..619ecbcba67
--- /dev/null
+++ b/spec/lib/gitlab/ci/status/canceled_spec.rb
@@ -0,0 +1,21 @@
+require 'spec_helper'
+
+describe Gitlab::Ci::Status::Canceled do
+ subject { described_class.new(double('subject')) }
+
+ describe '#text' do
+ it { expect(subject.label).to eq 'canceled' }
+ end
+
+ describe '#label' do
+ it { expect(subject.label).to eq 'canceled' }
+ end
+
+ describe '#icon' do
+ it { expect(subject.icon).to eq 'icon_status_canceled' }
+ end
+
+ describe '#title' do
+ it { expect(subject.title).to eq 'Double: canceled' }
+ end
+end
diff --git a/spec/lib/gitlab/ci/status/created_spec.rb b/spec/lib/gitlab/ci/status/created_spec.rb
new file mode 100644
index 00000000000..157302c65a8
--- /dev/null
+++ b/spec/lib/gitlab/ci/status/created_spec.rb
@@ -0,0 +1,21 @@
+require 'spec_helper'
+
+describe Gitlab::Ci::Status::Created do
+ subject { described_class.new(double('subject')) }
+
+ describe '#text' do
+ it { expect(subject.label).to eq 'created' }
+ end
+
+ describe '#label' do
+ it { expect(subject.label).to eq 'created' }
+ end
+
+ describe '#icon' do
+ it { expect(subject.icon).to eq 'icon_status_created' }
+ end
+
+ describe '#title' do
+ it { expect(subject.title).to eq 'Double: created' }
+ end
+end
diff --git a/spec/lib/gitlab/ci/status/extended_spec.rb b/spec/lib/gitlab/ci/status/extended_spec.rb
new file mode 100644
index 00000000000..120e121aae5
--- /dev/null
+++ b/spec/lib/gitlab/ci/status/extended_spec.rb
@@ -0,0 +1,12 @@
+require 'spec_helper'
+
+describe Gitlab::Ci::Status::Extended do
+ subject do
+ Class.new.extend(described_class)
+ end
+
+ it 'requires subclass to implement matcher' do
+ expect { subject.matches?(double) }
+ .to raise_error(NotImplementedError)
+ end
+end
diff --git a/spec/lib/gitlab/ci/status/failed_spec.rb b/spec/lib/gitlab/ci/status/failed_spec.rb
new file mode 100644
index 00000000000..0b3cb8168e6
--- /dev/null
+++ b/spec/lib/gitlab/ci/status/failed_spec.rb
@@ -0,0 +1,21 @@
+require 'spec_helper'
+
+describe Gitlab::Ci::Status::Failed do
+ subject { described_class.new(double('subject')) }
+
+ describe '#text' do
+ it { expect(subject.label).to eq 'failed' }
+ end
+
+ describe '#label' do
+ it { expect(subject.label).to eq 'failed' }
+ end
+
+ describe '#icon' do
+ it { expect(subject.icon).to eq 'icon_status_failed' }
+ end
+
+ describe '#title' do
+ it { expect(subject.title).to eq 'Double: failed' }
+ end
+end
diff --git a/spec/lib/gitlab/ci/status/pending_spec.rb b/spec/lib/gitlab/ci/status/pending_spec.rb
new file mode 100644
index 00000000000..57c901c1202
--- /dev/null
+++ b/spec/lib/gitlab/ci/status/pending_spec.rb
@@ -0,0 +1,21 @@
+require 'spec_helper'
+
+describe Gitlab::Ci::Status::Pending do
+ subject { described_class.new(double('subject')) }
+
+ describe '#text' do
+ it { expect(subject.label).to eq 'pending' }
+ end
+
+ describe '#label' do
+ it { expect(subject.label).to eq 'pending' }
+ end
+
+ describe '#icon' do
+ it { expect(subject.icon).to eq 'icon_status_pending' }
+ end
+
+ describe '#title' do
+ it { expect(subject.title).to eq 'Double: pending' }
+ end
+end
diff --git a/spec/lib/gitlab/ci/status/pipeline/common_spec.rb b/spec/lib/gitlab/ci/status/pipeline/common_spec.rb
new file mode 100644
index 00000000000..21adee3f8e7
--- /dev/null
+++ b/spec/lib/gitlab/ci/status/pipeline/common_spec.rb
@@ -0,0 +1,23 @@
+require 'spec_helper'
+
+describe Gitlab::Ci::Status::Pipeline::Common do
+ let(:pipeline) { create(:ci_pipeline) }
+
+ subject do
+ Class.new(Gitlab::Ci::Status::Core)
+ .new(pipeline).extend(described_class)
+ end
+
+ it 'does not have action' do
+ expect(subject).not_to have_action
+ end
+
+ it 'has details' do
+ expect(subject).to have_details
+ end
+
+ it 'links to the pipeline details page' do
+ expect(subject.details_path)
+ .to include "pipelines/#{pipeline.id}"
+ end
+end
diff --git a/spec/lib/gitlab/ci/status/pipeline/factory_spec.rb b/spec/lib/gitlab/ci/status/pipeline/factory_spec.rb
new file mode 100644
index 00000000000..d6243940f2e
--- /dev/null
+++ b/spec/lib/gitlab/ci/status/pipeline/factory_spec.rb
@@ -0,0 +1,52 @@
+require 'spec_helper'
+
+describe Gitlab::Ci::Status::Pipeline::Factory do
+ subject do
+ described_class.new(pipeline)
+ end
+
+ let(:status) do
+ subject.fabricate!
+ end
+
+ context 'when pipeline has a core status' do
+ HasStatus::AVAILABLE_STATUSES.each do |core_status|
+ context "when core status is #{core_status}" do
+ let(:pipeline) do
+ create(:ci_pipeline, status: core_status)
+ end
+
+ it "fabricates a core status #{core_status}" do
+ expect(status).to be_a(
+ Gitlab::Ci::Status.const_get(core_status.capitalize))
+ end
+
+ it 'extends core status with common pipeline methods' do
+ expect(status).to have_details
+ expect(status).not_to have_action
+ expect(status.details_path)
+ .to include "pipelines/#{pipeline.id}"
+ end
+ end
+ end
+ end
+
+ context 'when pipeline has warnings' do
+ let(:pipeline) do
+ create(:ci_pipeline, status: :success)
+ end
+
+ before do
+ create(:ci_build, :allowed_to_fail, :failed, pipeline: pipeline)
+ end
+
+ it 'fabricates extended "success with warnings" status' do
+ expect(status)
+ .to be_a Gitlab::Ci::Status::Pipeline::SuccessWithWarnings
+ end
+
+ it 'extends core status with common pipeline methods' do
+ expect(status).to have_details
+ end
+ end
+end
diff --git a/spec/lib/gitlab/ci/status/pipeline/success_with_warnings_spec.rb b/spec/lib/gitlab/ci/status/pipeline/success_with_warnings_spec.rb
new file mode 100644
index 00000000000..02e526e3de2
--- /dev/null
+++ b/spec/lib/gitlab/ci/status/pipeline/success_with_warnings_spec.rb
@@ -0,0 +1,65 @@
+require 'spec_helper'
+
+describe Gitlab::Ci::Status::Pipeline::SuccessWithWarnings do
+ subject do
+ described_class.new(double('status'))
+ end
+
+ describe '#test' do
+ it { expect(subject.text).to eq 'passed' }
+ end
+
+ describe '#label' do
+ it { expect(subject.label).to eq 'passed with warnings' }
+ end
+
+ describe '#icon' do
+ it { expect(subject.icon).to eq 'icon_status_warning' }
+ end
+
+ describe '.matches?' do
+ context 'when pipeline is successful' do
+ let(:pipeline) do
+ create(:ci_pipeline, status: :success)
+ end
+
+ context 'when pipeline has warnings' do
+ before do
+ allow(pipeline).to receive(:has_warnings?).and_return(true)
+ end
+
+ it 'is a correct match' do
+ expect(described_class.matches?(pipeline)).to eq true
+ end
+ end
+
+ context 'when pipeline does not have warnings' do
+ it 'does not match' do
+ expect(described_class.matches?(pipeline)).to eq false
+ end
+ end
+ end
+
+ context 'when pipeline is not successful' do
+ let(:pipeline) do
+ create(:ci_pipeline, status: :skipped)
+ end
+
+ context 'when pipeline has warnings' do
+ before do
+ allow(pipeline).to receive(:has_warnings?).and_return(true)
+ end
+
+ it 'does not match' do
+ expect(described_class.matches?(pipeline)).to eq false
+ end
+ end
+
+ context 'when pipeline does not have warnings' do
+ it 'does not match' do
+ expect(described_class.matches?(pipeline)).to eq false
+ end
+ end
+ end
+ end
+end
diff --git a/spec/lib/gitlab/ci/status/running_spec.rb b/spec/lib/gitlab/ci/status/running_spec.rb
new file mode 100644
index 00000000000..c023f1872cc
--- /dev/null
+++ b/spec/lib/gitlab/ci/status/running_spec.rb
@@ -0,0 +1,21 @@
+require 'spec_helper'
+
+describe Gitlab::Ci::Status::Running do
+ subject { described_class.new(double('subject')) }
+
+ describe '#text' do
+ it { expect(subject.label).to eq 'running' }
+ end
+
+ describe '#label' do
+ it { expect(subject.label).to eq 'running' }
+ end
+
+ describe '#icon' do
+ it { expect(subject.icon).to eq 'icon_status_running' }
+ end
+
+ describe '#title' do
+ it { expect(subject.title).to eq 'Double: running' }
+ end
+end
diff --git a/spec/lib/gitlab/ci/status/skipped_spec.rb b/spec/lib/gitlab/ci/status/skipped_spec.rb
new file mode 100644
index 00000000000..d4f7f4b3b70
--- /dev/null
+++ b/spec/lib/gitlab/ci/status/skipped_spec.rb
@@ -0,0 +1,21 @@
+require 'spec_helper'
+
+describe Gitlab::Ci::Status::Skipped do
+ subject { described_class.new(double('subject')) }
+
+ describe '#text' do
+ it { expect(subject.label).to eq 'skipped' }
+ end
+
+ describe '#label' do
+ it { expect(subject.label).to eq 'skipped' }
+ end
+
+ describe '#icon' do
+ it { expect(subject.icon).to eq 'icon_status_skipped' }
+ end
+
+ describe '#title' do
+ it { expect(subject.title).to eq 'Double: skipped' }
+ end
+end
diff --git a/spec/lib/gitlab/ci/status/success_spec.rb b/spec/lib/gitlab/ci/status/success_spec.rb
new file mode 100644
index 00000000000..9e261a3aa5f
--- /dev/null
+++ b/spec/lib/gitlab/ci/status/success_spec.rb
@@ -0,0 +1,21 @@
+require 'spec_helper'
+
+describe Gitlab::Ci::Status::Success do
+ subject { described_class.new(double('subject')) }
+
+ describe '#text' do
+ it { expect(subject.label).to eq 'passed' }
+ end
+
+ describe '#label' do
+ it { expect(subject.label).to eq 'passed' }
+ end
+
+ describe '#icon' do
+ it { expect(subject.icon).to eq 'icon_status_success' }
+ end
+
+ describe '#title' do
+ it { expect(subject.title).to eq 'Double: passed' }
+ end
+end
diff --git a/spec/lib/gitlab/cycle_analytics/permissions_spec.rb b/spec/lib/gitlab/cycle_analytics/permissions_spec.rb
index dc4f7dc69db..2d85e712db0 100644
--- a/spec/lib/gitlab/cycle_analytics/permissions_spec.rb
+++ b/spec/lib/gitlab/cycle_analytics/permissions_spec.rb
@@ -1,7 +1,7 @@
require 'spec_helper'
describe Gitlab::CycleAnalytics::Permissions do
- let(:project) { create(:empty_project) }
+ let(:project) { create(:empty_project, public_builds: false) }
let(:user) { create(:user) }
subject { described_class.get(user: user, project: project) }
diff --git a/spec/lib/gitlab/diff/file_collection/merge_request_diff_spec.rb b/spec/lib/gitlab/diff/file_collection/merge_request_diff_spec.rb
index c863a5f04cc..2a680f03476 100644
--- a/spec/lib/gitlab/diff/file_collection/merge_request_diff_spec.rb
+++ b/spec/lib/gitlab/diff/file_collection/merge_request_diff_spec.rb
@@ -10,4 +10,12 @@ describe Gitlab::Diff::FileCollection::MergeRequestDiff do
described_class.new(merge_request.merge_request_diff, diff_options: nil).diff_files
end
+
+ it 'does not hightlight file if blob is not accessable' do
+ allow_any_instance_of(Gitlab::Diff::File).to receive(:blob).and_return(nil)
+
+ expect_any_instance_of(Gitlab::Diff::File).not_to receive(:highlighted_diff_lines)
+
+ described_class.new(merge_request.merge_request_diff, diff_options: nil).diff_files
+ end
end
diff --git a/spec/lib/gitlab/gfm/reference_rewriter_spec.rb b/spec/lib/gitlab/gfm/reference_rewriter_spec.rb
index 6b3dfebd85d..d619e401897 100644
--- a/spec/lib/gitlab/gfm/reference_rewriter_spec.rb
+++ b/spec/lib/gitlab/gfm/reference_rewriter_spec.rb
@@ -64,7 +64,7 @@ describe Gitlab::Gfm::ReferenceRewriter do
context 'description with project labels' do
let!(:label) { create(:label, id: 123, name: 'test', project: old_project) }
- let(:project_ref) { old_project.to_reference }
+ let(:project_ref) { old_project.to_reference(new_project) }
context 'label referenced by id' do
let(:text) { '#1 and ~123' }
@@ -80,7 +80,7 @@ describe Gitlab::Gfm::ReferenceRewriter do
context 'description with group labels' do
let(:old_group) { create(:group) }
let!(:group_label) { create(:group_label, id: 321, name: 'group label', group: old_group) }
- let(:project_ref) { old_project.to_reference }
+ let(:project_ref) { old_project.to_reference(new_project) }
before do
old_project.update(namespace: old_group)
diff --git a/spec/lib/gitlab/import_export/members_mapper_spec.rb b/spec/lib/gitlab/import_export/members_mapper_spec.rb
index 770e8b0c2f4..1cb02f8e318 100644
--- a/spec/lib/gitlab/import_export/members_mapper_spec.rb
+++ b/spec/lib/gitlab/import_export/members_mapper_spec.rb
@@ -2,9 +2,9 @@ require 'spec_helper'
describe Gitlab::ImportExport::MembersMapper, services: true do
describe 'map members' do
- let(:user) { create(:user) }
+ let(:user) { create(:user, authorized_projects_populated: true) }
let(:project) { create(:project, :public, name: 'searchable_project') }
- let(:user2) { create(:user) }
+ let(:user2) { create(:user, authorized_projects_populated: true) }
let(:exported_user_id) { 99 }
let(:exported_members) do
[{
@@ -67,5 +67,12 @@ describe Gitlab::ImportExport::MembersMapper, services: true do
expect(ProjectMember.find_by_invite_email('invite@test.com')).not_to be_nil
end
+
+ it 'authorizes the users to the project' do
+ members_mapper.map
+
+ expect(user.authorized_project?(project)).to be true
+ expect(user2.authorized_project?(project)).to be true
+ end
end
end
diff --git a/spec/models/ci/pipeline_spec.rb b/spec/models/ci/pipeline_spec.rb
index 0d2b4920835..3f93d9ddf19 100644
--- a/spec/models/ci/pipeline_spec.rb
+++ b/spec/models/ci/pipeline_spec.rb
@@ -404,6 +404,76 @@ describe Ci::Pipeline, models: true do
end
end
+ describe '#detailed_status' do
+ context 'when pipeline is created' do
+ let(:pipeline) { create(:ci_pipeline, status: :created) }
+
+ it 'returns detailed status for created pipeline' do
+ expect(pipeline.detailed_status.text).to eq 'created'
+ end
+ end
+
+ context 'when pipeline is pending' do
+ let(:pipeline) { create(:ci_pipeline, status: :pending) }
+
+ it 'returns detailed status for pending pipeline' do
+ expect(pipeline.detailed_status.text).to eq 'pending'
+ end
+ end
+
+ context 'when pipeline is running' do
+ let(:pipeline) { create(:ci_pipeline, status: :running) }
+
+ it 'returns detailed status for running pipeline' do
+ expect(pipeline.detailed_status.text).to eq 'running'
+ end
+ end
+
+ context 'when pipeline is successful' do
+ let(:pipeline) { create(:ci_pipeline, status: :success) }
+
+ it 'returns detailed status for successful pipeline' do
+ expect(pipeline.detailed_status.text).to eq 'passed'
+ end
+ end
+
+ context 'when pipeline is failed' do
+ let(:pipeline) { create(:ci_pipeline, status: :failed) }
+
+ it 'returns detailed status for failed pipeline' do
+ expect(pipeline.detailed_status.text).to eq 'failed'
+ end
+ end
+
+ context 'when pipeline is canceled' do
+ let(:pipeline) { create(:ci_pipeline, status: :canceled) }
+
+ it 'returns detailed status for canceled pipeline' do
+ expect(pipeline.detailed_status.text).to eq 'canceled'
+ end
+ end
+
+ context 'when pipeline is skipped' do
+ let(:pipeline) { create(:ci_pipeline, status: :skipped) }
+
+ it 'returns detailed status for skipped pipeline' do
+ expect(pipeline.detailed_status.text).to eq 'skipped'
+ end
+ end
+
+ context 'when pipeline is successful but with warnings' do
+ let(:pipeline) { create(:ci_pipeline, status: :success) }
+
+ before do
+ create(:ci_build, :allowed_to_fail, :failed, pipeline: pipeline)
+ end
+
+ it 'retruns detailed status for successful pipeline with warnings' do
+ expect(pipeline.detailed_status.label).to eq 'passed with warnings'
+ end
+ end
+ end
+
describe '#cancelable?' do
%i[created running pending].each do |status0|
context "when there is a build #{status0}" do
diff --git a/spec/models/commit_range_spec.rb b/spec/models/commit_range_spec.rb
index c41359b55a3..d89d4342dea 100644
--- a/spec/models/commit_range_spec.rb
+++ b/spec/models/commit_range_spec.rb
@@ -45,7 +45,7 @@ describe CommitRange, models: true do
end
describe '#to_reference' do
- let(:cross) { create(:project) }
+ let(:cross) { create(:empty_project, namespace: project.namespace) }
it 'returns a String reference to the object' do
expect(range.to_reference).to eq "#{full_sha_from}...#{full_sha_to}"
@@ -56,12 +56,12 @@ describe CommitRange, models: true do
end
it 'supports a cross-project reference' do
- expect(range.to_reference(cross)).to eq "#{project.to_reference}@#{full_sha_from}...#{full_sha_to}"
+ expect(range.to_reference(cross)).to eq "#{project.path}@#{full_sha_from}...#{full_sha_to}"
end
end
describe '#reference_link_text' do
- let(:cross) { create(:project) }
+ let(:cross) { create(:empty_project, namespace: project.namespace) }
it 'returns a String reference to the object' do
expect(range.reference_link_text).to eq "#{sha_from}...#{sha_to}"
@@ -72,7 +72,7 @@ describe CommitRange, models: true do
end
it 'supports a cross-project reference' do
- expect(range.reference_link_text(cross)).to eq "#{project.to_reference}@#{sha_from}...#{sha_to}"
+ expect(range.reference_link_text(cross)).to eq "#{project.path}@#{sha_from}...#{sha_to}"
end
end
diff --git a/spec/models/commit_spec.rb b/spec/models/commit_spec.rb
index 7194c20d3bf..eb482c7f913 100644
--- a/spec/models/commit_spec.rb
+++ b/spec/models/commit_spec.rb
@@ -34,24 +34,30 @@ describe Commit, models: true do
end
describe '#to_reference' do
+ let(:project) { create(:project, path: 'sample-project') }
+ let(:commit) { project.commit }
+
it 'returns a String reference to the object' do
expect(commit.to_reference).to eq commit.id
end
it 'supports a cross-project reference' do
- cross = double('project')
- expect(commit.to_reference(cross)).to eq "#{project.to_reference}@#{commit.id}"
+ another_project = build(:project, name: 'another-project', namespace: project.namespace)
+ expect(commit.to_reference(another_project)).to eq "sample-project@#{commit.id}"
end
end
describe '#reference_link_text' do
+ let(:project) { create(:project, path: 'sample-project') }
+ let(:commit) { project.commit }
+
it 'returns a String reference to the object' do
expect(commit.reference_link_text).to eq commit.short_id
end
it 'supports a cross-project reference' do
- cross = double('project')
- expect(commit.reference_link_text(cross)).to eq "#{project.to_reference}@#{commit.short_id}"
+ another_project = build(:project, name: 'another-project', namespace: project.namespace)
+ expect(commit.reference_link_text(another_project)).to eq "sample-project@#{commit.short_id}"
end
end
diff --git a/spec/models/discussion_spec.rb b/spec/models/discussion_spec.rb
index 2a67c60b978..bc32fadd391 100644
--- a/spec/models/discussion_spec.rb
+++ b/spec/models/discussion_spec.rb
@@ -521,6 +521,15 @@ describe Discussion, model: true do
end
end
+ describe "#first_note_to_resolve" do
+ it "returns the first not that still needs to be resolved" do
+ allow(first_note).to receive(:to_be_resolved?).and_return(false)
+ allow(second_note).to receive(:to_be_resolved?).and_return(true)
+
+ expect(subject.first_note_to_resolve).to eq(second_note)
+ end
+ end
+
describe "#collapsed?" do
context "when a diff discussion" do
before do
diff --git a/spec/models/group_label_spec.rb b/spec/models/group_label_spec.rb
index 2369658bf78..668aa6fb357 100644
--- a/spec/models/group_label_spec.rb
+++ b/spec/models/group_label_spec.rb
@@ -37,6 +37,16 @@ describe GroupLabel, models: true do
end
end
+ context 'cross-project' do
+ let(:namespace) { build_stubbed(:namespace) }
+ let(:source_project) { build_stubbed(:empty_project, name: 'project-1', namespace: namespace) }
+ let(:target_project) { build_stubbed(:empty_project, name: 'project-2', namespace: namespace) }
+
+ it 'returns a String reference to the object' do
+ expect(label.to_reference(source_project, target_project)).to eq %(project-1~#{label.id})
+ end
+ end
+
context 'using invalid format' do
it 'raises error' do
expect { label.to_reference(format: :invalid) }
diff --git a/spec/models/issue_spec.rb b/spec/models/issue_spec.rb
index 89e93dce8c5..24e216329a9 100644
--- a/spec/models/issue_spec.rb
+++ b/spec/models/issue_spec.rb
@@ -43,14 +43,16 @@ describe Issue, models: true do
end
describe '#to_reference' do
+ let(:project) { build(:empty_project, name: 'sample-project') }
+ let(:issue) { build(:issue, iid: 1, project: project) }
+
it 'returns a String reference to the object' do
- expect(subject.to_reference).to eq "##{subject.iid}"
+ expect(issue.to_reference).to eq "#1"
end
it 'supports a cross-project reference' do
- cross = double('project')
- expect(subject.to_reference(cross)).
- to eq "#{subject.project.to_reference}##{subject.iid}"
+ another_project = build(:project, name: 'another-project', namespace: project.namespace)
+ expect(issue.to_reference(another_project)).to eq "sample-project#1"
end
end
diff --git a/spec/models/merge_request_spec.rb b/spec/models/merge_request_spec.rb
index ec22ef93465..8b730be91fd 100644
--- a/spec/models/merge_request_spec.rb
+++ b/spec/models/merge_request_spec.rb
@@ -31,7 +31,7 @@ describe MergeRequest, models: true do
it { is_expected.to validate_presence_of(:target_branch) }
it { is_expected.to validate_presence_of(:source_branch) }
- context "Validation of merge user with Merge When Build succeeds" do
+ context "Validation of merge user with Merge When Pipeline Succeeds" do
it "allows user to be nil when the feature is disabled" do
expect(subject).to be_valid
end
@@ -142,13 +142,16 @@ describe MergeRequest, models: true do
end
describe '#to_reference' do
+ let(:project) { build(:empty_project, name: 'sample-project') }
+ let(:merge_request) { build(:merge_request, target_project: project, iid: 1) }
+
it 'returns a String reference to the object' do
- expect(subject.to_reference).to eq "!#{subject.iid}"
+ expect(merge_request.to_reference).to eq "!1"
end
it 'supports a cross-project reference' do
- cross = double('project')
- expect(subject.to_reference(cross)).to eq "#{subject.source_project.to_reference}!#{subject.iid}"
+ another_project = build(:project, name: 'another-project', namespace: project.namespace)
+ expect(merge_request.to_reference(another_project)).to eq "sample-project!1"
end
end
@@ -1124,6 +1127,46 @@ describe MergeRequest, models: true do
allow(subject).to receive(:diff_discussions).and_return([first_discussion, second_discussion, third_discussion])
end
+ describe '#resolvable_discussions' do
+ before do
+ allow(first_discussion).to receive(:to_be_resolved?).and_return(true)
+ allow(second_discussion).to receive(:to_be_resolved?).and_return(false)
+ allow(third_discussion).to receive(:to_be_resolved?).and_return(false)
+ end
+
+ it 'includes only discussions that need to be resolved' do
+ expect(subject.resolvable_discussions).to eq([first_discussion])
+ end
+ end
+
+ describe '#discussions_can_be_resolved_by? user' do
+ let(:user) { build(:user) }
+
+ context 'all discussions can be resolved by the user' do
+ before do
+ allow(first_discussion).to receive(:can_resolve?).with(user).and_return(true)
+ allow(second_discussion).to receive(:can_resolve?).with(user).and_return(true)
+ allow(third_discussion).to receive(:can_resolve?).with(user).and_return(true)
+ end
+
+ it 'allows a user to resolve the discussions' do
+ expect(subject.discussions_can_be_resolved_by?(user)).to be(true)
+ end
+ end
+
+ context 'one discussion cannot be resolved by the user' do
+ before do
+ allow(first_discussion).to receive(:can_resolve?).with(user).and_return(true)
+ allow(second_discussion).to receive(:can_resolve?).with(user).and_return(true)
+ allow(third_discussion).to receive(:can_resolve?).with(user).and_return(false)
+ end
+
+ it 'allows a user to resolve the discussions' do
+ expect(subject.discussions_can_be_resolved_by?(user)).to be(false)
+ end
+ end
+ end
+
describe "#discussions_resolvable?" do
context "when all discussions are unresolvable" do
before do
diff --git a/spec/models/milestone_spec.rb b/spec/models/milestone_spec.rb
index a4bfe851dfb..0cc2efae5f9 100644
--- a/spec/models/milestone_spec.rb
+++ b/spec/models/milestone_spec.rb
@@ -246,4 +246,18 @@ describe Milestone, models: true do
end
end
end
+
+ describe '#to_reference' do
+ let(:project) { build(:empty_project, name: 'sample-project') }
+ let(:milestone) { build(:milestone, iid: 1, project: project) }
+
+ it 'returns a String reference to the object' do
+ expect(milestone.to_reference).to eq "%1"
+ end
+
+ it 'supports a cross-project reference' do
+ another_project = build(:project, name: 'another-project', namespace: project.namespace)
+ expect(milestone.to_reference(another_project)).to eq "sample-project%1"
+ end
+ end
end
diff --git a/spec/models/project_label_spec.rb b/spec/models/project_label_spec.rb
index 18c9d449ee5..4d538cac007 100644
--- a/spec/models/project_label_spec.rb
+++ b/spec/models/project_label_spec.rb
@@ -105,14 +105,14 @@ describe ProjectLabel, models: true do
context 'using name' do
it 'returns cross reference with label name' do
expect(label.to_reference(project, format: :name))
- .to eq %Q(#{label.project.to_reference}~"#{label.name}")
+ .to eq %Q(#{label.project.path_with_namespace}~"#{label.name}")
end
end
context 'using id' do
it 'returns cross reference with label id' do
expect(label.to_reference(project, format: :id))
- .to eq %Q(#{label.project.to_reference}~#{label.id})
+ .to eq %Q(#{label.project.path_with_namespace}~#{label.id})
end
end
end
diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb
index f7c8c97fdee..4d57330ed1c 100644
--- a/spec/models/project_spec.rb
+++ b/spec/models/project_spec.rb
@@ -262,10 +262,70 @@ describe Project, models: true do
end
describe '#to_reference' do
- let(:project) { create(:empty_project) }
+ let(:owner) { create(:user, name: 'Gitlab') }
+ let(:namespace) { create(:namespace, path: 'sample-namespace', owner: owner) }
+ let(:project) { create(:empty_project, path: 'sample-project', namespace: namespace) }
+
+ context 'when nil argument' do
+ it 'returns nil' do
+ expect(project.to_reference).to be_nil
+ end
+ end
+
+ context 'when same project argument' do
+ it 'returns nil' do
+ expect(project.to_reference(project)).to be_nil
+ end
+ end
- it 'returns a String reference to the object' do
- expect(project.to_reference).to eq project.path_with_namespace
+ context 'when cross namespace project argument' do
+ let(:another_namespace_project) { create(:empty_project, name: 'another-project') }
+
+ it 'returns complete path to the project' do
+ expect(project.to_reference(another_namespace_project)).to eq 'sample-namespace/sample-project'
+ end
+ end
+
+ context 'when same namespace / cross-project argument' do
+ let(:another_project) { create(:empty_project, namespace: namespace) }
+
+ it 'returns complete path to the project' do
+ expect(project.to_reference(another_project)).to eq 'sample-project'
+ end
+ end
+ end
+
+ describe '#to_human_reference' do
+ let(:owner) { create(:user, name: 'Gitlab') }
+ let(:namespace) { create(:namespace, name: 'Sample namespace', owner: owner) }
+ let(:project) { create(:empty_project, name: 'Sample project', namespace: namespace) }
+
+ context 'when nil argument' do
+ it 'returns nil' do
+ expect(project.to_human_reference).to be_nil
+ end
+ end
+
+ context 'when same project argument' do
+ it 'returns nil' do
+ expect(project.to_human_reference(project)).to be_nil
+ end
+ end
+
+ context 'when cross namespace project argument' do
+ let(:another_namespace_project) { create(:empty_project, name: 'another-project') }
+
+ it 'returns complete name with namespace of the project' do
+ expect(project.to_human_reference(another_namespace_project)).to eq 'Gitlab / Sample project'
+ end
+ end
+
+ context 'when same namespace / cross-project argument' do
+ let(:another_project) { create(:empty_project, namespace: namespace) }
+
+ it 'returns name of the project' do
+ expect(project.to_human_reference(another_project)).to eq 'Sample project'
+ end
end
end
diff --git a/spec/models/repository_spec.rb b/spec/models/repository_spec.rb
index b797d19161d..d9b0e63eeb6 100644
--- a/spec/models/repository_spec.rb
+++ b/spec/models/repository_spec.rb
@@ -768,7 +768,6 @@ describe Repository, models: true do
expect(repository).not_to receive(:expire_root_ref_cache)
expect(repository).not_to receive(:expire_emptiness_caches)
expect(repository).to receive(:expire_branches_cache)
- expect(repository).to receive(:expire_has_visible_content_cache)
repository.update_branch_with_hooks(user, 'new-feature') { new_rev }
end
@@ -786,7 +785,6 @@ describe Repository, models: true do
expect(empty_repository).to receive(:expire_root_ref_cache)
expect(empty_repository).to receive(:expire_emptiness_caches)
expect(empty_repository).to receive(:expire_branches_cache)
- expect(empty_repository).to receive(:expire_has_visible_content_cache)
empty_repository.commit_file(user, 'CHANGELOG', 'Changelog!',
'Updates file content', 'master', false)
@@ -829,15 +827,6 @@ describe Repository, models: true do
expect(subject).to eq(true)
end
-
- it 'caches the output' do
- expect(repository).to receive(:branch_count).
- once.
- and_return(3)
-
- repository.has_visible_content?
- repository.has_visible_content?
- end
end
end
@@ -918,20 +907,6 @@ describe Repository, models: true do
end
end
- describe '#expire_has_visible_content_cache' do
- it 'expires the visible content cache' do
- repository.has_visible_content?
-
- expect(repository).to receive(:branch_count).
- once.
- and_return(0)
-
- repository.expire_has_visible_content_cache
-
- expect(repository.has_visible_content?).to eq(false)
- end
- end
-
describe '#expire_branch_cache' do
# This method is private but we need it for testing purposes. Sadly there's
# no other proper way of testing caching operations.
@@ -967,7 +942,6 @@ describe Repository, models: true do
allow(repository).to receive(:empty?).and_return(true)
expect(cache).to receive(:expire).with(:empty?)
- expect(repository).to receive(:expire_has_visible_content_cache)
repository.expire_emptiness_caches
end
@@ -976,7 +950,6 @@ describe Repository, models: true do
allow(repository).to receive(:empty?).and_return(false)
expect(cache).not_to receive(:expire).with(:empty?)
- expect(repository).not_to receive(:expire_has_visible_content_cache)
repository.expire_emptiness_caches
end
@@ -1204,7 +1177,7 @@ describe Repository, models: true do
describe '#after_create_branch' do
it 'flushes the visible content cache' do
- expect(repository).to receive(:expire_has_visible_content_cache)
+ expect(repository).to receive(:expire_branches_cache)
repository.after_create_branch
end
@@ -1212,7 +1185,7 @@ describe Repository, models: true do
describe '#after_remove_branch' do
it 'flushes the visible content cache' do
- expect(repository).to receive(:expire_has_visible_content_cache)
+ expect(repository).to receive(:expire_branches_cache)
repository.after_remove_branch
end
diff --git a/spec/models/snippet_spec.rb b/spec/models/snippet_spec.rb
index 279dc30c357..7425a897769 100644
--- a/spec/models/snippet_spec.rb
+++ b/spec/models/snippet_spec.rb
@@ -33,16 +33,31 @@ describe Snippet, models: true do
end
describe '#to_reference' do
- let(:project) { create(:empty_project) }
- let(:snippet) { create(:snippet, project: project) }
+ context 'when snippet belongs to a project' do
+ let(:project) { build(:empty_project, name: 'sample-project') }
+ let(:snippet) { build(:snippet, id: 1, project: project) }
+
+ it 'returns a String reference to the object' do
+ expect(snippet.to_reference).to eq "$1"
+ end
- it 'returns a String reference to the object' do
- expect(snippet.to_reference).to eq "$#{snippet.id}"
+ it 'supports a cross-project reference' do
+ another_project = build(:project, name: 'another-project', namespace: project.namespace)
+ expect(snippet.to_reference(another_project)).to eq "sample-project$1"
+ end
end
- it 'supports a cross-project reference' do
- cross = double('project')
- expect(snippet.to_reference(cross)).to eq "#{project.to_reference}$#{snippet.id}"
+ context 'when snippet does not belong to a project' do
+ let(:snippet) { build(:snippet, id: 1, project: nil) }
+
+ it 'returns a String reference to the object' do
+ expect(snippet.to_reference).to eq "$1"
+ end
+
+ it 'still returns shortest reference when project arg present' do
+ another_project = build(:project, name: 'another-project')
+ expect(snippet.to_reference(another_project)).to eq "$1"
+ end
end
end
diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb
index 95fe2dc65d9..bad6ed9e146 100644
--- a/spec/models/user_spec.rb
+++ b/spec/models/user_spec.rb
@@ -575,6 +575,23 @@ describe User, models: true do
end
end
end
+
+ describe '#require_ssh_key?' do
+ protocol_and_expectation = {
+ 'http' => false,
+ 'ssh' => true,
+ '' => true,
+ }
+
+ protocol_and_expectation.each do |protocol, expected|
+ it "has correct require_ssh_key?" do
+ stub_application_setting(enabled_git_access_protocol: protocol)
+ user = build(:user)
+
+ expect(user.require_ssh_key?).to eq(expected)
+ end
+ end
+ end
end
describe '.find_by_any_email' do
diff --git a/spec/policies/project_policy_spec.rb b/spec/policies/project_policy_spec.rb
index b49e4f3a8bc..eeab9827d99 100644
--- a/spec/policies/project_policy_spec.rb
+++ b/spec/policies/project_policy_spec.rb
@@ -111,14 +111,36 @@ describe ProjectPolicy, models: true do
context 'guests' do
let(:current_user) { guest }
+ let(:reporter_public_build_permissions) do
+ reporter_permissions - [:read_build, :read_pipeline]
+ end
+
it do
is_expected.to include(*guest_permissions)
- is_expected.not_to include(*reporter_permissions)
+ is_expected.not_to include(*reporter_public_build_permissions)
is_expected.not_to include(*team_member_reporter_permissions)
is_expected.not_to include(*developer_permissions)
is_expected.not_to include(*master_permissions)
is_expected.not_to include(*owner_permissions)
end
+
+ context 'public builds enabled' do
+ it do
+ is_expected.to include(*guest_permissions)
+ is_expected.to include(:read_build, :read_pipeline)
+ end
+ end
+
+ context 'public builds disabled' do
+ before do
+ project.update(public_builds: false)
+ end
+
+ it do
+ is_expected.to include(*guest_permissions)
+ is_expected.not_to include(:read_build, :read_pipeline)
+ end
+ end
end
context 'reporter' do
diff --git a/spec/requests/api/builds_spec.rb b/spec/requests/api/builds_spec.rb
index 0ea991b18b8..7be7acebb19 100644
--- a/spec/requests/api/builds_spec.rb
+++ b/spec/requests/api/builds_spec.rb
@@ -5,7 +5,7 @@ describe API::Builds, api: true do
let(:user) { create(:user) }
let(:api_user) { user }
- let!(:project) { create(:project, creator_id: user.id) }
+ let!(:project) { create(:project, creator_id: user.id, public_builds: false) }
let!(:developer) { create(:project_member, :developer, user: user, project: project) }
let(:reporter) { create(:project_member, :reporter, project: project) }
let(:guest) { create(:project_member, :guest, project: project) }
diff --git a/spec/requests/api/commits_spec.rb b/spec/requests/api/commits_spec.rb
index 52491e1b9ed..e497bce6943 100644
--- a/spec/requests/api/commits_spec.rb
+++ b/spec/requests/api/commits_spec.rb
@@ -18,11 +18,14 @@ describe API::Commits, api: true do
before { project.team << [user2, :reporter] }
it "returns project commits" do
+ commit = project.repository.commit
get api("/projects/#{project.id}/repository/commits", user)
- expect(response).to have_http_status(200)
+ expect(response).to have_http_status(200)
expect(json_response).to be_an Array
- expect(json_response.first['id']).to eq(project.repository.commit.id)
+ expect(json_response.first['id']).to eq(commit.id)
+ expect(json_response.first['committer_name']).to eq(commit.committer_name)
+ expect(json_response.first['committer_email']).to eq(commit.committer_email)
end
end
@@ -134,6 +137,8 @@ describe API::Commits, api: true do
expect(response).to have_http_status(201)
expect(json_response['title']).to eq(message)
+ expect(json_response['committer_name']).to eq(user.name)
+ expect(json_response['committer_email']).to eq(user.email)
end
it 'returns a 400 bad request if file exists' do
diff --git a/spec/requests/api/issues_spec.rb b/spec/requests/api/issues_spec.rb
index 5700f800c2e..553983575c4 100644
--- a/spec/requests/api/issues_spec.rb
+++ b/spec/requests/api/issues_spec.rb
@@ -692,6 +692,32 @@ describe API::Issues, api: true do
])
end
+ context 'resolving issues in a merge request' do
+ let(:discussion) { Discussion.for_diff_notes([create(:diff_note_on_merge_request)]).first }
+ let(:merge_request) { discussion.noteable }
+ let(:project) { merge_request.source_project }
+ before do
+ project.team << [user, :master]
+ post api("/projects/#{project.id}/issues", user),
+ title: 'New Issue',
+ merge_request_for_resolving_discussions: merge_request.iid
+ end
+
+ it 'creates a new project issue' do
+ expect(response).to have_http_status(:created)
+ end
+
+ it 'resolves the discussions in a merge request' do
+ discussion.first_note.reload
+
+ expect(discussion.resolved?).to be(true)
+ end
+
+ it 'assigns a description to the issue mentioning the merge request' do
+ expect(json_response['description']).to include(merge_request.to_reference)
+ end
+ end
+
context 'with due date' do
it 'creates a new project issue' do
due_date = 2.weeks.from_now.strftime('%Y-%m-%d')
diff --git a/spec/requests/api/merge_requests_spec.rb b/spec/requests/api/merge_requests_spec.rb
index 918a71129f7..0b89ac7960e 100644
--- a/spec/requests/api/merge_requests_spec.rb
+++ b/spec/requests/api/merge_requests_spec.rb
@@ -465,7 +465,7 @@ describe API::MergeRequests, api: true do
expect(response).to have_http_status(200)
end
- it "enables merge when build succeeds if the ci is active" do
+ it "enables merge when pipeline succeeds if the pipeline is active" do
allow_any_instance_of(MergeRequest).to receive(:head_pipeline).and_return(pipeline)
allow(pipeline).to receive(:active?).and_return(true)
diff --git a/spec/requests/projects/cycle_analytics_events_spec.rb b/spec/requests/projects/cycle_analytics_events_spec.rb
index f5e0fdcda2d..e0368e6001f 100644
--- a/spec/requests/projects/cycle_analytics_events_spec.rb
+++ b/spec/requests/projects/cycle_analytics_events_spec.rb
@@ -2,7 +2,7 @@ require 'spec_helper'
describe 'cycle analytics events' do
let(:user) { create(:user) }
- let(:project) { create(:project) }
+ let(:project) { create(:project, public_builds: false) }
let(:issue) { create(:issue, project: project, created_at: 2.days.ago) }
describe 'GET /:namespace/:project/cycle_analytics/events/issues' do
diff --git a/spec/services/discussions/resolve_service_spec.rb b/spec/services/discussions/resolve_service_spec.rb
new file mode 100644
index 00000000000..12c3cdf28c6
--- /dev/null
+++ b/spec/services/discussions/resolve_service_spec.rb
@@ -0,0 +1,52 @@
+require 'spec_helper'
+
+describe Discussions::ResolveService do
+ describe '#execute' do
+ let(:discussion) { Discussion.for_diff_notes([create(:diff_note_on_merge_request)]).first }
+ let(:project) { merge_request.project }
+ let(:merge_request) { discussion.noteable }
+ let(:user) { create(:user) }
+ let(:service) { described_class.new(discussion.noteable.project, user, merge_request: merge_request) }
+
+ before do
+ project.team << [user, :master]
+ end
+
+ it "doesn't resolve discussions the user can't resolve" do
+ expect(discussion).to receive(:can_resolve?).with(user).and_return(false)
+
+ service.execute(discussion)
+
+ expect(discussion.resolved?).to be(false)
+ end
+
+ it 'resolves the discussion' do
+ service.execute(discussion)
+
+ expect(discussion.resolved?).to be(true)
+ end
+
+ it 'executes the notification service' do
+ expect_any_instance_of(MergeRequests::ResolvedDiscussionNotificationService).to receive(:execute).with(discussion.noteable)
+
+ service.execute(discussion)
+ end
+
+ it 'adds a system note to the discussion' do
+ issue = create(:issue, project: project)
+
+ expect(SystemNoteService).to receive(:discussion_continued_in_issue).with(discussion, project, user, issue)
+ service = described_class.new(project, user, merge_request: merge_request, follow_up_issue: issue)
+ service.execute(discussion)
+ end
+
+ it 'can resolve multiple discussions at once' do
+ other_discussion = Discussion.for_diff_notes([create(:diff_note_on_merge_request, noteable: discussion.noteable, project: discussion.noteable.source_project)]).first
+
+ service.execute([discussion, other_discussion])
+
+ expect(discussion.resolved?).to be(true)
+ expect(other_discussion.resolved?).to be(true)
+ end
+ end
+end
diff --git a/spec/services/issues/build_service_spec.rb b/spec/services/issues/build_service_spec.rb
new file mode 100644
index 00000000000..4cfba35c830
--- /dev/null
+++ b/spec/services/issues/build_service_spec.rb
@@ -0,0 +1,130 @@
+require 'spec_helper.rb'
+
+describe Issues::BuildService, services: true do
+ let(:project) { create(:project) }
+ let(:user) { create(:user) }
+
+ before do
+ project.team << [user, :developer]
+ end
+
+ context 'for discussions in a merge request' do
+ let(:merge_request) { create(:merge_request_with_diff_notes, source_project: project) }
+ let(:issue) { described_class.new(project, user, merge_request_for_resolving_discussions: merge_request).execute }
+
+ def position_on_line(line_number)
+ Gitlab::Diff::Position.new(
+ old_path: "files/ruby/popen.rb",
+ new_path: "files/ruby/popen.rb",
+ old_line: nil,
+ new_line: line_number,
+ diff_refs: merge_request.diff_refs
+ )
+ end
+
+ describe '#items_for_discussions' do
+ it 'has an item for each discussion' do
+ create(:diff_note_on_merge_request, noteable: merge_request, project: merge_request.source_project, position: position_on_line(13))
+ service = described_class.new(project, user, merge_request_for_resolving_discussions: merge_request)
+
+ service.execute
+
+ expect(service.items_for_discussions.size).to eq(2)
+ end
+ end
+
+ describe '#item_for_discussion' do
+ let(:service) { described_class.new(project, user, merge_request_for_resolving_discussions: merge_request) }
+
+ it 'mentions the author of the note' do
+ discussion = Discussion.new([create(:diff_note_on_merge_request, author: create(:user, username: 'author'))])
+ expect(service.item_for_discussion(discussion)).to include('@author')
+ end
+
+ it 'wraps the note in a blockquote' do
+ note_text = "This is a string\n"\
+ ">>>\n"\
+ "with a blockquote\n"\
+ "> That has a quote\n"\
+ ">>>\n"
+ note_result = "This is a string\n"\
+ "> with a blockquote\n"\
+ "> > That has a quote\n"
+ discussion = Discussion.new([create(:diff_note_on_merge_request, note: note_text)])
+ expect(service.item_for_discussion(discussion)).to include(">>>\n#{note_result}\n>>>")
+ end
+ end
+
+ describe '#execute' do
+ it 'has the merge request reference in the title' do
+ expect(issue.title).to include(merge_request.title)
+ end
+
+ it 'has the reference of the merge request in the description' do
+ expect(issue.description).to include(merge_request.to_reference)
+ end
+
+ it 'does not assign title when a title was given' do
+ issue = described_class.new(project, user,
+ merge_request_for_resolving_discussions: merge_request,
+ title: 'What an issue').execute
+
+ expect(issue.title).to eq('What an issue')
+ end
+
+ it 'does not assign description when a description was given' do
+ issue = described_class.new(project, user,
+ merge_request_for_resolving_discussions: merge_request,
+ description: 'Fix at your earliest conveignance').execute
+
+ expect(issue.description).to eq('Fix at your earliest conveignance')
+ end
+
+ describe 'with multiple discussions' do
+ before do
+ create(:diff_note_on_merge_request, noteable: merge_request, project: merge_request.target_project, position: position_on_line(15))
+ end
+
+ it 'mentions all the authors in the description' do
+ authors = merge_request.diff_discussions.map(&:author)
+
+ expect(issue.description).to include(*authors.map(&:to_reference))
+ end
+
+ it 'has a link for each unresolved discussion in the description' do
+ notes = merge_request.diff_discussions.map(&:first_note)
+ links = notes.map { |note| Gitlab::UrlBuilder.build(note) }
+
+ expect(issue.description).to include(*links)
+ end
+
+ it 'mentions additional notes' do
+ create_list(:diff_note_on_merge_request, 2, noteable: merge_request, project: merge_request.target_project, position: position_on_line(15))
+
+ expect(issue.description).to include('(+2 comments)')
+ end
+ end
+ end
+ end
+
+ context 'For a merge request without discussions' do
+ let(:merge_request) { create(:merge_request, source_project: project) }
+
+ describe '#execute' do
+ it 'mentions the merge request in the description' do
+ issue = described_class.new(project, user, merge_request_for_resolving_discussions: merge_request).execute
+
+ expect(issue.description).to include("Review the conversation in #{merge_request.to_reference}")
+ end
+ end
+ end
+
+ describe '#execute' do
+ it 'builds a new issues with given params' do
+ issue = described_class.new(project, user, title: 'Issue #1', description: 'Issue description').execute
+
+ expect(issue.title).to eq('Issue #1')
+ expect(issue.description).to eq('Issue description')
+ end
+ end
+end
diff --git a/spec/services/issues/create_service_spec.rb b/spec/services/issues/create_service_spec.rb
index 5c0331ebe66..8bde61ee336 100644
--- a/spec/services/issues/create_service_spec.rb
+++ b/spec/services/issues/create_service_spec.rb
@@ -136,5 +136,48 @@ describe Issues::CreateService, services: true do
end
it_behaves_like 'new issuable record that supports slash commands'
+
+ context 'for a merge request' do
+ let(:discussion) { Discussion.for_diff_notes([create(:diff_note_on_merge_request)]).first }
+ let(:merge_request) { discussion.noteable }
+ let(:project) { merge_request.source_project }
+ let(:opts) { { merge_request_for_resolving_discussions: merge_request } }
+
+ before do
+ project.team << [user, :master]
+ end
+
+ it 'resolves the discussion for the merge request' do
+ described_class.new(project, user, opts).execute
+ discussion.first_note.reload
+
+ expect(discussion.resolved?).to be(true)
+ end
+
+ it 'added a system note to the discussion' do
+ described_class.new(project, user, opts).execute
+
+ reloaded_discussion = MergeRequest.find(merge_request.id).discussions.first
+
+ expect(reloaded_discussion.last_note.system).to eq(true)
+ end
+
+ it 'assigns the title and description for the issue' do
+ issue = described_class.new(project, user, opts).execute
+
+ expect(issue.title).not_to be_nil
+ expect(issue.description).not_to be_nil
+ end
+
+ it 'can set nil explicityly to the title and description' do
+ issue = described_class.new(project, user,
+ merge_request_for_resolving_discussions: merge_request,
+ description: nil,
+ title: nil).execute
+
+ expect(issue.description).to be_nil
+ expect(issue.title).to be_nil
+ end
+ end
end
end
diff --git a/spec/services/issues/move_service_spec.rb b/spec/services/issues/move_service_spec.rb
index c7de0d0c534..db196ed5751 100644
--- a/spec/services/issues/move_service_spec.rb
+++ b/spec/services/issues/move_service_spec.rb
@@ -189,7 +189,7 @@ describe Issues::MoveService, services: true do
it 'rewrites references using a cross reference to old project' do
expect(new_note.note)
- .to eq "Note with reference to merge request #{old_project.to_reference}!1"
+ .to eq "Note with reference to merge request #{old_project.to_reference(new_project)}!1"
end
end
@@ -217,7 +217,7 @@ describe Issues::MoveService, services: true do
it 'rewrites referenced issues creating cross project reference' do
expect(new_issue.description)
- .to eq "Some description #{old_project.to_reference}#{another_issue.to_reference}"
+ .to eq "Some description #{another_issue.to_reference(new_project)}"
end
end
diff --git a/spec/services/merge_requests/merge_when_build_succeeds_service_spec.rb b/spec/services/merge_requests/merge_when_pipeline_succeeds_service_spec.rb
index 963d9573ac4..f92978a33a3 100644
--- a/spec/services/merge_requests/merge_when_build_succeeds_service_spec.rb
+++ b/spec/services/merge_requests/merge_when_pipeline_succeeds_service_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe MergeRequests::MergeWhenBuildSucceedsService do
+describe MergeRequests::MergeWhenPipelineSucceedsService do
let(:user) { create(:user) }
let(:project) { create(:project) }
@@ -10,8 +10,14 @@ describe MergeRequests::MergeWhenBuildSucceedsService do
source_project: project, target_project: project, state: "opened")
end
- let(:pipeline) { create(:ci_pipeline_with_one_job, ref: mr_merge_if_green_enabled.source_branch, project: project) }
- let(:service) { MergeRequests::MergeWhenBuildSucceedsService.new(project, user, commit_message: 'Awesome message') }
+ let(:pipeline) do
+ create(:ci_pipeline_with_one_job, ref: mr_merge_if_green_enabled.source_branch,
+ project: project)
+ end
+
+ let(:service) do
+ described_class.new(project, user, commit_message: 'Awesome message')
+ end
describe "#execute" do
let(:merge_request) do
@@ -37,12 +43,12 @@ describe MergeRequests::MergeWhenBuildSucceedsService do
it 'creates a system note' do
note = merge_request.notes.last
- expect(note.note).to match /enabled an automatic merge when the build for (\w+\/\w+@)?\h{8}/
+ expect(note.note).to match /enabled an automatic merge when the pipeline for (\w+\/\w+@)?\h{8}/
end
end
context 'already approved' do
- let(:service) { MergeRequests::MergeWhenBuildSucceedsService.new(project, user, new_key: true) }
+ let(:service) { described_class.new(project, user, new_key: true) }
let(:build) { create(:ci_build, ref: mr_merge_if_green_enabled.source_branch) }
before do
diff --git a/spec/services/projects/create_service_spec.rb b/spec/services/projects/create_service_spec.rb
index fbd22560d6e..a1539b69401 100644
--- a/spec/services/projects/create_service_spec.rb
+++ b/spec/services/projects/create_service_spec.rb
@@ -1,150 +1,150 @@
require 'spec_helper'
-describe Projects::CreateService, services: true do
- describe :create_by_user do
- before do
- @user = create :user
- @opts = {
- name: "GitLab",
- namespace: @user.namespace
- }
- end
+describe Projects::CreateService, '#execute', services: true do
+ let(:user) { create :user }
+ let(:opts) do
+ {
+ name: "GitLab",
+ namespace: user.namespace
+ }
+ end
- it 'creates labels on Project creation if there are templates' do
- Label.create(title: "bug", template: true)
- project = create_project(@user, @opts)
- project.reload
+ it 'creates labels on Project creation if there are templates' do
+ Label.create(title: "bug", template: true)
+ project = create_project(user, opts)
- expect(project.labels).not_to be_empty
- end
+ expect(project.labels).not_to be_empty
+ end
- context 'user namespace' do
- before do
- @project = create_project(@user, @opts)
- end
+ context 'user namespace' do
+ it do
+ project = create_project(user, opts)
- it { expect(@project).to be_valid }
- it { expect(@project.owner).to eq(@user) }
- it { expect(@project.team.masters).to include(@user) }
- it { expect(@project.namespace).to eq(@user.namespace) }
+ expect(project).to be_valid
+ expect(project.owner).to eq(user)
+ expect(project.team.masters).to include(user)
+ expect(project.namespace).to eq(user.namespace)
end
+ end
- context 'group namespace' do
- before do
- @group = create :group
- @group.add_owner(@user)
+ context 'group namespace' do
+ let(:group) do
+ create(:group).tap do |group|
+ group.add_owner(user)
+ end
+ end
- @user.refresh_authorized_projects # Ensure cache is warm
+ before do
+ user.refresh_authorized_projects # Ensure cache is warm
+ end
- @opts.merge!(namespace_id: @group.id)
- @project = create_project(@user, @opts)
- end
+ it do
+ project = create_project(user, opts.merge!(namespace_id: group.id))
- it { expect(@project).to be_valid }
- it { expect(@project.owner).to eq(@group) }
- it { expect(@project.namespace).to eq(@group) }
- it { expect(@user.authorized_projects).to include(@project) }
+ expect(project).to be_valid
+ expect(project.owner).to eq(group)
+ expect(project.namespace).to eq(group)
+ expect(user.authorized_projects).to include(project)
end
+ end
- context 'error handling' do
- it 'handles invalid options' do
- @opts.merge!({ default_branch: 'master' } )
- expect(create_project(@user, @opts)).to eq(nil)
- end
+ context 'error handling' do
+ it 'handles invalid options' do
+ opts.merge!({ default_branch: 'master' } )
+ expect(create_project(user, opts)).to eq(nil)
end
+ end
- context 'wiki_enabled creates repository directory' do
- context 'wiki_enabled true creates wiki repository directory' do
- before do
- @project = create_project(@user, @opts)
- @path = ProjectWiki.new(@project, @user).send(:path_to_repo)
- end
+ context 'wiki_enabled creates repository directory' do
+ context 'wiki_enabled true creates wiki repository directory' do
+ it do
+ project = create_project(user, opts)
+ path = ProjectWiki.new(project, user).send(:path_to_repo)
- it { expect(File.exist?(@path)).to be_truthy }
+ expect(File.exist?(path)).to be_truthy
end
+ end
- context 'wiki_enabled false does not create wiki repository directory' do
- before do
- @opts.merge!(wiki_enabled: false)
- @project = create_project(@user, @opts)
- @path = ProjectWiki.new(@project, @user).send(:path_to_repo)
- end
+ context 'wiki_enabled false does not create wiki repository directory' do
+ it do
+ opts.merge!(wiki_enabled: false)
+ project = create_project(user, opts)
+ path = ProjectWiki.new(project, user).send(:path_to_repo)
- it { expect(File.exist?(@path)).to be_falsey }
+ expect(File.exist?(path)).to be_falsey
end
end
+ end
- context 'builds_enabled global setting' do
- let(:project) { create_project(@user, @opts) }
-
- subject { project.builds_enabled? }
+ context 'builds_enabled global setting' do
+ let(:project) { create_project(user, opts) }
- context 'global builds_enabled false does not enable CI by default' do
- before do
- project.project_feature.update_attribute(:builds_access_level, ProjectFeature::DISABLED)
- end
+ subject { project.builds_enabled? }
- it { is_expected.to be_falsey }
+ context 'global builds_enabled false does not enable CI by default' do
+ before do
+ project.project_feature.update_attribute(:builds_access_level, ProjectFeature::DISABLED)
end
- context 'global builds_enabled true does enable CI by default' do
- before do
- project.project_feature.update_attribute(:builds_access_level, ProjectFeature::ENABLED)
- end
+ it { is_expected.to be_falsey }
+ end
- it { is_expected.to be_truthy }
+ context 'global builds_enabled true does enable CI by default' do
+ before do
+ project.project_feature.update_attribute(:builds_access_level, ProjectFeature::ENABLED)
end
+
+ it { is_expected.to be_truthy }
end
+ end
- context 'restricted visibility level' do
- before do
- stub_application_setting(restricted_visibility_levels: [Gitlab::VisibilityLevel::PUBLIC])
+ context 'restricted visibility level' do
+ before do
+ stub_application_setting(restricted_visibility_levels: [Gitlab::VisibilityLevel::PUBLIC])
- @opts.merge!(
- visibility_level: Gitlab::VisibilityLevel.options['Public']
- )
- end
+ opts.merge!(
+ visibility_level: Gitlab::VisibilityLevel.options['Public']
+ )
+ end
- it 'does not allow a restricted visibility level for non-admins' do
- project = create_project(@user, @opts)
- expect(project).to respond_to(:errors)
- expect(project.errors.messages).to have_key(:visibility_level)
- expect(project.errors.messages[:visibility_level].first).to(
- match('restricted by your GitLab administrator')
- )
- end
+ it 'does not allow a restricted visibility level for non-admins' do
+ project = create_project(user, opts)
+ expect(project).to respond_to(:errors)
+ expect(project.errors.messages).to have_key(:visibility_level)
+ expect(project.errors.messages[:visibility_level].first).to(
+ match('restricted by your GitLab administrator')
+ )
+ end
- it 'allows a restricted visibility level for admins' do
- admin = create(:admin)
- project = create_project(admin, @opts)
+ it 'allows a restricted visibility level for admins' do
+ admin = create(:admin)
+ project = create_project(admin, opts)
- expect(project.errors.any?).to be(false)
- expect(project.saved?).to be(true)
- end
+ expect(project.errors.any?).to be(false)
+ expect(project.saved?).to be(true)
end
+ end
- context 'repository creation' do
- it 'synchronously creates the repository' do
- expect_any_instance_of(Project).to receive(:create_repository)
+ context 'repository creation' do
+ it 'synchronously creates the repository' do
+ expect_any_instance_of(Project).to receive(:create_repository)
- project = create_project(@user, @opts)
- expect(project).to be_valid
- expect(project.owner).to eq(@user)
- expect(project.namespace).to eq(@user.namespace)
- end
+ project = create_project(user, opts)
+ expect(project).to be_valid
+ expect(project.owner).to eq(user)
+ expect(project.namespace).to eq(user.namespace)
end
+ end
- context 'when there is an active service template' do
- before do
- create(:service, project: nil, template: true, active: true)
- end
+ context 'when there is an active service template' do
+ before do
+ create(:service, project: nil, template: true, active: true)
+ end
- it 'creates a service from this template' do
- project = create_project(@user, @opts)
- project.reload
+ it 'creates a service from this template' do
+ project = create_project(user, opts)
- expect(project.services.count).to eq 1
- end
+ expect(project.services.count).to eq 1
end
end
diff --git a/spec/services/system_note_service_spec.rb b/spec/services/system_note_service_spec.rb
index 4a8f6c321aa..90b7e62bc6f 100644
--- a/spec/services/system_note_service_spec.rb
+++ b/spec/services/system_note_service_spec.rb
@@ -225,8 +225,8 @@ describe SystemNoteService, services: true do
it_behaves_like 'a system note'
- it "posts the Merge When Build Succeeds system note" do
- expect(subject.note).to match /enabled an automatic merge when the build for (\w+\/\w+@)?\h{40} succeeds/
+ it "posts the 'merge when pipeline succeeds' system note" do
+ expect(subject.note).to match /enabled an automatic merge when the pipeline for (\w+\/\w+@)?\h{40} succeeds/
end
end
@@ -239,7 +239,7 @@ describe SystemNoteService, services: true do
it_behaves_like 'a system note'
- it "posts the Merge When Build Succeeds system note" do
+ it "posts the 'merge when pipeline succeeds' system note" do
expect(subject.note).to eq "canceled the automatic merge"
end
end
@@ -530,7 +530,7 @@ describe SystemNoteService, services: true do
end
it 'mentions referenced project' do
- expect(subject.note).to include new_project.to_reference
+ expect(subject.note).to include new_project.path_with_namespace
end
end
@@ -712,4 +712,32 @@ describe SystemNoteService, services: true do
end
end
end
+
+ describe '.discussion_continued_in_issue' do
+ let(:discussion) { Discussion.for_diff_notes([create(:diff_note_on_merge_request)]).first }
+ let(:merge_request) { discussion.noteable }
+ let(:project) { merge_request.source_project }
+ let(:issue) { create(:issue, project: project) }
+ let(:user) { create(:user) }
+
+ def reloaded_merge_request
+ MergeRequest.find(merge_request.id)
+ end
+
+ before do
+ project.team << [user, :developer]
+ end
+
+ it 'creates a new note in the discussion' do
+ # we need to completely rebuild the merge request object, or the `@discussions` on the merge request are not reloaded.
+ expect { SystemNoteService.discussion_continued_in_issue(discussion, project, user, issue) }.
+ to change { reloaded_merge_request.discussions.first.notes.size }.by(1)
+ end
+
+ it 'mentions the created issue in the system note' do
+ note = SystemNoteService.discussion_continued_in_issue(discussion, project, user, issue)
+
+ expect(note.note).to include(issue.to_reference)
+ end
+ end
end
diff --git a/spec/workers/pipeline_notification_worker_spec.rb b/spec/workers/pipeline_notification_worker_spec.rb
index 739f9b63967..603ae52ed1e 100644
--- a/spec/workers/pipeline_notification_worker_spec.rb
+++ b/spec/workers/pipeline_notification_worker_spec.rb
@@ -11,7 +11,7 @@ describe PipelineNotificationWorker do
status: status)
end
- let(:project) { create(:project) }
+ let(:project) { create(:project, public_builds: false) }
let(:user) { create(:user) }
let(:pusher) { user }
let(:watcher) { pusher }
diff --git a/spec/workers/pipeline_success_worker_spec.rb b/spec/workers/pipeline_success_worker_spec.rb
index 5e31cc2c8e7..d1c84adda6f 100644
--- a/spec/workers/pipeline_success_worker_spec.rb
+++ b/spec/workers/pipeline_success_worker_spec.rb
@@ -7,7 +7,7 @@ describe PipelineSuccessWorker do
it 'performs "merge when pipeline succeeds"' do
expect_any_instance_of(
- MergeRequests::MergeWhenBuildSucceedsService
+ MergeRequests::MergeWhenPipelineSucceedsService
).to receive(:trigger)
described_class.new.perform(pipeline.id)