summaryrefslogtreecommitdiff
path: root/app
diff options
context:
space:
mode:
Diffstat (limited to 'app')
-rw-r--r--[-rwxr-xr-x]app/assets/fonts/SourceSansPro-Black.ttfbin148368 -> 289364 bytes
-rw-r--r--app/assets/fonts/SourceSansPro-BlackIt.ttfbin0 -> 103404 bytes
-rw-r--r--[-rwxr-xr-x]app/assets/fonts/SourceSansPro-Bold.ttfbin291424 -> 291424 bytes
-rw-r--r--app/assets/fonts/SourceSansPro-BoldIt.ttfbin0 -> 103608 bytes
-rw-r--r--[-rwxr-xr-x]app/assets/fonts/SourceSansPro-ExtraLight.ttfbin150528 -> 291652 bytes
-rw-r--r--app/assets/fonts/SourceSansPro-ExtraLightIt.ttfbin0 -> 104768 bytes
-rw-r--r--app/assets/fonts/SourceSansPro-It.ttfbin0 -> 104236 bytes
-rw-r--r--[-rwxr-xr-x]app/assets/fonts/SourceSansPro-Light.ttfbin293220 -> 293220 bytes
-rw-r--r--app/assets/fonts/SourceSansPro-LightIt.ttfbin0 -> 104616 bytes
-rw-r--r--[-rwxr-xr-x]app/assets/fonts/SourceSansPro-Regular.ttfbin293956 -> 293956 bytes
-rw-r--r--[-rwxr-xr-x]app/assets/fonts/SourceSansPro-Semibold.ttfbin292404 -> 292404 bytes
-rw-r--r--app/assets/fonts/SourceSansPro-SemiboldIt.ttfbin0 -> 104020 bytes
-rw-r--r--app/assets/images/logo.svg16
-rw-r--r--app/assets/javascripts/blob/edit_blob.js.coffee8
-rw-r--r--app/assets/javascripts/blob/new_blob.js.coffee8
-rw-r--r--app/assets/javascripts/calendar.js.coffee2
-rw-r--r--app/assets/javascripts/ci/build.coffee4
-rw-r--r--app/assets/javascripts/copy_to_clipboard.js.coffee21
-rw-r--r--app/assets/javascripts/merge_request_tabs.js.coffee8
-rw-r--r--app/assets/javascripts/shortcuts_navigation.coffee1
-rw-r--r--app/assets/stylesheets/framework/blocks.scss50
-rw-r--r--app/assets/stylesheets/framework/buttons.scss15
-rw-r--r--app/assets/stylesheets/framework/common.scss10
-rw-r--r--app/assets/stylesheets/framework/files.scss5
-rw-r--r--app/assets/stylesheets/framework/lists.scss2
-rw-r--r--app/assets/stylesheets/framework/mixins.scss6
-rw-r--r--app/assets/stylesheets/framework/selects.scss4
-rw-r--r--app/assets/stylesheets/framework/sidebar.scss13
-rw-r--r--app/assets/stylesheets/framework/tables.scss10
-rw-r--r--app/assets/stylesheets/framework/timeline.scss6
-rw-r--r--app/assets/stylesheets/framework/typography.scss88
-rw-r--r--app/assets/stylesheets/highlight/dark.scss11
-rw-r--r--app/assets/stylesheets/highlight/monokai.scss13
-rw-r--r--app/assets/stylesheets/highlight/solarized_dark.scss9
-rw-r--r--app/assets/stylesheets/highlight/solarized_light.scss9
-rw-r--r--app/assets/stylesheets/highlight/white.scss18
-rw-r--r--app/assets/stylesheets/pages/ci_projects.scss5
-rw-r--r--app/assets/stylesheets/pages/commits.scss2
-rw-r--r--app/assets/stylesheets/pages/editor.scss2
-rw-r--r--app/assets/stylesheets/pages/events.scss2
-rw-r--r--app/assets/stylesheets/pages/help.scss4
-rw-r--r--app/assets/stylesheets/pages/issuable.scss21
-rw-r--r--app/assets/stylesheets/pages/issues.scss5
-rw-r--r--app/assets/stylesheets/pages/merge_requests.scss9
-rw-r--r--app/assets/stylesheets/pages/notes.scss5
-rw-r--r--app/assets/stylesheets/pages/profile.scss32
-rw-r--r--app/assets/stylesheets/pages/projects.scss74
-rw-r--r--app/assets/stylesheets/pages/runners.scss52
-rw-r--r--app/assets/stylesheets/pages/snippets.scss60
-rw-r--r--app/assets/stylesheets/pages/tree.scss16
-rw-r--r--app/controllers/abuse_reports_controller.rb4
-rw-r--r--app/controllers/admin/application_settings_controller.rb1
-rw-r--r--app/controllers/admin/broadcast_messages_controller.rb2
-rw-r--r--app/controllers/admin/hooks_controller.rb2
-rw-r--r--app/controllers/admin/services_controller.rb8
-rw-r--r--app/controllers/admin/users_controller.rb26
-rw-r--r--app/controllers/application_controller.rb13
-rw-r--r--app/controllers/ci/admin/runners_controller.rb5
-rw-r--r--app/controllers/ci/application_controller.rb8
-rw-r--r--app/controllers/ci/events_controller.rb21
-rw-r--r--app/controllers/ci/projects_controller.rb11
-rw-r--r--app/controllers/ci/runner_projects_controller.rb2
-rw-r--r--app/controllers/import/bitbucket_controller.rb2
-rw-r--r--app/controllers/import/fogbugz_controller.rb2
-rw-r--r--app/controllers/import/github_controller.rb6
-rw-r--r--app/controllers/import/gitlab_controller.rb2
-rw-r--r--app/controllers/import/gitorious_controller.rb2
-rw-r--r--app/controllers/import/google_code_controller.rb8
-rw-r--r--app/controllers/invites_controller.rb4
-rw-r--r--app/controllers/profiles/notifications_controller.rb2
-rw-r--r--app/controllers/profiles_controller.rb2
-rw-r--r--app/controllers/projects/avatars_controller.rb2
-rw-r--r--app/controllers/projects/blob_controller.rb8
-rw-r--r--app/controllers/projects/builds_controller.rb32
-rw-r--r--app/controllers/projects/ci_services_controller.rb10
-rw-r--r--app/controllers/projects/ci_web_hooks_controller.rb2
-rw-r--r--app/controllers/projects/commit_controller.rb11
-rw-r--r--app/controllers/projects/commits_controller.rb2
-rw-r--r--app/controllers/projects/compare_controller.rb3
-rw-r--r--app/controllers/projects/deploy_keys_controller.rb2
-rw-r--r--app/controllers/projects/hooks_controller.rb2
-rw-r--r--app/controllers/projects/issues_controller.rb13
-rw-r--r--app/controllers/projects/merge_requests_controller.rb9
-rw-r--r--app/controllers/projects/milestones_controller.rb6
-rw-r--r--app/controllers/projects/notes_controller.rb4
-rw-r--r--app/controllers/projects/project_members_controller.rb3
-rw-r--r--app/controllers/projects/raw_controller.rb2
-rw-r--r--app/controllers/projects/refs_controller.rb7
-rw-r--r--app/controllers/projects/repositories_controller.rb17
-rw-r--r--app/controllers/projects/runners_controller.rb11
-rw-r--r--app/controllers/projects/services_controller.rb10
-rw-r--r--app/controllers/projects/snippets_controller.rb1
-rw-r--r--app/controllers/projects/tree_controller.rb6
-rw-r--r--app/controllers/projects/uploads_controller.rb2
-rw-r--r--app/controllers/projects_controller.rb38
-rw-r--r--app/controllers/search_controller.rb4
-rw-r--r--app/controllers/uploads_controller.rb6
-rw-r--r--app/finders/issuable_finder.rb114
-rw-r--r--app/helpers/appearances_helper.rb2
-rw-r--r--app/helpers/application_helper.rb10
-rw-r--r--app/helpers/ci_status_helper.rb9
-rw-r--r--app/helpers/clipboard_helper.rb8
-rw-r--r--app/helpers/diff_helper.rb3
-rw-r--r--app/helpers/gitlab_markdown_helper.rb21
-rw-r--r--app/helpers/gitlab_routing_helper.rb4
-rw-r--r--app/helpers/issues_helper.rb4
-rw-r--r--app/helpers/labels_helper.rb18
-rw-r--r--app/helpers/merge_requests_helper.rb2
-rw-r--r--app/helpers/preferences_helper.rb8
-rw-r--r--app/helpers/projects_helper.rb10
-rw-r--r--app/helpers/runners_helper.rb35
-rw-r--r--app/helpers/tab_helper.rb18
-rw-r--r--app/mailers/abuse_report_mailer.rb12
-rw-r--r--app/models/ability.rb5
-rw-r--r--app/models/application_setting.rb4
-rw-r--r--app/models/ci/build.rb32
-rw-r--r--app/models/ci/commit.rb56
-rw-r--r--app/models/ci/project.rb9
-rw-r--r--app/models/ci/project_status.rb4
-rw-r--r--app/models/ci/runner.rb22
-rw-r--r--app/models/commit.rb16
-rw-r--r--app/models/commit_status.rb8
-rw-r--r--app/models/concerns/issuable.rb12
-rw-r--r--app/models/concerns/mentionable.rb52
-rw-r--r--app/models/concerns/participable.rb28
-rw-r--r--app/models/group.rb2
-rw-r--r--app/models/group_label.rb9
-rw-r--r--app/models/group_milestone.rb12
-rw-r--r--app/models/issue.rb10
-rw-r--r--app/models/merge_request.rb30
-rw-r--r--app/models/merge_request_diff.rb7
-rw-r--r--app/models/milestone.rb32
-rw-r--r--app/models/namespace.rb2
-rw-r--r--app/models/note.rb22
-rw-r--r--app/models/project.rb15
-rw-r--r--app/models/project_services/bamboo_service.rb2
-rw-r--r--app/models/project_services/teamcity_service.rb2
-rw-r--r--app/models/project_team.rb19
-rw-r--r--app/models/repository.rb61
-rw-r--r--app/models/service.rb35
-rw-r--r--app/models/user.rb75
-rw-r--r--app/services/archive_repository_service.rb47
-rw-r--r--app/services/ci/create_builds_service.rb14
-rw-r--r--app/services/ci/image_for_build_service.rb16
-rw-r--r--app/services/ci/register_build_service.rb2
-rw-r--r--app/services/files/create_dir_service.rb11
-rw-r--r--app/services/files/create_service.rb11
-rw-r--r--app/services/git_push_service.rb55
-rw-r--r--app/services/issues/create_service.rb2
-rw-r--r--app/services/issues/update_service.rb2
-rw-r--r--app/services/labels/group_service.rb26
-rw-r--r--app/services/merge_requests/create_service.rb2
-rw-r--r--app/services/merge_requests/post_merge_service.rb10
-rw-r--r--app/services/merge_requests/refresh_service.rb90
-rw-r--r--app/services/merge_requests/update_service.rb2
-rw-r--r--app/services/notes/create_service.rb8
-rw-r--r--app/services/notes/update_service.rb2
-rw-r--r--app/services/projects/transfer_service.rb4
-rw-r--r--app/services/system_note_service.rb27
-rw-r--r--app/uploaders/file_uploader.rb2
-rw-r--r--app/views/abuse_report_mailer/notify.html.haml11
-rw-r--r--app/views/abuse_report_mailer/notify.text.haml5
-rw-r--r--app/views/admin/abuse_reports/index.html.haml21
-rw-r--r--app/views/admin/application_settings/_form.html.haml6
-rw-r--r--app/views/admin/applications/show.html.haml37
-rw-r--r--app/views/admin/background_jobs/show.html.haml37
-rw-r--r--app/views/admin/deploy_keys/index.html.haml37
-rw-r--r--app/views/admin/identities/index.html.haml15
-rw-r--r--app/views/admin/services/index.html.haml39
-rw-r--r--app/views/admin/users/_profile.html.haml (renamed from app/views/users/_profile.html.haml)0
-rw-r--r--app/views/admin/users/show.html.haml4
-rw-r--r--app/views/ci/admin/events/index.html.haml33
-rw-r--r--app/views/ci/admin/projects/index.html.haml23
-rw-r--r--app/views/ci/admin/runner_projects/index.html.haml2
-rw-r--r--app/views/ci/admin/runners/index.html.haml31
-rw-r--r--app/views/ci/admin/runners/show.html.haml34
-rw-r--r--app/views/ci/events/index.html.haml19
-rw-r--r--app/views/ci/lints/_create.html.haml50
-rw-r--r--app/views/ci/projects/index.html.haml20
-rw-r--r--app/views/ci/user_sessions/new.html.haml3
-rw-r--r--app/views/dashboard/milestones/_issue.html.haml2
-rw-r--r--app/views/dashboard/milestones/_merge_request.html.haml2
-rw-r--r--app/views/dashboard/milestones/show.html.haml44
-rw-r--r--app/views/dashboard/projects/_projects.html.haml3
-rw-r--r--app/views/dashboard/snippets/index.html.haml26
-rw-r--r--app/views/doorkeeper/applications/index.html.haml30
-rw-r--r--app/views/doorkeeper/applications/show.html.haml38
-rw-r--r--app/views/doorkeeper/authorized_applications/index.html.haml25
-rw-r--r--app/views/events/_event_issue.atom.haml3
-rw-r--r--app/views/events/_event_merge_request.atom.haml3
-rw-r--r--app/views/events/_event_note.atom.haml2
-rw-r--r--app/views/events/_event_push.atom.haml2
-rw-r--r--app/views/explore/snippets/index.html.haml3
-rw-r--r--app/views/groups/_projects.html.haml3
-rw-r--r--app/views/groups/group_members/_group_member.html.haml2
-rw-r--r--app/views/groups/milestones/_issue.html.haml2
-rw-r--r--app/views/groups/milestones/_merge_request.html.haml2
-rw-r--r--app/views/groups/milestones/show.html.haml44
-rw-r--r--app/views/help/_shortcuts.html.haml6
-rw-r--r--app/views/import/bitbucket/status.html.haml77
-rw-r--r--app/views/import/fogbugz/new_user_map.html.haml31
-rw-r--r--app/views/import/fogbugz/status.html.haml63
-rw-r--r--app/views/import/github/status.html.haml63
-rw-r--r--app/views/import/gitlab/status.html.haml63
-rw-r--r--app/views/import/gitorious/status.html.haml63
-rw-r--r--app/views/import/google_code/status.html.haml77
-rw-r--r--app/views/layouts/_page.html.haml2
-rw-r--r--app/views/layouts/_search.html.haml2
-rw-r--r--app/views/layouts/ci/_page.html.haml2
-rw-r--r--app/views/layouts/ci/project.html.haml11
-rw-r--r--app/views/layouts/nav/_group.html.haml4
-rw-r--r--app/views/layouts/nav/_group_settings.html.haml4
-rw-r--r--app/views/layouts/nav/_profile.html.haml4
-rw-r--r--app/views/layouts/nav/_project.html.haml18
-rw-r--r--app/views/layouts/nav/_project_settings.html.haml9
-rw-r--r--app/views/layouts/notify.html.haml4
-rw-r--r--app/views/notify/_note_message.html.haml2
-rw-r--r--app/views/notify/new_issue_email.html.haml2
-rw-r--r--app/views/notify/new_merge_request_email.html.haml2
-rw-r--r--app/views/profiles/_event_table.html.haml29
-rw-r--r--app/views/profiles/preferences/show.html.haml4
-rw-r--r--app/views/profiles/show.html.haml2
-rw-r--r--app/views/projects/_activity.html.haml1
-rw-r--r--app/views/projects/_files.html.haml6
-rw-r--r--app/views/projects/_last_commit.html.haml12
-rw-r--r--app/views/projects/_md_preview.html.haml4
-rw-r--r--app/views/projects/_readme.html.haml13
-rw-r--r--app/views/projects/_zen.html.haml6
-rw-r--r--app/views/projects/activity.html.haml2
-rw-r--r--app/views/projects/blob/_blob.html.haml31
-rw-r--r--app/views/projects/blob/show.html.haml3
-rw-r--r--app/views/projects/builds/_build.html.haml53
-rw-r--r--app/views/projects/builds/index.html.haml53
-rw-r--r--app/views/projects/builds/show.html.haml25
-rw-r--r--app/views/projects/buttons/_dropdown.html.haml4
-rw-r--r--app/views/projects/buttons/_notifications.html.haml32
-rw-r--r--app/views/projects/ci_services/index.html.haml2
-rw-r--r--app/views/projects/ci_settings/_no_runners.html.haml2
-rw-r--r--app/views/projects/ci_web_hooks/index.html.haml23
-rw-r--r--app/views/projects/commit/ci.html.haml58
-rw-r--r--app/views/projects/commit_statuses/_commit_status.html.haml9
-rw-r--r--app/views/projects/commits/_commit.html.haml6
-rw-r--r--app/views/projects/diffs/_diffs.html.haml4
-rw-r--r--app/views/projects/diffs/_file.html.haml4
-rw-r--r--app/views/projects/edit.html.haml18
-rw-r--r--app/views/projects/empty.html.haml85
-rw-r--r--app/views/projects/imports/new.html.haml2
-rw-r--r--app/views/projects/issues/_closed_by_box.html.haml3
-rw-r--r--app/views/projects/issues/_discussion.html.haml6
-rw-r--r--app/views/projects/issues/_issues.html.haml7
-rw-r--r--app/views/projects/issues/show.html.haml3
-rw-r--r--app/views/projects/labels/destroy.js.haml2
-rw-r--r--app/views/projects/labels/index.html.haml6
-rw-r--r--app/views/projects/merge_requests/_merge_request.html.haml3
-rw-r--r--app/views/projects/merge_requests/_merge_requests.html.haml6
-rw-r--r--app/views/projects/merge_requests/_show.html.haml3
-rw-r--r--app/views/projects/merge_requests/show/_how_to_merge.html.haml7
-rw-r--r--app/views/projects/merge_requests/widget/_heading.html.haml73
-rw-r--r--app/views/projects/milestones/_issue.html.haml2
-rw-r--r--app/views/projects/milestones/_merge_request.html.haml2
-rw-r--r--app/views/projects/milestones/show.html.haml2
-rw-r--r--app/views/projects/notes/_note.html.haml6
-rw-r--r--app/views/projects/project_members/_project_member.html.haml2
-rw-r--r--app/views/projects/protected_branches/_branches_list.html.haml59
-rw-r--r--app/views/projects/remove_fork.js.haml2
-rw-r--r--app/views/projects/runners/show.html.haml101
-rw-r--r--app/views/projects/services/index.html.haml39
-rw-r--r--app/views/projects/show.html.haml17
-rw-r--r--app/views/projects/snippets/_actions.html.haml11
-rw-r--r--app/views/projects/snippets/index.html.haml20
-rw-r--r--app/views/projects/snippets/show.html.haml46
-rw-r--r--app/views/projects/tree/_blob_item.html.haml2
-rw-r--r--app/views/projects/tree/_readme.html.haml6
-rw-r--r--app/views/projects/tree/_tree_content.html.haml (renamed from app/views/projects/tree/_tree.html.haml)37
-rw-r--r--app/views/projects/tree/_tree_header.html.haml32
-rw-r--r--app/views/projects/tree/_tree_item.html.haml2
-rw-r--r--app/views/projects/tree/show.html.haml8
-rw-r--r--app/views/projects/triggers/index.html.haml13
-rw-r--r--app/views/projects/wikis/history.html.haml49
-rw-r--r--app/views/search/_category.html.haml7
-rw-r--r--app/views/search/results/_commit.html.haml2
-rw-r--r--app/views/shared/_clone_panel.html.haml4
-rw-r--r--app/views/shared/_logo.svg21
-rw-r--r--app/views/shared/issuable/_filter.html.haml9
-rw-r--r--app/views/shared/projects/_project.html.haml4
-rw-r--r--app/views/shared/snippets/_header.html.haml24
-rw-r--r--app/views/shared/snippets/_snippet.html.haml1
-rw-r--r--app/views/snippets/_actions.html.haml11
-rw-r--r--app/views/snippets/show.html.haml51
-rw-r--r--app/views/users/_projects.html.haml13
-rw-r--r--app/views/users/calendar.html.haml6
-rw-r--r--app/views/users/show.html.haml147
-rw-r--r--app/workers/repository_archive_cache_worker.rb9
-rw-r--r--app/workers/repository_archive_worker.rb43
-rw-r--r--app/workers/stuck_ci_builds_worker.rb18
295 files changed, 2868 insertions, 1910 deletions
diff --git a/app/assets/fonts/SourceSansPro-Black.ttf b/app/assets/fonts/SourceSansPro-Black.ttf
index cb89a2d171e..9c9b5cb7f03 100755..100644
--- a/app/assets/fonts/SourceSansPro-Black.ttf
+++ b/app/assets/fonts/SourceSansPro-Black.ttf
Binary files differ
diff --git a/app/assets/fonts/SourceSansPro-BlackIt.ttf b/app/assets/fonts/SourceSansPro-BlackIt.ttf
new file mode 100644
index 00000000000..294ce5abe8f
--- /dev/null
+++ b/app/assets/fonts/SourceSansPro-BlackIt.ttf
Binary files differ
diff --git a/app/assets/fonts/SourceSansPro-Bold.ttf b/app/assets/fonts/SourceSansPro-Bold.ttf
index 5d65c93242f..5d65c93242f 100755..100644
--- a/app/assets/fonts/SourceSansPro-Bold.ttf
+++ b/app/assets/fonts/SourceSansPro-Bold.ttf
Binary files differ
diff --git a/app/assets/fonts/SourceSansPro-BoldIt.ttf b/app/assets/fonts/SourceSansPro-BoldIt.ttf
new file mode 100644
index 00000000000..3decd130070
--- /dev/null
+++ b/app/assets/fonts/SourceSansPro-BoldIt.ttf
Binary files differ
diff --git a/app/assets/fonts/SourceSansPro-ExtraLight.ttf b/app/assets/fonts/SourceSansPro-ExtraLight.ttf
index bb4176c6fff..253eafa3783 100755..100644
--- a/app/assets/fonts/SourceSansPro-ExtraLight.ttf
+++ b/app/assets/fonts/SourceSansPro-ExtraLight.ttf
Binary files differ
diff --git a/app/assets/fonts/SourceSansPro-ExtraLightIt.ttf b/app/assets/fonts/SourceSansPro-ExtraLightIt.ttf
new file mode 100644
index 00000000000..00d7e9a7aa8
--- /dev/null
+++ b/app/assets/fonts/SourceSansPro-ExtraLightIt.ttf
Binary files differ
diff --git a/app/assets/fonts/SourceSansPro-It.ttf b/app/assets/fonts/SourceSansPro-It.ttf
new file mode 100644
index 00000000000..f7af5377595
--- /dev/null
+++ b/app/assets/fonts/SourceSansPro-It.ttf
Binary files differ
diff --git a/app/assets/fonts/SourceSansPro-Light.ttf b/app/assets/fonts/SourceSansPro-Light.ttf
index 83a0a336661..83a0a336661 100755..100644
--- a/app/assets/fonts/SourceSansPro-Light.ttf
+++ b/app/assets/fonts/SourceSansPro-Light.ttf
Binary files differ
diff --git a/app/assets/fonts/SourceSansPro-LightIt.ttf b/app/assets/fonts/SourceSansPro-LightIt.ttf
new file mode 100644
index 00000000000..f18827985ef
--- /dev/null
+++ b/app/assets/fonts/SourceSansPro-LightIt.ttf
Binary files differ
diff --git a/app/assets/fonts/SourceSansPro-Regular.ttf b/app/assets/fonts/SourceSansPro-Regular.ttf
index 44486cdc670..44486cdc670 100755..100644
--- a/app/assets/fonts/SourceSansPro-Regular.ttf
+++ b/app/assets/fonts/SourceSansPro-Regular.ttf
Binary files differ
diff --git a/app/assets/fonts/SourceSansPro-Semibold.ttf b/app/assets/fonts/SourceSansPro-Semibold.ttf
index 86b00c067e0..86b00c067e0 100755..100644
--- a/app/assets/fonts/SourceSansPro-Semibold.ttf
+++ b/app/assets/fonts/SourceSansPro-Semibold.ttf
Binary files differ
diff --git a/app/assets/fonts/SourceSansPro-SemiboldIt.ttf b/app/assets/fonts/SourceSansPro-SemiboldIt.ttf
new file mode 100644
index 00000000000..13d66a1fc45
--- /dev/null
+++ b/app/assets/fonts/SourceSansPro-SemiboldIt.ttf
Binary files differ
diff --git a/app/assets/images/logo.svg b/app/assets/images/logo.svg
index c09785cb96f..f4e19b67008 100644
--- a/app/assets/images/logo.svg
+++ b/app/assets/images/logo.svg
@@ -10,17 +10,17 @@
<g id="Fill-1-+-Group-24">
<g id="Group-24">
<g id="Group">
- <path d="M105.0614,193.655 L105.0614,193.655 L143.7014,74.734 L66.4214,74.734 L105.0614,193.655 L105.0614,193.655 Z" id="Fill-4" fill="#E24329"></path>
- <path d="M105.0614,193.6548 L66.4214,74.7338 L12.2684,74.7338 L105.0614,193.6548 L105.0614,193.6548 Z" id="Fill-8" fill="#FC6D26"></path>
- <path d="M12.2685,74.7341 L12.2685,74.7341 L0.5265,110.8731 C-0.5445,114.1691 0.6285,117.7801 3.4325,119.8171 L105.0615,193.6551 L12.2685,74.7341 L12.2685,74.7341 Z" id="Fill-12" fill="#FCA326"></path>
- <path d="M12.2685,74.7342 L66.4215,74.7342 L43.1485,3.1092 C41.9515,-0.5768 36.7375,-0.5758 35.5405,3.1092 L12.2685,74.7342 L12.2685,74.7342 Z" id="Fill-16" fill="#E24329"></path>
- <path d="M105.0614,193.6548 L143.7014,74.7338 L197.8544,74.7338 L105.0614,193.6548 L105.0614,193.6548 Z" id="Fill-18" fill="#FC6D26"></path>
- <path d="M197.8544,74.7341 L197.8544,74.7341 L209.5964,110.8731 C210.6674,114.1691 209.4944,117.7801 206.6904,119.8171 L105.0614,193.6551 L197.8544,74.7341 L197.8544,74.7341 Z" id="Fill-20" fill="#FCA326"></path>
- <path d="M197.8544,74.7342 L143.7014,74.7342 L166.9744,3.1092 C168.1714,-0.5768 173.3854,-0.5758 174.5824,3.1092 L197.8544,74.7342 L197.8544,74.7342 Z" id="Fill-22" fill="#E24329"></path>
+ <path d="M105.0614,193.655 L105.0614,193.655 L143.7014,74.734 L66.4214,74.734 L105.0614,193.655 L105.0614,193.655 Z" id="Fill-4" fill="#E24329" class="tanuki-shape"></path>
+ <path d="M105.0614,193.6548 L66.4214,74.7338 L12.2684,74.7338 L105.0614,193.6548 L105.0614,193.6548 Z" id="Fill-8" fill="#FC6D26" class="tanuki-shape"></path>
+ <path d="M12.2685,74.7341 L12.2685,74.7341 L0.5265,110.8731 C-0.5445,114.1691 0.6285,117.7801 3.4325,119.8171 L105.0615,193.6551 L12.2685,74.7341 L12.2685,74.7341 Z" id="Fill-12" fill="#FCA326" class="tanuki-shape"></path>
+ <path d="M12.2685,74.7342 L66.4215,74.7342 L43.1485,3.1092 C41.9515,-0.5768 36.7375,-0.5758 35.5405,3.1092 L12.2685,74.7342 L12.2685,74.7342 Z" id="Fill-16" fill="#E24329" class="tanuki-shape"></path>
+ <path d="M105.0614,193.6548 L143.7014,74.7338 L197.8544,74.7338 L105.0614,193.6548 L105.0614,193.6548 Z" id="Fill-18" fill="#FC6D26" class="tanuki-shape"></path>
+ <path d="M197.8544,74.7341 L197.8544,74.7341 L209.5964,110.8731 C210.6674,114.1691 209.4944,117.7801 206.6904,119.8171 L105.0614,193.6551 L197.8544,74.7341 L197.8544,74.7341 Z" id="Fill-20" fill="#FCA326" class="tanuki-shape"></path>
+ <path d="M197.8544,74.7342 L143.7014,74.7342 L166.9744,3.1092 C168.1714,-0.5768 173.3854,-0.5758 174.5824,3.1092 L197.8544,74.7342 L197.8544,74.7342 Z" id="Fill-22" fill="#E24329" class="tanuki-shape"></path>
</g>
</g>
</g>
</g>
</g>
</g>
-</svg> \ No newline at end of file
+</svg>
diff --git a/app/assets/javascripts/blob/edit_blob.js.coffee b/app/assets/javascripts/blob/edit_blob.js.coffee
index 050888f9c15..f6bf836f19f 100644
--- a/app/assets/javascripts/blob/edit_blob.js.coffee
+++ b/app/assets/javascripts/blob/edit_blob.js.coffee
@@ -11,10 +11,10 @@ class @EditBlob
if ace_mode
editor.getSession().setMode "ace/mode/" + ace_mode
- $(".js-commit-button").click ->
- $("#file-content").val editor.getValue()
- $(".file-editor form").submit()
- return false
+ # Before a form submission, move the content from the Ace editor into the
+ # submitted textarea
+ $('form').submit ->
+ $("#file-content").val(editor.getValue())
editModePanes = $(".js-edit-mode-pane")
editModeLinks = $(".js-edit-mode a")
diff --git a/app/assets/javascripts/blob/new_blob.js.coffee b/app/assets/javascripts/blob/new_blob.js.coffee
index 1f36a53f191..68c5e5195e3 100644
--- a/app/assets/javascripts/blob/new_blob.js.coffee
+++ b/app/assets/javascripts/blob/new_blob.js.coffee
@@ -11,10 +11,10 @@ class @NewBlob
if ace_mode
editor.getSession().setMode "ace/mode/" + ace_mode
- $(".js-commit-button").click ->
- $("#file-content").val editor.getValue()
- $(".file-editor form").submit()
- return false
+ # Before a form submission, move the content from the Ace editor into the
+ # submitted textarea
+ $('form').submit ->
+ $("#file-content").val(editor.getValue())
editor: ->
return @editor
diff --git a/app/assets/javascripts/calendar.js.coffee b/app/assets/javascripts/calendar.js.coffee
index 4c4bc3d66ed..2b1e20d3225 100644
--- a/app/assets/javascripts/calendar.js.coffee
+++ b/app/assets/javascripts/calendar.js.coffee
@@ -25,7 +25,7 @@ class @Calendar
30
]
legendCellPadding: 3
- cellSize: $('.user-calendar').width() / 80
+ cellSize: $('.user-calendar').width() / 76
onClick: (date, count) ->
formated_date = date.getFullYear() + "-" + (date.getMonth()+1) + "-" + date.getDate()
$.ajax
diff --git a/app/assets/javascripts/ci/build.coffee b/app/assets/javascripts/ci/build.coffee
index c30859b484b..44d5ddb7d95 100644
--- a/app/assets/javascripts/ci/build.coffee
+++ b/app/assets/javascripts/ci/build.coffee
@@ -22,7 +22,7 @@ class CiBuild
# Only valid for runnig build when output changes during time
#
CiBuild.interval = setInterval =>
- if window.location.href is build_url
+ if window.location.href.split("#").first() is build_url
$.ajax
url: build_url
dataType: "json"
@@ -31,7 +31,7 @@ class CiBuild
$('#build-trace code').html build.trace_html
$('#build-trace code').append '<i class="fa fa-refresh fa-spin"/>'
@checkAutoscroll()
- else
+ else if build.status != build_status
Turbolinks.visit build_url
, 4000
diff --git a/app/assets/javascripts/copy_to_clipboard.js.coffee b/app/assets/javascripts/copy_to_clipboard.js.coffee
new file mode 100644
index 00000000000..ec4b80cca6f
--- /dev/null
+++ b/app/assets/javascripts/copy_to_clipboard.js.coffee
@@ -0,0 +1,21 @@
+#= require clipboard
+
+$ ->
+ clipboard = new Clipboard '.js-clipboard-trigger',
+ text: (trigger) ->
+ $target = $(trigger.nextElementSibling || trigger.previousElementSibling)
+ $target.data('clipboard-text') || $target.text().trim()
+
+ clipboard.on 'success', (e) ->
+ $(e.trigger).
+ tooltip(trigger: 'manual', placement: 'auto bottom', title: 'Copied!').
+ tooltip('show')
+
+ # Clear the selection and blur the trigger so it loses its border
+ e.clearSelection()
+ $(e.trigger).blur()
+
+ # Manually hide the tooltip after 1 second
+ setTimeout(->
+ $(e.trigger).tooltip('hide')
+ , 1000)
diff --git a/app/assets/javascripts/merge_request_tabs.js.coffee b/app/assets/javascripts/merge_request_tabs.js.coffee
index 3e77ea515f8..593a8f42130 100644
--- a/app/assets/javascripts/merge_request_tabs.js.coffee
+++ b/app/assets/javascripts/merge_request_tabs.js.coffee
@@ -68,8 +68,8 @@ class @MergeRequestTabs
scrollToElement: (container) ->
if window.location.hash
- top = $(container + " " + window.location.hash).offset().top
- $('body').scrollTo(top)
+ $el = $("#{container} #{window.location.hash}")
+ $('body').scrollTo($el.offset().top) if $el.length
# Activate a tab based on the current action
activateTab: (action) ->
@@ -127,7 +127,7 @@ class @MergeRequestTabs
document.getElementById('commits').innerHTML = data.html
$('.js-timeago').timeago()
@commitsLoaded = true
- @scrollToElement(".commits")
+ @scrollToElement("#commits")
loadDiff: (source) ->
return if @diffsLoaded
@@ -137,7 +137,7 @@ class @MergeRequestTabs
success: (data) =>
document.getElementById('diffs').innerHTML = data.html
@diffsLoaded = true
- @scrollToElement(".diffs")
+ @scrollToElement("#diffs")
# Show or hide the loading spinner
#
diff --git a/app/assets/javascripts/shortcuts_navigation.coffee b/app/assets/javascripts/shortcuts_navigation.coffee
index 5b6f9e7e3f2..8decaedd87b 100644
--- a/app/assets/javascripts/shortcuts_navigation.coffee
+++ b/app/assets/javascripts/shortcuts_navigation.coffee
@@ -7,6 +7,7 @@ class @ShortcutsNavigation extends Shortcuts
Mousetrap.bind('g e', -> ShortcutsNavigation.findAndFollowLink('.shortcuts-project-activity'))
Mousetrap.bind('g f', -> ShortcutsNavigation.findAndFollowLink('.shortcuts-tree'))
Mousetrap.bind('g c', -> ShortcutsNavigation.findAndFollowLink('.shortcuts-commits'))
+ Mousetrap.bind('g b', -> ShortcutsNavigation.findAndFollowLink('.shortcuts-builds'))
Mousetrap.bind('g n', -> ShortcutsNavigation.findAndFollowLink('.shortcuts-network'))
Mousetrap.bind('g g', -> ShortcutsNavigation.findAndFollowLink('.shortcuts-graphs'))
Mousetrap.bind('g i', -> ShortcutsNavigation.findAndFollowLink('.shortcuts-issues'))
diff --git a/app/assets/stylesheets/framework/blocks.scss b/app/assets/stylesheets/framework/blocks.scss
index 6ce34b5c3e8..8917c53b1f5 100644
--- a/app/assets/stylesheets/framework/blocks.scss
+++ b/app/assets/stylesheets/framework/blocks.scss
@@ -18,6 +18,7 @@
line-height: 36px;
}
+.content-block,
.gray-content-block {
margin: -$gl-padding;
background-color: $background-color;
@@ -27,6 +28,10 @@
border-bottom: 1px solid $border-color;
color: $gl-gray;
+ &.white {
+ background-color: white;
+ }
+
&.top-block {
border-top: none;
}
@@ -60,3 +65,48 @@
line-height: 42px;
}
}
+
+.cover-block {
+ text-align: center;
+ background: #f7f8fa;
+ margin: -$gl-padding;
+ margin-bottom: 0;
+ padding: 44px $gl-padding;
+ border-bottom: 1px solid $border-color;
+ position: relative;
+
+ .avatar-holder {
+ margin-bottom: 16px;
+
+ .avatar, .identicon {
+ margin: 0 auto;
+ float: none;
+ }
+
+ .identicon {
+ @include border-radius(50%);
+ }
+ }
+
+ .cover-title {
+ color: $gl-header-color;
+ margin: 0;
+ font-size: 23px;
+ font-weight: normal;
+ margin: 16px 0 5px 0;
+ color: #4c4e54;
+ font-size: 23px;
+ line-height: 1.1;
+ }
+
+ .cover-desc {
+ padding: 0 $gl-padding 3px;
+ color: $gl-text-color;
+ }
+
+ .cover-controls {
+ position: absolute;
+ top: 10px;
+ right: 10px;
+ }
+}
diff --git a/app/assets/stylesheets/framework/buttons.scss b/app/assets/stylesheets/framework/buttons.scss
index e5f0c0ad9ef..fe56266284b 100644
--- a/app/assets/stylesheets/framework/buttons.scss
+++ b/app/assets/stylesheets/framework/buttons.scss
@@ -162,10 +162,25 @@
border-color: #e7e9ed;
width: 140px;
+ .badge {
+ font-weight: normal;
+ background-color: #eee;
+ color: #78a;
+ }
+
&.active {
border-color: $gl-info;
background: $gl-info;
color: #fff;
+
+ .badge {
+ color: $gl-info;
+ background-color: white;
+ }
}
}
}
+
+.btn-clipboard {
+ border: none;
+}
diff --git a/app/assets/stylesheets/framework/common.scss b/app/assets/stylesheets/framework/common.scss
index e1a1793be9c..3d0b71e066e 100644
--- a/app/assets/stylesheets/framework/common.scss
+++ b/app/assets/stylesheets/framework/common.scss
@@ -387,6 +387,16 @@ table {
}
}
+.center-middle-menu {
+ @include nav-menu;
+ text-align: center;
+ margin: -$gl-padding;
+ height: auto;
+ margin-top: 0;
+ margin-bottom: 0;
+ border-bottom: 1px solid $border-color;
+}
+
.dropzone .dz-preview .dz-progress {
border-color: $border-color !important;
}
diff --git a/app/assets/stylesheets/framework/files.scss b/app/assets/stylesheets/framework/files.scss
index 9dd77747884..35db00281e5 100644
--- a/app/assets/stylesheets/framework/files.scss
+++ b/app/assets/stylesheets/framework/files.scss
@@ -10,6 +10,10 @@
border-bottom: 1px solid #E7E9EE;
margin-bottom: 1em;
+ &.readme-holder {
+ border-bottom: 0;
+ }
+
table {
@extend .table;
}
@@ -94,7 +98,6 @@
border-right: none;
}
background: #fff;
- padding: 10px $gl-padding;
}
.lines {
pre {
diff --git a/app/assets/stylesheets/framework/lists.scss b/app/assets/stylesheets/framework/lists.scss
index c5764c36597..f6942db5816 100644
--- a/app/assets/stylesheets/framework/lists.scss
+++ b/app/assets/stylesheets/framework/lists.scss
@@ -107,7 +107,7 @@ ul.content-list {
> li {
padding: $gl-padding;
- border-color: #f1f2f4;
+ border-color: $table-border-color;
margin-left: -$gl-padding;
margin-right: -$gl-padding;
color: $gl-gray;
diff --git a/app/assets/stylesheets/framework/mixins.scss b/app/assets/stylesheets/framework/mixins.scss
index 089e6958eeb..fe078d016d7 100644
--- a/app/assets/stylesheets/framework/mixins.scss
+++ b/app/assets/stylesheets/framework/mixins.scss
@@ -147,14 +147,8 @@
.badge {
font-weight: normal;
- background-color: #fff;
background-color: #eee;
color: #78a;
}
}
}
-
-.fa-align {
- top: 20px;
- position: relative;
-}
diff --git a/app/assets/stylesheets/framework/selects.scss b/app/assets/stylesheets/framework/selects.scss
index cba621635b6..78fff58d232 100644
--- a/app/assets/stylesheets/framework/selects.scss
+++ b/app/assets/stylesheets/framework/selects.scss
@@ -32,7 +32,7 @@
}
.select2-results .select2-result-label {
- padding: 16px;
+ padding: 9px;
}
.select2-drop{
@@ -143,4 +143,4 @@
.ajax-users-dropdown {
min-width: 250px !important;
-}
+} \ No newline at end of file
diff --git a/app/assets/stylesheets/framework/sidebar.scss b/app/assets/stylesheets/framework/sidebar.scss
index c5ea3aca7ca..985ea164576 100644
--- a/app/assets/stylesheets/framework/sidebar.scss
+++ b/app/assets/stylesheets/framework/sidebar.scss
@@ -242,6 +242,9 @@
img {
width: 36px;
height: 36px;
+ }
+
+ #tanuki-logo, img {
float: left;
}
@@ -265,3 +268,13 @@
}
}
}
+
+
+.tanuki-shape {
+ transition: all 0.8s;
+
+ &:hover {
+ fill: rgb(255, 255, 255);
+ transition: all 0.1s;
+ }
+}
diff --git a/app/assets/stylesheets/framework/tables.scss b/app/assets/stylesheets/framework/tables.scss
index 789b34020c1..66e16e8df75 100644
--- a/app/assets/stylesheets/framework/tables.scss
+++ b/app/assets/stylesheets/framework/tables.scss
@@ -1,3 +1,9 @@
+.table-holder {
+ margin: -$gl-padding;
+ margin-top: 0;
+ margin-bottom: 0;
+}
+
table {
&.table {
.dropdown-menu a {
@@ -18,15 +24,17 @@ table {
tr {
td, th {
- padding: 8px 10px;
+ padding: 10px $gl-padding;
line-height: 20px;
vertical-align: middle;
}
+
th {
font-weight: normal;
font-size: 15px;
border-bottom: 1px solid $border-color !important;
}
+
td {
border-color: $table-border-color !important;
border-bottom: 1px solid;
diff --git a/app/assets/stylesheets/framework/timeline.scss b/app/assets/stylesheets/framework/timeline.scss
index bf21d7fce76..eb53c4153d3 100644
--- a/app/assets/stylesheets/framework/timeline.scss
+++ b/app/assets/stylesheets/framework/timeline.scss
@@ -6,13 +6,17 @@
.timeline-entry {
padding: $gl-padding;
- border-color: #f1f2f4;
+ border-color: $table-border-color;
margin-left: -$gl-padding;
margin-right: -$gl-padding;
color: $gl-gray;
border-bottom: 1px solid #ECEEF1;
border-right: 1px solid #ECEEF1;
+ &:target {
+ background: $hover;
+ }
+
&:last-child {
border-bottom: none;
}
diff --git a/app/assets/stylesheets/framework/typography.scss b/app/assets/stylesheets/framework/typography.scss
index bf36f96cc97..e6558a23858 100644
--- a/app/assets/stylesheets/framework/typography.scss
+++ b/app/assets/stylesheets/framework/typography.scss
@@ -1,5 +1,6 @@
@mixin md-typography {
color: $md-text-color;
+ word-wrap: break-word;
a {
color: $md-link-color;
@@ -17,7 +18,6 @@
font-family: $monospace_font;
white-space: pre;
word-wrap: normal;
- padding: 1px 2px;
}
kbd {
@@ -73,6 +73,8 @@
}
blockquote {
+ color: #7f8fa4;
+ font-size: inherit;
padding: 8px 21px;
margin: 12px 0 12px;
border-left: 3px solid #e7e9ed;
@@ -80,7 +82,7 @@
blockquote p {
color: #7f8fa4 !important;
- font-size: 15px;
+ font-size: inherit;
line-height: 1.5;
}
@@ -101,9 +103,9 @@
pre {
margin: 12px 0 12px 0 !important;
- background-color: #f8fafc !important;
+ background-color: #f8fafc;
font-size: 13px !important;
- color: #5b6169 !important;
+ color: #5b6169;
line-height: 1.6em !important;
@include border-radius(2px);
}
@@ -112,9 +114,9 @@
font-weight: inherit;
}
-
- ul {
- color: #5c5d5e;
+ ul, ol {
+ padding: 0;
+ margin: 6px 0 6px 18px !important;
}
li {
@@ -136,6 +138,33 @@
text-decoration: none;
}
}
+
+ /* Link to current header. */
+ h1, h2, h3, h4, h5, h6 {
+ position: relative;
+
+ a.anchor {
+ // Setting `display: none` would prevent the anchor being scrolled to, so
+ // instead we set the height to 0 and it gets updated on hover.
+ height: 0;
+ }
+
+ &:hover > a.anchor {
+ $size: 16px;
+ position: absolute;
+ right: 100%;
+ top: 50%;
+ margin-top: -$size/2;
+ margin-right: 0px;
+ padding-right: 20px;
+ display: inline-block;
+ width: $size;
+ height: $size;
+ background-image: image-url("icon-link.png");
+ background-size: contain;
+ background-repeat: no-repeat;
+ }
+ }
}
@@ -202,53 +231,11 @@ a > code {
}
/**
- * Wiki typography
+ * Apply Markdown typography
*
*/
.wiki {
@include md-typography;
-
- word-wrap: break-word;
- padding: 7px;
-
- /* Link to current header. */
- h1, h2, h3, h4, h5, h6 {
- position: relative;
-
- a.anchor {
- // Setting `display: none` would prevent the anchor being scrolled to, so
- // instead we set the height to 0 and it gets updated on hover.
- height: 0;
- }
-
- &:hover > a.anchor {
- $size: 16px;
- position: absolute;
- right: 100%;
- top: 50%;
- margin-top: -$size/2;
- margin-right: 0px;
- padding-right: 20px;
- display: inline-block;
- width: $size;
- height: $size;
- background-image: image-url("icon-link.png");
- background-size: contain;
- background-repeat: no-repeat;
- }
- }
-
- ul,ol {
- padding: 0;
- margin: 6px 0 6px 18px !important;
- }
- ol {
- color: #5c5d5e;
- }
-}
-
-.md-area {
- @include md-typography;
}
.md {
@@ -261,6 +248,7 @@ a > code {
*/
textarea.js-gfm-input {
font-family: $monospace_font;
+ color: $gl-text-color;
}
.md-preview {
diff --git a/app/assets/stylesheets/highlight/dark.scss b/app/assets/stylesheets/highlight/dark.scss
index 8323a8598ec..6a2b25ddc67 100644
--- a/app/assets/stylesheets/highlight/dark.scss
+++ b/app/assets/stylesheets/highlight/dark.scss
@@ -1,11 +1,10 @@
/* https://github.com/MozMorris/tomorrow-pygments */
-pre.code.highlight.dark,
.code.dark {
- background-color: #1d1f21;
- color: #c5c8c6;
+ background-color: #1d1f21 !important;
+ color: #c5c8c6 !important;
- pre.code,
+ pre.highlight,
.line-numbers,
.line-numbers a {
background-color: #1d1f21 !important;
@@ -23,8 +22,8 @@ pre.code.highlight.dark,
// Search result highlight
span.highlight_word {
- background: #ffe792;
- color: #000000;
+ background-color: #ffe792 !important;
+ color: #000000 !important;
}
.hll { background-color: #373b41 }
diff --git a/app/assets/stylesheets/highlight/monokai.scss b/app/assets/stylesheets/highlight/monokai.scss
index e8381674336..8560c3c490f 100644
--- a/app/assets/stylesheets/highlight/monokai.scss
+++ b/app/assets/stylesheets/highlight/monokai.scss
@@ -1,15 +1,14 @@
/* https://github.com/richleland/pygments-css/blob/master/monokai.css */
-pre.code.monokai,
.code.monokai {
- background: #272822;
- color: #f8f8f2;
+ background-color: #272822 !important;
+ color: #f8f8f2 !important;
pre.highlight,
.line-numbers,
.line-numbers a {
- background:#272822 !important;
- color:#f8f8f2 !important;
+ background-color :#272822 !important;
+ color: #f8f8f2 !important;
}
pre.code {
@@ -23,8 +22,8 @@ pre.code.monokai,
// Search result highlight
span.highlight_word {
- background: #ffe792;
- color: #000000;
+ background-color: #ffe792 !important;
+ color: #000000 !important;
}
.hll { background-color: #49483e }
diff --git a/app/assets/stylesheets/highlight/solarized_dark.scss b/app/assets/stylesheets/highlight/solarized_dark.scss
index bd41480aefb..7d489a9666b 100644
--- a/app/assets/stylesheets/highlight/solarized_dark.scss
+++ b/app/assets/stylesheets/highlight/solarized_dark.scss
@@ -1,11 +1,10 @@
/* https://gist.github.com/qguv/7936275 */
-pre.code.highlight.solarized-dark,
.code.solarized-dark {
- background-color: #002b36;
- color: #93a1a1;
+ background-color: #002b36 !important;
+ color: #93a1a1 !important;
- pre.code,
+ pre.highlight,
.line-numbers,
.line-numbers a {
background-color: #002b36 !important;
@@ -23,7 +22,7 @@ pre.code.highlight.solarized-dark,
// Search result highlight
span.highlight_word {
- background: #094554;
+ background-color: #094554 !important;
}
/* Solarized Dark
diff --git a/app/assets/stylesheets/highlight/solarized_light.scss b/app/assets/stylesheets/highlight/solarized_light.scss
index 4cc62863870..200ed346446 100644
--- a/app/assets/stylesheets/highlight/solarized_light.scss
+++ b/app/assets/stylesheets/highlight/solarized_light.scss
@@ -1,11 +1,10 @@
/* https://gist.github.com/qguv/7936275 */
-pre.code.highlight.solarized-light,
.code.solarized-light {
- background-color: #fdf6e3;
- color: #586e75;
+ background-color: #fdf6e3 !important;
+ color: #586e75 !important;
- pre.code,
+ pre.highlight,
.line-numbers,
.line-numbers a {
background-color: #fdf6e3 !important;
@@ -23,7 +22,7 @@ pre.code.highlight.solarized-light,
// Search result highlight
span.highlight_word {
- background: #eee8d5;
+ background-color: #eee8d5 !important;
}
/* Solarized Light
diff --git a/app/assets/stylesheets/highlight/white.scss b/app/assets/stylesheets/highlight/white.scss
index 20a144ef952..e2626da7871 100644
--- a/app/assets/stylesheets/highlight/white.scss
+++ b/app/assets/stylesheets/highlight/white.scss
@@ -1,24 +1,20 @@
/* https://github.com/aahan/pygments-github-style */
-pre.code.highlight.white,
.code.white {
- background-color: #f8fafc;
- font-size: 13px;
- color: #5b6169;
- line-height: 1.6em;
+ background-color: #f8fafc !important;
+ color: #5b6169 !important;
+
+ pre.highlight,
.line-numbers,
.line-numbers a {
background-color: $background-color !important;
color: $gl-gray !important;
}
- pre.highlight {
- background-color: #fff !important;
- color: #333 !important;
- }
-
pre.code {
border-left: 1px solid $border-color;
+ background-color: #fff !important;
+ color: #333 !important;
}
// highlight line via anchor
@@ -28,7 +24,7 @@ pre.code.highlight.white,
// Search result highlight
span.highlight_word {
- background: #fafe3d;
+ background-color: #fafe3d !important;
}
.hll { background-color: #f8f8f8 }
diff --git a/app/assets/stylesheets/pages/ci_projects.scss b/app/assets/stylesheets/pages/ci_projects.scss
index 8c5273abcda..2a7b5cfc7fd 100644
--- a/app/assets/stylesheets/pages/ci_projects.scss
+++ b/app/assets/stylesheets/pages/ci_projects.scss
@@ -6,11 +6,6 @@
line-height: 1.5;
}
- .wide-table-holder {
- margin-left: -$gl-padding;
- margin-right: -$gl-padding;
- }
-
.builds,
.projects-table {
.light {
diff --git a/app/assets/stylesheets/pages/commits.scss b/app/assets/stylesheets/pages/commits.scss
index 4e121b95d13..e485487bcfd 100644
--- a/app/assets/stylesheets/pages/commits.scss
+++ b/app/assets/stylesheets/pages/commits.scss
@@ -33,6 +33,8 @@
}
li.commit {
+ list-style: none;
+
.commit-row-title {
font-size: $list-font-size;
line-height: 20px;
diff --git a/app/assets/stylesheets/pages/editor.scss b/app/assets/stylesheets/pages/editor.scss
index 1d565477dd4..e2c521af91e 100644
--- a/app/assets/stylesheets/pages/editor.scss
+++ b/app/assets/stylesheets/pages/editor.scss
@@ -50,7 +50,7 @@
.editor-file-name {
.new-file-name {
display: inline-block;
- width: 200px;
+ width: 450px;
}
.form-control {
diff --git a/app/assets/stylesheets/pages/events.scss b/app/assets/stylesheets/pages/events.scss
index ca2ee455423..dfb901652bf 100644
--- a/app/assets/stylesheets/pages/events.scss
+++ b/app/assets/stylesheets/pages/events.scss
@@ -7,7 +7,7 @@
padding: $gl-padding;
margin-left: -$gl-padding;
margin-right: -$gl-padding;
- border-bottom: 1px solid #f1f2f4;
+ border-bottom: 1px solid $table-border-color;
color: #7f8fa4;
&.event-inline {
diff --git a/app/assets/stylesheets/pages/help.scss b/app/assets/stylesheets/pages/help.scss
index 6da7a2511a2..bd224705f04 100644
--- a/app/assets/stylesheets/pages/help.scss
+++ b/app/assets/stylesheets/pages/help.scss
@@ -68,3 +68,7 @@ body.modal-open {
.modal .modal-dialog {
width: 860px;
}
+
+.documentation {
+ padding: 7px;
+}
diff --git a/app/assets/stylesheets/pages/issuable.scss b/app/assets/stylesheets/pages/issuable.scss
index 9da085a3473..abc27a19e32 100644
--- a/app/assets/stylesheets/pages/issuable.scss
+++ b/app/assets/stylesheets/pages/issuable.scss
@@ -80,3 +80,24 @@
}
}
}
+
+.issuable-filter-count {
+ span {
+ display: block;
+ margin-bottom: -16px;
+ padding: 13px 0;
+ }
+}
+
+.cross-project-reference {
+ text-align: center;
+ width: 100%;
+
+ .slead {
+ padding: 5px;
+ }
+
+ span, button {
+ background-color: $background-color;
+ }
+}
diff --git a/app/assets/stylesheets/pages/issues.scss b/app/assets/stylesheets/pages/issues.scss
index 4bf58cb4a59..41c069f0ad3 100644
--- a/app/assets/stylesheets/pages/issues.scss
+++ b/app/assets/stylesheets/pages/issues.scss
@@ -132,6 +132,11 @@ form.edit-issue {
}
}
+.issue-closed-by-widget {
+ padding: 16px 0;
+ margin: 0px;
+}
+
.issue-form .select2-container {
width: 250px !important;
}
diff --git a/app/assets/stylesheets/pages/merge_requests.scss b/app/assets/stylesheets/pages/merge_requests.scss
index a1a5208c59c..f0b3667acca 100644
--- a/app/assets/stylesheets/pages/merge_requests.scss
+++ b/app/assets/stylesheets/pages/merge_requests.scss
@@ -205,6 +205,15 @@
#modal_merge_info .modal-dialog {
width: 600px;
+
+ .btn-clipboard {
+ @extend .pull-right;
+
+ margin-right: 18px;
+ margin-top: 5px;
+ position: absolute;
+ right: 0;
+ }
}
.mr-source-target {
diff --git a/app/assets/stylesheets/pages/notes.scss b/app/assets/stylesheets/pages/notes.scss
index abb03b07f51..1980fe0d458 100644
--- a/app/assets/stylesheets/pages/notes.scss
+++ b/app/assets/stylesheets/pages/notes.scss
@@ -30,7 +30,6 @@ ul.notes {
.discussion-header,
.note-header {
@extend .cgray;
- padding-bottom: 15px;
a:hover {
text-decoration: none;
@@ -75,6 +74,10 @@ ul.notes {
}
}
+ .discussion-body {
+ padding-top: 15px;
+ }
+
.discussion {
overflow: hidden;
display: block;
diff --git a/app/assets/stylesheets/pages/profile.scss b/app/assets/stylesheets/pages/profile.scss
index 8e4f0eb2b25..bc1ad21305a 100644
--- a/app/assets/stylesheets/pages/profile.scss
+++ b/app/assets/stylesheets/pages/profile.scss
@@ -47,3 +47,35 @@
}
}
}
+
+.calendar-hint {
+ margin-top: -12px;
+ float: right;
+ font-size: 12px;
+}
+
+.profile-link-holder {
+ display: inline;
+
+ &:after {
+ content: "\00B7";
+ padding: 0px 6px;
+ font-weight: bold;
+ }
+
+ &:last-child {
+ &:after {
+ content: "";
+ padding: 0;
+ }
+ }
+
+ a {
+ color: $blue-dark;
+ text-decoration: none;
+ }
+}
+
+.cal-heatmap-container {
+ margin: 0 auto;
+}
diff --git a/app/assets/stylesheets/pages/projects.scss b/app/assets/stylesheets/pages/projects.scss
index b384e3fae6c..2e7ad1173a5 100644
--- a/app/assets/stylesheets/pages/projects.scss
+++ b/app/assets/stylesheets/pages/projects.scss
@@ -50,7 +50,17 @@
}
.project-home-dropdown {
- margin: 11px 3px 0;
+ margin: 13px 0px 0;
+ }
+
+ .notifications-btn {
+ .fa-bell {
+ margin-right: 6px;
+ }
+
+ .fa-angle-down {
+ margin-left: 6px;
+ }
}
.project-home-desc {
@@ -85,6 +95,7 @@
color: inherit;
}
}
+
.input-group {
display: inline-table;
position: relative;
@@ -233,23 +244,11 @@
}
}
- .fa-fw {
+ i {
margin-right: 8px;
}
}
-.fa-bell {
- margin-right: 6px;
-}
-
-.fa-angle-down {
- margin-left: 6px;
-}
-
-.project-home-panel .project-home-dropdown {
- margin: 13px 0px 0;
-}
-
.project-visibility-level-holder {
.radio {
margin-bottom: 10px;
@@ -457,7 +456,7 @@ pre.light-well {
.project-row {
padding: $gl-padding;
- border-color: #f1f2f4;
+ border-color: $table-border-color;
margin-left: -$gl-padding;
margin-right: -$gl-padding;
@@ -512,6 +511,49 @@ pre.light-well {
}
}
+.project-last-commit {
+ margin: 0 7px;
+
+ .ci-status {
+ margin-right: 16px;
+ }
+
+ .commit-row-message {
+ color: $gl-gray;
+ }
+
+ .commit_short_id {
+ margin-right: 5px;
+ color: $gl-link-color;
+ font-weight: 600;
+ }
+
+ .commit-author-link {
+ margin-left: 7px;
+ text-decoration: none;
+ .avatar {
+ float: none;
+ margin-right: 4px;
+ }
+
+ .commit-author-name {
+ font-weight: 600;
+ }
+ }
+}
+
+.project-show-readme .readme-holder {
+ margin-left: -$gl-padding;
+ margin-right: -$gl-padding;
+ padding: ($gl-padding + 7px);
+ border-top: 0;
+
+ .edit-project-readme {
+ z-index: 100;
+ position: relative;
+ }
+}
+
.form-control-padding-top {
padding-top: 10px;
-}
+} \ No newline at end of file
diff --git a/app/assets/stylesheets/pages/runners.scss b/app/assets/stylesheets/pages/runners.scss
index 2b15ab83129..a9111a7388f 100644
--- a/app/assets/stylesheets/pages/runners.scss
+++ b/app/assets/stylesheets/pages/runners.scss
@@ -1,36 +1,34 @@
-.ci-body {
- .runner-state {
- padding: 6px 12px;
- margin-right: 10px;
- color: #FFF;
+.runner-state {
+ padding: 6px 12px;
+ margin-right: 10px;
+ color: #FFF;
- &.runner-state-shared {
- background: #32b186;
- }
- &.runner-state-specific {
- background: #3498db;
- }
+ &.runner-state-shared {
+ background: #32b186;
}
-
- .runner-status-online {
- color: green;
+ &.runner-state-specific {
+ background: #3498db;
}
+}
- .runner-status-offline {
- color: gray;
- }
+.runner-status-online {
+ color: green;
+}
- .runner-status-paused {
- color: red;
- }
+.runner-status-offline {
+ color: gray;
+}
+
+.runner-status-paused {
+ color: red;
+}
- .runner {
- .btn {
- padding: 1px 6px;
- }
+.runner {
+ .btn {
+ padding: 1px 6px;
+ }
- h4 {
- font-weight: normal;
- }
+ h4 {
+ font-weight: normal;
}
}
diff --git a/app/assets/stylesheets/pages/snippets.scss b/app/assets/stylesheets/pages/snippets.scss
index a3d7aba054d..242783a7b7e 100644
--- a/app/assets/stylesheets/pages/snippets.scss
+++ b/app/assets/stylesheets/pages/snippets.scss
@@ -1,8 +1,3 @@
-.my-snippets li:first-child {
- h4 { margin-top: 0; }
- padding-top: 0;
-}
-
.snippet-form-holder .file-holder .file-title {
padding: 2px;
}
@@ -30,3 +25,58 @@
}
}
}
+
+.snippet-holder {
+ .snippet-details {
+ .page-title {
+ margin-top: -15px;
+ padding: 10px 0;
+ margin-bottom: 0;
+ color: #5c5d5e;
+ font-size: 16px;
+
+ .author {
+ color: #5c5d5e;
+ }
+
+ .snippet-id {
+ color: #5c5d5e;
+ }
+ }
+
+ .snippet-title {
+ margin: 0;
+ font-size: 23px;
+ color: #313236;
+ }
+
+ @media (max-width: $screen-md-max) {
+ .new-snippet-link {
+ display: none;
+ }
+ }
+
+ @media (max-width: $screen-sm-max) {
+ .creator,
+ .page-title .btn-close {
+ display: none;
+ }
+ }
+ }
+
+ .file-holder {
+ border-top: 0;
+ }
+}
+
+
+.snippet-box {
+ @include border-radius(2px);
+
+ display: inline-block;
+ padding: 10px $gl-padding;
+ font-weight: normal;
+ margin-right: 10px;
+ font-size: $gl-font-size;
+ border: 1px solid;
+}
diff --git a/app/assets/stylesheets/pages/tree.scss b/app/assets/stylesheets/pages/tree.scss
index dadd86e88cc..d4ab6967ccd 100644
--- a/app/assets/stylesheets/pages/tree.scss
+++ b/app/assets/stylesheets/pages/tree.scss
@@ -1,25 +1,11 @@
.tree-holder {
- .tree-table-holder {
- margin-left: -$gl-padding;
- margin-right: -$gl-padding;
- }
-
- .tree_progress {
- display: none;
- margin: 20px;
- &.loading {
- display: block;
- }
- }
.tree-table {
margin-bottom: 0;
tr {
> td, > th {
- padding: 10px $gl-padding;
- line-height: 32px;
- border-color: $table-border-color !important;
+ line-height: 28px;
}
&:hover {
diff --git a/app/controllers/abuse_reports_controller.rb b/app/controllers/abuse_reports_controller.rb
index 65dbd5ef551..2f4054eaa11 100644
--- a/app/controllers/abuse_reports_controller.rb
+++ b/app/controllers/abuse_reports_controller.rb
@@ -9,6 +9,10 @@ class AbuseReportsController < ApplicationController
@abuse_report.reporter = current_user
if @abuse_report.save
+ if current_application_settings.admin_notification_email.present?
+ AbuseReportMailer.delay.notify(@abuse_report.id)
+ end
+
message = "Thank you for your report. A GitLab administrator will look into it shortly."
redirect_to root_path, notice: message
else
diff --git a/app/controllers/admin/application_settings_controller.rb b/app/controllers/admin/application_settings_controller.rb
index 7c134d2ec9b..039f18f23e0 100644
--- a/app/controllers/admin/application_settings_controller.rb
+++ b/app/controllers/admin/application_settings_controller.rb
@@ -55,6 +55,7 @@ class Admin::ApplicationSettingsController < Admin::ApplicationController
:default_snippet_visibility,
:restricted_signup_domains_raw,
:version_check_enabled,
+ :admin_notification_email,
:user_oauth_applications,
restricted_visibility_levels: [],
import_sources: []
diff --git a/app/controllers/admin/broadcast_messages_controller.rb b/app/controllers/admin/broadcast_messages_controller.rb
index 0808024fc39..497c34f8f49 100644
--- a/app/controllers/admin/broadcast_messages_controller.rb
+++ b/app/controllers/admin/broadcast_messages_controller.rb
@@ -19,7 +19,7 @@ class Admin::BroadcastMessagesController < Admin::ApplicationController
BroadcastMessage.find(params[:id]).destroy
respond_to do |format|
- format.html { redirect_to :back }
+ format.html { redirect_back_or_default(default: { action: 'index' }) }
format.js { render nothing: true }
end
end
diff --git a/app/controllers/admin/hooks_controller.rb b/app/controllers/admin/hooks_controller.rb
index d670386f8c6..0bd19c49d8f 100644
--- a/app/controllers/admin/hooks_controller.rb
+++ b/app/controllers/admin/hooks_controller.rb
@@ -35,7 +35,7 @@ class Admin::HooksController < Admin::ApplicationController
}
@hook.execute(data, 'system_hooks')
- redirect_to :back
+ redirect_back_or_default
end
def hook_params
diff --git a/app/controllers/admin/services_controller.rb b/app/controllers/admin/services_controller.rb
index a62170662e1..46133588332 100644
--- a/app/controllers/admin/services_controller.rb
+++ b/app/controllers/admin/services_controller.rb
@@ -39,7 +39,13 @@ class Admin::ServicesController < Admin::ApplicationController
end
def application_services_params
- params.permit(:id,
+ application_services_params = params.permit(:id,
service: Projects::ServicesController::ALLOWED_PARAMS)
+ if application_services_params[:service].is_a?(Hash)
+ Projects::ServicesController::FILTER_BLANK_PARAMS.each do |param|
+ application_services_params[:service].delete(param) if application_services_params[:service][param].blank?
+ end
+ end
+ application_services_params
end
end
diff --git a/app/controllers/admin/users_controller.rb b/app/controllers/admin/users_controller.rb
index 00f41a10dd1..c63d0793e31 100644
--- a/app/controllers/admin/users_controller.rb
+++ b/app/controllers/admin/users_controller.rb
@@ -33,33 +33,33 @@ class Admin::UsersController < Admin::ApplicationController
def block
if user.block
- redirect_to :back, notice: "Successfully blocked"
+ redirect_back_or_admin_user(notice: "Successfully blocked")
else
- redirect_to :back, alert: "Error occurred. User was not blocked"
+ redirect_back_or_admin_user(alert: "Error occurred. User was not blocked")
end
end
def unblock
if user.activate
- redirect_to :back, notice: "Successfully unblocked"
+ redirect_back_or_admin_user(notice: "Successfully unblocked")
else
- redirect_to :back, alert: "Error occurred. User was not unblocked"
+ redirect_back_or_admin_user(alert: "Error occurred. User was not unblocked")
end
end
def unlock
if user.unlock_access!
- redirect_to :back, alert: "Successfully unlocked"
+ redirect_back_or_admin_user(alert: "Successfully unlocked")
else
- redirect_to :back, alert: "Error occurred. User was not unlocked"
+ redirect_back_or_admin_user(alert: "Error occurred. User was not unlocked")
end
end
def confirm
if user.confirm
- redirect_to :back, notice: "Successfully confirmed"
+ redirect_back_or_admin_user(notice: "Successfully confirmed")
else
- redirect_to :back, alert: "Error occurred. User was not confirmed"
+ redirect_back_or_admin_user(alert: "Error occurred. User was not confirmed")
end
end
@@ -138,7 +138,7 @@ class Admin::UsersController < Admin::ApplicationController
user.update_secondary_emails!
respond_to do |format|
- format.html { redirect_to :back, notice: "Successfully removed email." }
+ format.html { redirect_back_or_admin_user(notice: "Successfully removed email.") }
format.js { render nothing: true }
end
end
@@ -157,4 +157,12 @@ class Admin::UsersController < Admin::ApplicationController
:projects_limit, :can_create_group, :admin, :key_id
)
end
+
+ def redirect_back_or_admin_user(options = {})
+ redirect_back_or_default(default: default_route, options: options)
+ end
+
+ def default_route
+ [:admin, @user]
+ end
end
diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb
index 527c9da0faa..1b0609e279e 100644
--- a/app/controllers/application_controller.rb
+++ b/app/controllers/application_controller.rb
@@ -30,7 +30,11 @@ class ApplicationController < ActionController::Base
rescue_from ActiveRecord::RecordNotFound do |exception|
log_exception(exception)
- render "errors/not_found", layout: "errors", status: 404
+ render_404
+ end
+
+ def redirect_back_or_default(default: root_path, options: {})
+ redirect_to request.referer.present? ? :back : default, options
end
protected
@@ -120,7 +124,6 @@ class ApplicationController < ActionController::Base
project_path = "#{namespace}/#{id}"
@project = Project.find_with_namespace(project_path)
-
if @project and can?(current_user, :read_project, @project)
if @project.path_with_namespace != project_path
redirect_to request.original_url.gsub(project_path, @project.path_with_namespace) and return
@@ -149,12 +152,8 @@ class ApplicationController < ActionController::Base
render "errors/access_denied", layout: "errors", status: 404
end
- def not_found!
- render "errors/not_found", layout: "errors", status: 404
- end
-
def git_not_found!
- render "errors/git_not_found", layout: "errors", status: 404
+ render html: "errors/git_not_found", layout: "errors", status: 404
end
def method_missing(method_sym, *arguments, &block)
diff --git a/app/controllers/ci/admin/runners_controller.rb b/app/controllers/ci/admin/runners_controller.rb
index 9a68add9083..0cafad27418 100644
--- a/app/controllers/ci/admin/runners_controller.rb
+++ b/app/controllers/ci/admin/runners_controller.rb
@@ -6,7 +6,7 @@ module Ci
@runners = Ci::Runner.order('id DESC')
@runners = @runners.search(params[:search]) if params[:search].present?
@runners = @runners.page(params[:page]).per(30)
- @active_runners_cnt = Ci::Runner.where("contacted_at > ?", 1.minutes.ago).count
+ @active_runners_cnt = Ci::Runner.online.count
end
def show
@@ -17,6 +17,7 @@ module Ci
@projects = @projects.where(gitlab_id: @gl_projects.select(:id))
end
@projects = @projects.where("ci_projects.id NOT IN (?)", @runner.projects.pluck(:id)) if @runner.projects.any?
+ @projects = @projects.joins(:gl_project)
@projects = @projects.page(params[:page]).per(30)
end
@@ -66,7 +67,7 @@ module Ci
end
def runner_params
- params.require(:runner).permit(:token, :description, :tag_list, :contacted_at, :active)
+ params.require(:runner).permit(:token, :description, :tag_list, :active)
end
end
end
diff --git a/app/controllers/ci/application_controller.rb b/app/controllers/ci/application_controller.rb
index 9be470660e6..848f2b4e314 100644
--- a/app/controllers/ci/application_controller.rb
+++ b/app/controllers/ci/application_controller.rb
@@ -8,14 +8,6 @@ module Ci
private
- def authenticate_public_page!
- unless project.public
- authenticate_user!
-
- return access_denied! unless can?(current_user, :read_project, gl_project)
- end
- end
-
def authenticate_token!
unless project.valid_token?(params[:token])
return head(403)
diff --git a/app/controllers/ci/events_controller.rb b/app/controllers/ci/events_controller.rb
deleted file mode 100644
index 89b784a1e89..00000000000
--- a/app/controllers/ci/events_controller.rb
+++ /dev/null
@@ -1,21 +0,0 @@
-module Ci
- class EventsController < Ci::ApplicationController
- EVENTS_PER_PAGE = 50
-
- before_action :authenticate_user!
- before_action :project
- before_action :authorize_manage_project!
-
- layout 'ci/project'
-
- def index
- @events = project.events.order("created_at DESC").page(params[:page]).per(EVENTS_PER_PAGE)
- end
-
- private
-
- def project
- @project ||= Ci::Project.find(params[:project_id])
- end
- end
-end
diff --git a/app/controllers/ci/projects_controller.rb b/app/controllers/ci/projects_controller.rb
index 7777aa18031..809b44387ba 100644
--- a/app/controllers/ci/projects_controller.rb
+++ b/app/controllers/ci/projects_controller.rb
@@ -1,12 +1,17 @@
module Ci
class ProjectsController < Ci::ApplicationController
- before_action :project
- before_action :authenticate_user!, except: [:build, :badge]
- before_action :authorize_access_project!, except: [:badge]
+ before_action :project, except: [:index]
+ before_action :authenticate_user!, except: [:index, :build, :badge]
+ before_action :authorize_access_project!, except: [:index, :badge]
before_action :authorize_manage_project!, only: [:toggle_shared_runners, :dumped_yaml]
before_action :no_cache, only: [:badge]
protect_from_forgery
+ def show
+ # Temporary compatibility with CI badges pointing to CI project page
+ redirect_to namespace_project_path(project.gl_project.namespace, project.gl_project)
+ end
+
# Project status badge
# Image with build status for sha or ref
def badge
diff --git a/app/controllers/ci/runner_projects_controller.rb b/app/controllers/ci/runner_projects_controller.rb
index 97f01d40af5..9d555313369 100644
--- a/app/controllers/ci/runner_projects_controller.rb
+++ b/app/controllers/ci/runner_projects_controller.rb
@@ -4,8 +4,6 @@ module Ci
before_action :project
before_action :authorize_manage_project!
- layout 'ci/project'
-
def create
@runner = Ci::Runner.find(params[:runner_project][:runner_id])
diff --git a/app/controllers/import/bitbucket_controller.rb b/app/controllers/import/bitbucket_controller.rb
index f84f85a7df8..25e58724860 100644
--- a/app/controllers/import/bitbucket_controller.rb
+++ b/app/controllers/import/bitbucket_controller.rb
@@ -62,7 +62,7 @@ class Import::BitbucketController < Import::BaseController
end
def verify_bitbucket_import_enabled
- not_found! unless bitbucket_import_enabled?
+ render_404 unless bitbucket_import_enabled?
end
def bitbucket_auth
diff --git a/app/controllers/import/fogbugz_controller.rb b/app/controllers/import/fogbugz_controller.rb
index 849646cd665..18300390851 100644
--- a/app/controllers/import/fogbugz_controller.rb
+++ b/app/controllers/import/fogbugz_controller.rb
@@ -99,6 +99,6 @@ class Import::FogbugzController < Import::BaseController
end
def verify_fogbugz_import_enabled
- not_found! unless fogbugz_import_enabled?
+ render_404 unless fogbugz_import_enabled?
end
end
diff --git a/app/controllers/import/github_controller.rb b/app/controllers/import/github_controller.rb
index f21fbd9ecca..67bf4190e7e 100644
--- a/app/controllers/import/github_controller.rb
+++ b/app/controllers/import/github_controller.rb
@@ -11,10 +11,6 @@ class Import::GithubController < Import::BaseController
def status
@repos = client.repos
- client.orgs.each do |org|
- @repos += client.org_repos(org.login)
- end
-
@already_added_projects = current_user.created_projects.where(import_type: "github")
already_added_projects_names = @already_added_projects.pluck(:import_source)
@@ -47,7 +43,7 @@ class Import::GithubController < Import::BaseController
end
def verify_github_import_enabled
- not_found! unless github_import_enabled?
+ render_404 unless github_import_enabled?
end
def github_auth
diff --git a/app/controllers/import/gitlab_controller.rb b/app/controllers/import/gitlab_controller.rb
index 27af19f5f61..23a396e8084 100644
--- a/app/controllers/import/gitlab_controller.rb
+++ b/app/controllers/import/gitlab_controller.rb
@@ -44,7 +44,7 @@ class Import::GitlabController < Import::BaseController
end
def verify_gitlab_import_enabled
- not_found! unless gitlab_import_enabled?
+ render_404 unless gitlab_import_enabled?
end
def gitlab_auth
diff --git a/app/controllers/import/gitorious_controller.rb b/app/controllers/import/gitorious_controller.rb
index f24cdb3709a..eecbe380c9e 100644
--- a/app/controllers/import/gitorious_controller.rb
+++ b/app/controllers/import/gitorious_controller.rb
@@ -42,7 +42,7 @@ class Import::GitoriousController < Import::BaseController
end
def verify_gitorious_import_enabled
- not_found! unless gitorious_import_enabled?
+ render_404 unless gitorious_import_enabled?
end
end
diff --git a/app/controllers/import/google_code_controller.rb b/app/controllers/import/google_code_controller.rb
index 82fadeb7e83..e0de31f2251 100644
--- a/app/controllers/import/google_code_controller.rb
+++ b/app/controllers/import/google_code_controller.rb
@@ -10,18 +10,18 @@ class Import::GoogleCodeController < Import::BaseController
dump_file = params[:dump_file]
unless dump_file.respond_to?(:read)
- return redirect_to :back, alert: "You need to upload a Google Takeout archive."
+ return redirect_back_or_default(options: { alert: "You need to upload a Google Takeout archive." })
end
begin
dump = JSON.parse(dump_file.read)
rescue
- return redirect_to :back, alert: "The uploaded file is not a valid Google Takeout archive."
+ return redirect_back_or_default(options: { alert: "The uploaded file is not a valid Google Takeout archive." })
end
client = Gitlab::GoogleCodeImport::Client.new(dump)
unless client.valid?
- return redirect_to :back, alert: "The uploaded file is not a valid Google Takeout archive."
+ return redirect_back_or_default(options: { alert: "The uploaded file is not a valid Google Takeout archive." })
end
session[:google_code_dump] = dump
@@ -106,7 +106,7 @@ class Import::GoogleCodeController < Import::BaseController
end
def verify_google_code_import_enabled
- not_found! unless google_code_import_enabled?
+ render_404 unless google_code_import_enabled?
end
def user_map
diff --git a/app/controllers/invites_controller.rb b/app/controllers/invites_controller.rb
index 8ef10a17f55..94bb108c5f5 100644
--- a/app/controllers/invites_controller.rb
+++ b/app/controllers/invites_controller.rb
@@ -14,7 +14,7 @@ class InvitesController < ApplicationController
redirect_to path, notice: "You have been granted #{member.human_access} access to #{label}."
else
- redirect_to :back, alert: "The invitation could not be accepted."
+ redirect_back_or_default(options: { alert: "The invitation could not be accepted." })
end
end
@@ -31,7 +31,7 @@ class InvitesController < ApplicationController
redirect_to path, notice: "You have declined the invitation to join #{label}."
else
- redirect_to :back, alert: "The invitation could not be declined."
+ redirect_back_or_default(options: { alert: "The invitation could not be declined." })
end
end
diff --git a/app/controllers/profiles/notifications_controller.rb b/app/controllers/profiles/notifications_controller.rb
index 22423651c17..1fd1d6882df 100644
--- a/app/controllers/profiles/notifications_controller.rb
+++ b/app/controllers/profiles/notifications_controller.rb
@@ -29,7 +29,7 @@ class Profiles::NotificationsController < Profiles::ApplicationController
flash[:alert] = "Failed to save new settings"
end
- redirect_to :back
+ redirect_back_or_default(default: profile_notifications_path)
end
format.js
diff --git a/app/controllers/profiles_controller.rb b/app/controllers/profiles_controller.rb
index 26a4de15462..8da7b4d50ea 100644
--- a/app/controllers/profiles_controller.rb
+++ b/app/controllers/profiles_controller.rb
@@ -26,7 +26,7 @@ class ProfilesController < Profiles::ApplicationController
end
respond_to do |format|
- format.html { redirect_to :back }
+ format.html { redirect_back_or_default(default: { action: 'show' }) }
end
end
diff --git a/app/controllers/projects/avatars_controller.rb b/app/controllers/projects/avatars_controller.rb
index 9c3763d5934..548f1b9ebfe 100644
--- a/app/controllers/projects/avatars_controller.rb
+++ b/app/controllers/projects/avatars_controller.rb
@@ -12,7 +12,7 @@ class Projects::AvatarsController < Projects::ApplicationController
filename: @blob.name
)
else
- not_found!
+ render_404
end
end
diff --git a/app/controllers/projects/blob_controller.rb b/app/controllers/projects/blob_controller.rb
index ae9b1384463..93738aa1ee5 100644
--- a/app/controllers/projects/blob_controller.rb
+++ b/app/controllers/projects/blob_controller.rb
@@ -113,14 +113,14 @@ class Projects::BlobController < Projects::ApplicationController
end
end
- return not_found!
+ return render_404
end
end
def commit
@commit = @repository.commit(@ref)
- return not_found! unless @commit
+ return render_404 unless @commit
end
def assign_blob_vars
@@ -128,7 +128,7 @@ class Projects::BlobController < Projects::ApplicationController
@ref, @path = extract_ref(@id)
rescue InvalidPathError
- not_found!
+ render_404
end
def after_edit_path
@@ -161,7 +161,7 @@ class Projects::BlobController < Projects::ApplicationController
if params[:file].present?
params[:file_name] = params[:file].original_filename
end
- File.join(@path, File.basename(params[:file_name]))
+ File.join(@path, params[:file_name])
else
@path
end
diff --git a/app/controllers/projects/builds_controller.rb b/app/controllers/projects/builds_controller.rb
index 4e4ac6689d3..7d72e0b951b 100644
--- a/app/controllers/projects/builds_controller.rb
+++ b/app/controllers/projects/builds_controller.rb
@@ -1,11 +1,33 @@
class Projects::BuildsController < Projects::ApplicationController
before_action :ci_project
- before_action :build
+ before_action :build, except: [:index, :cancel_all]
- before_action :authorize_admin_project!, except: [:show, :status]
+ before_action :authorize_manage_builds!, except: [:index, :show, :status]
layout "project"
+ def index
+ @scope = params[:scope]
+ @all_builds = project.ci_builds
+ @builds = @all_builds.order('created_at DESC')
+ @builds =
+ case @scope
+ when 'all'
+ @builds
+ when 'finished'
+ @builds.finished
+ else
+ @builds.running_or_pending.reverse_order
+ end
+ @builds = @builds.page(params[:page]).per(30)
+ end
+
+ def cancel_all
+ @project.ci_builds.running_or_pending.each(&:cancel)
+
+ redirect_to namespace_project_builds_path(project.namespace, project)
+ end
+
def show
@builds = @ci_project.commits.find_by_sha(@build.sha).builds.order('id DESC')
@builds = @builds.where("id not in (?)", @build.id).page(params[:page]).per(20)
@@ -52,4 +74,10 @@ class Projects::BuildsController < Projects::ApplicationController
def build_path(build)
namespace_project_build_path(build.gl_project.namespace, build.gl_project, build)
end
+
+ def authorize_manage_builds!
+ unless can?(current_user, :manage_builds, project)
+ return page_404
+ end
+ end
end
diff --git a/app/controllers/projects/ci_services_controller.rb b/app/controllers/projects/ci_services_controller.rb
index 6d2756eba3d..550a019e8e2 100644
--- a/app/controllers/projects/ci_services_controller.rb
+++ b/app/controllers/projects/ci_services_controller.rb
@@ -14,23 +14,23 @@ class Projects::CiServicesController < Projects::ApplicationController
end
def update
- if @service.update_attributes(service_params)
- redirect_to edit_namespace_project_ci_service_path(@project, @project.namespace, @service.to_param)
+ if service.update_attributes(service_params)
+ redirect_to edit_namespace_project_ci_service_path(@project.namespace, @project, service.to_param)
else
render 'edit'
end
end
def test
- last_build = @project.builds.last
+ last_build = @project.ci_builds.last
- if @service.execute(last_build)
+ if service.execute(last_build)
message = { notice: 'We successfully tested the service' }
else
message = { alert: 'We tried to test the service but error occurred' }
end
- redirect_to :back, message
+ redirect_back_or_default(options: message)
end
private
diff --git a/app/controllers/projects/ci_web_hooks_controller.rb b/app/controllers/projects/ci_web_hooks_controller.rb
index 7f40ddcb3f3..a2d470d4a69 100644
--- a/app/controllers/projects/ci_web_hooks_controller.rb
+++ b/app/controllers/projects/ci_web_hooks_controller.rb
@@ -24,7 +24,7 @@ class Projects::CiWebHooksController < Projects::ApplicationController
def test
Ci::TestHookService.new.execute(hook, current_user)
- redirect_to :back
+ redirect_back_or_default(default: { action: 'index' })
end
def destroy
diff --git a/app/controllers/projects/commit_controller.rb b/app/controllers/projects/commit_controller.rb
index 7886f3c6deb..878c3a66e7d 100644
--- a/app/controllers/projects/commit_controller.rb
+++ b/app/controllers/projects/commit_controller.rb
@@ -4,7 +4,8 @@
class Projects::CommitController < Projects::ApplicationController
# Authorize
before_action :require_non_empty_project
- before_action :authorize_download_code!
+ before_action :authorize_download_code!, except: [:cancel_builds]
+ before_action :authorize_manage_builds!, only: [:cancel_builds]
before_action :commit
def show
@@ -55,4 +56,12 @@ class Projects::CommitController < Projects::ApplicationController
def commit
@commit ||= @project.commit(params[:id])
end
+
+ private
+
+ def authorize_manage_builds!
+ unless can?(current_user, :manage_builds, project)
+ return page_404
+ end
+ end
end
diff --git a/app/controllers/projects/commits_controller.rb b/app/controllers/projects/commits_controller.rb
index d1c15174aea..58fb946dbc2 100644
--- a/app/controllers/projects/commits_controller.rb
+++ b/app/controllers/projects/commits_controller.rb
@@ -12,7 +12,7 @@ class Projects::CommitsController < Projects::ApplicationController
@limit, @offset = (params[:limit] || 40), (params[:offset] || 0)
@commits = @repo.commits(@ref, @path, @limit, @offset)
- @note_counts = Note.where(commit_id: @commits.map(&:id)).
+ @note_counts = project.notes.where(commit_id: @commits.map(&:id)).
group(:commit_id).count
respond_to do |format|
diff --git a/app/controllers/projects/compare_controller.rb b/app/controllers/projects/compare_controller.rb
index d15004f93a6..71aaad1fad6 100644
--- a/app/controllers/projects/compare_controller.rb
+++ b/app/controllers/projects/compare_controller.rb
@@ -17,9 +17,10 @@ class Projects::CompareController < Projects::ApplicationController
execute(@project, head_ref, @project, base_ref)
if compare_result
- @commits = compare_result.commits
+ @commits = Commit.decorate(compare_result.commits, @project)
@diffs = compare_result.diffs
@commit = @commits.last
+ @first_commit = @commits.first
@line_notes = []
end
end
diff --git a/app/controllers/projects/deploy_keys_controller.rb b/app/controllers/projects/deploy_keys_controller.rb
index 40e2b37912b..7d09288bc80 100644
--- a/app/controllers/projects/deploy_keys_controller.rb
+++ b/app/controllers/projects/deploy_keys_controller.rb
@@ -46,7 +46,7 @@ class Projects::DeployKeysController < Projects::ApplicationController
def disable
@project.deploy_keys_projects.find_by(deploy_key_id: params[:id]).destroy
- redirect_to :back
+ redirect_back_or_default(default: { action: 'index' })
end
protected
diff --git a/app/controllers/projects/hooks_controller.rb b/app/controllers/projects/hooks_controller.rb
index 4e5b4125f5a..c7569541899 100644
--- a/app/controllers/projects/hooks_controller.rb
+++ b/app/controllers/projects/hooks_controller.rb
@@ -37,7 +37,7 @@ class Projects::HooksController < Projects::ApplicationController
flash[:alert] = 'Hook execution failed. Ensure the project has commits.'
end
- redirect_to :back
+ redirect_back_or_default(default: { action: 'index' })
end
def destroy
diff --git a/app/controllers/projects/issues_controller.rb b/app/controllers/projects/issues_controller.rb
index 0f89f2e88cc..e767efbdc0c 100644
--- a/app/controllers/projects/issues_controller.rb
+++ b/app/controllers/projects/issues_controller.rb
@@ -14,6 +14,9 @@ class Projects::IssuesController < Projects::ApplicationController
# Allow issues bulk update
before_action :authorize_admin_issues!, only: [:bulk_update]
+ # Cross-reference merge requests
+ before_action :closed_by_merge_requests, only: [:show]
+
respond_to :html
def index
@@ -55,9 +58,9 @@ class Projects::IssuesController < Projects::ApplicationController
end
def show
- @participants = @issue.participants(current_user, @project)
+ @participants = @issue.participants(current_user)
@note = @project.notes.new(noteable: @issue)
- @notes = @issue.notes.inc_author.fresh
+ @notes = @issue.notes.with_associations.fresh
@noteable = @issue
respond_with(@issue)
@@ -103,7 +106,7 @@ class Projects::IssuesController < Projects::ApplicationController
def bulk_update
result = Issues::BulkUpdateService.new(project, current_user, bulk_update_params).execute
- redirect_to :back, notice: "#{result[:count]} issues updated"
+ redirect_back_or_default(default: { action: 'index' }, options: { notice: "#{result[:count]} issues updated" })
end
def toggle_subscription
@@ -112,6 +115,10 @@ class Projects::IssuesController < Projects::ApplicationController
render nothing: true
end
+ def closed_by_merge_requests
+ @closed_by_merge_requests ||= @issue.closed_by_merge_requests(current_user)
+ end
+
protected
def issue
diff --git a/app/controllers/projects/merge_requests_controller.rb b/app/controllers/projects/merge_requests_controller.rb
index 7570934e727..16c42386623 100644
--- a/app/controllers/projects/merge_requests_controller.rb
+++ b/app/controllers/projects/merge_requests_controller.rb
@@ -56,6 +56,8 @@ class Projects::MergeRequestsController < Projects::ApplicationController
def diffs
@commit = @merge_request.last_commit
+ @first_commit = @merge_request.first_commit
+
@comments_allowed = @reply_allowed = true
@comments_target = {
noteable_type: 'MergeRequest',
@@ -89,7 +91,8 @@ class Projects::MergeRequestsController < Projects::ApplicationController
@target_project = merge_request.target_project
@source_project = merge_request.source_project
@commits = @merge_request.compare_commits
- @commit = @merge_request.compare_commits.last
+ @commit = @merge_request.last_commit
+ @first_commit = @merge_request.first_commit
@diffs = @merge_request.compare_diffs
@note_counts = Note.where(commit_id: @commits.map(&:id)).
group(:commit_id).count
@@ -246,7 +249,7 @@ class Projects::MergeRequestsController < Projects::ApplicationController
end
def define_show_vars
- @participants = @merge_request.participants(current_user, @project)
+ @participants = @merge_request.participants(current_user)
# Build a note object for comment form
@note = @project.notes.new(noteable: @merge_request)
@@ -259,7 +262,7 @@ class Projects::MergeRequestsController < Projects::ApplicationController
@commits = @merge_request.commits
@merge_request_diff = @merge_request.merge_request_diff
-
+
if @merge_request.locked_long_ago?
@merge_request.unlock_mr
@merge_request.close
diff --git a/app/controllers/projects/milestones_controller.rb b/app/controllers/projects/milestones_controller.rb
index 86f4a02a6e9..15506bd677a 100644
--- a/app/controllers/projects/milestones_controller.rb
+++ b/app/controllers/projects/milestones_controller.rb
@@ -75,11 +75,7 @@ class Projects::MilestonesController < Projects::ApplicationController
end
def sort_issues
- @issues = @milestone.issues.where(id: params['sortable_issue'])
- @issues.each do |issue|
- issue.position = params['sortable_issue'].index(issue.id.to_s) + 1
- issue.save
- end
+ @milestone.sort_issues(params['sortable_issue'].map(&:to_i))
render json: { saved: true }
end
diff --git a/app/controllers/projects/notes_controller.rb b/app/controllers/projects/notes_controller.rb
index 0f5d82ce133..41cd08c93c6 100644
--- a/app/controllers/projects/notes_controller.rb
+++ b/app/controllers/projects/notes_controller.rb
@@ -25,7 +25,7 @@ class Projects::NotesController < Projects::ApplicationController
respond_to do |format|
format.json { render_note_json(@note) }
- format.html { redirect_to :back }
+ format.html { redirect_back_or_default }
end
end
@@ -34,7 +34,7 @@ class Projects::NotesController < Projects::ApplicationController
respond_to do |format|
format.json { render_note_json(@note) }
- format.html { redirect_to :back }
+ format.html { redirect_back_or_default }
end
end
diff --git a/app/controllers/projects/project_members_controller.rb b/app/controllers/projects/project_members_controller.rb
index cf73bc01c8f..9de5269cd25 100644
--- a/app/controllers/projects/project_members_controller.rb
+++ b/app/controllers/projects/project_members_controller.rb
@@ -72,7 +72,8 @@ class Projects::ProjectMembersController < Projects::ApplicationController
def leave
if @project.namespace == current_user.namespace
- return redirect_to(:back, alert: 'You can not leave your own project. Transfer or delete the project.')
+ message = 'You can not leave your own project. Transfer or delete the project.'
+ return redirect_back_or_default(default: { action: 'index' }, options: { alert: message })
end
@project.project_members.find_by(user_id: current_user).destroy
diff --git a/app/controllers/projects/raw_controller.rb b/app/controllers/projects/raw_controller.rb
index 5f6fbce795e..d5ee6ac8663 100644
--- a/app/controllers/projects/raw_controller.rb
+++ b/app/controllers/projects/raw_controller.rb
@@ -20,7 +20,7 @@ class Projects::RawController < Projects::ApplicationController
disposition: 'inline'
)
else
- not_found!
+ render_404
end
end
diff --git a/app/controllers/projects/refs_controller.rb b/app/controllers/projects/refs_controller.rb
index 6080c849c8d..c4e18c17077 100644
--- a/app/controllers/projects/refs_controller.rb
+++ b/app/controllers/projects/refs_controller.rb
@@ -3,6 +3,7 @@ class Projects::RefsController < Projects::ApplicationController
include TreeHelper
before_action :require_non_empty_project
+ before_action :validate_ref_id
before_action :assign_ref_vars
before_action :authorize_download_code!
@@ -71,4 +72,10 @@ class Projects::RefsController < Projects::ApplicationController
format.js
end
end
+
+ private
+
+ def validate_ref_id
+ return not_found! if params[:id].present? && params[:id] !~ Gitlab::Regex.git_reference_regex
+ end
end
diff --git a/app/controllers/projects/repositories_controller.rb b/app/controllers/projects/repositories_controller.rb
index c4a5e2d6359..ba9aea1c165 100644
--- a/app/controllers/projects/repositories_controller.rb
+++ b/app/controllers/projects/repositories_controller.rb
@@ -11,18 +11,9 @@ class Projects::RepositoriesController < Projects::ApplicationController
end
def archive
- begin
- file_path = ArchiveRepositoryService.new(@project, params[:ref], params[:format]).execute
- rescue
- return head :not_found
- end
-
- if file_path
- # Send file to user
- response.headers["Content-Length"] = File.open(file_path).size.to_s
- send_file file_path
- else
- redirect_to request.fullpath
- end
+ render json: ArchiveRepositoryService.new(@project, params[:ref], params[:format]).execute
+ rescue => ex
+ logger.error("#{self.class.name}: #{ex}")
+ return git_not_found!
end
end
diff --git a/app/controllers/projects/runners_controller.rb b/app/controllers/projects/runners_controller.rb
index 6cb6e3ef6d4..bfbcf2567f3 100644
--- a/app/controllers/projects/runners_controller.rb
+++ b/app/controllers/projects/runners_controller.rb
@@ -6,11 +6,10 @@ class Projects::RunnersController < Projects::ApplicationController
layout 'project_settings'
def index
- @runners = @ci_project.runners.order('id DESC')
- @specific_runners =
- Ci::Runner.specific.includes(:runner_projects).
- where(Ci::RunnerProject.table_name => { project_id: current_user.authorized_projects } ).
- where.not(id: @runners).order("#{Ci::Runner.table_name}.id DESC").page(params[:page]).per(20)
+ @runners = @ci_project.runners.ordered
+ @specific_runners = current_user.ci_authorized_runners.
+ where.not(id: @ci_project.runners).
+ ordered.page(params[:page]).per(20)
@shared_runners = Ci::Runner.shared.active
@shared_runners_count = @shared_runners.count(:all)
end
@@ -60,6 +59,6 @@ class Projects::RunnersController < Projects::ApplicationController
end
def runner_params
- params.require(:runner).permit(:description, :tag_list, :contacted_at, :active)
+ params.require(:runner).permit(:description, :tag_list, :active)
end
end
diff --git a/app/controllers/projects/services_controller.rb b/app/controllers/projects/services_controller.rb
index 3047ee8a1ff..42dbb497e01 100644
--- a/app/controllers/projects/services_controller.rb
+++ b/app/controllers/projects/services_controller.rb
@@ -9,6 +9,10 @@ class Projects::ServicesController < Projects::ApplicationController
:note_events, :send_from_committer_email, :disable_diffs, :external_wiki_url,
:notify, :color,
:server_host, :server_port, :default_irc_uri, :enable_ssl_verification]
+
+ # Parameters to ignore if no value is specified
+ FILTER_BLANK_PARAMS = [:password]
+
# Authorize
before_action :authorize_admin_project!
before_action :service, only: [:edit, :update, :test]
@@ -48,7 +52,7 @@ class Projects::ServicesController < Projects::ApplicationController
message = { alert: error_message }
end
- redirect_to :back, message
+ redirect_back_or_default(options: message)
end
private
@@ -59,7 +63,9 @@ class Projects::ServicesController < Projects::ApplicationController
def service_params
service_params = params.require(:service).permit(ALLOWED_PARAMS)
- service_params.delete("password") if service_params["password"].blank?
+ FILTER_BLANK_PARAMS.each do |param|
+ service_params.delete(param) if service_params[param].blank?
+ end
service_params
end
end
diff --git a/app/controllers/projects/snippets_controller.rb b/app/controllers/projects/snippets_controller.rb
index b07a2a8db2f..2104c7a7a71 100644
--- a/app/controllers/projects/snippets_controller.rb
+++ b/app/controllers/projects/snippets_controller.rb
@@ -21,6 +21,7 @@ class Projects::SnippetsController < Projects::ApplicationController
filter: :by_project,
project: @project
})
+ @snippets = @snippets.page(params[:page]).per(PER_PAGE)
end
def new
diff --git a/app/controllers/projects/tree_controller.rb b/app/controllers/projects/tree_controller.rb
index 7eaff1d61ee..bdcb1a3e297 100644
--- a/app/controllers/projects/tree_controller.rb
+++ b/app/controllers/projects/tree_controller.rb
@@ -10,7 +10,7 @@ class Projects::TreeController < Projects::ApplicationController
before_action :authorize_push_code!, only: [:create_dir]
def show
- return not_found! unless @repository.commit(@ref)
+ return render_404 unless @repository.commit(@ref)
if tree.entries.empty?
if @repository.blob_at(@commit.id, @path)
@@ -19,7 +19,7 @@ class Projects::TreeController < Projects::ApplicationController
File.join(@ref, @path))
) and return
elsif @path.present?
- return not_found!
+ return render_404
end
end
@@ -31,7 +31,7 @@ class Projects::TreeController < Projects::ApplicationController
end
def create_dir
- return not_found! unless @commit_params.values.all?
+ return render_404 unless @commit_params.values.all?
begin
result = Files::CreateDirService.new(@project, current_user, @commit_params).execute
diff --git a/app/controllers/projects/uploads_controller.rb b/app/controllers/projects/uploads_controller.rb
index 71ecc20dd95..e1fe7ea2114 100644
--- a/app/controllers/projects/uploads_controller.rb
+++ b/app/controllers/projects/uploads_controller.rb
@@ -20,7 +20,7 @@ class Projects::UploadsController < Projects::ApplicationController
end
def show
- return not_found! if uploader.nil? || !uploader.file.exists?
+ return render_404 if uploader.nil? || !uploader.file.exists?
disposition = uploader.image? ? 'inline' : 'attachment'
send_file uploader.file.path, disposition: disposition
diff --git a/app/controllers/projects_controller.rb b/app/controllers/projects_controller.rb
index 213c2a7173b..00d13a83ce8 100644
--- a/app/controllers/projects_controller.rb
+++ b/app/controllers/projects_controller.rb
@@ -1,11 +1,14 @@
class ProjectsController < ApplicationController
- prepend_before_filter :render_go_import, only: [:show]
+ include ExtractsPath
+
+ prepend_before_action :render_go_import, only: [:show]
skip_before_action :authenticate_user!, only: [:show, :activity]
before_action :project, except: [:new, :create]
before_action :repository, except: [:new, :create]
+ before_action :assign_ref_vars, :tree, only: [:show], if: :repo_exists?
# Authorize
- before_action :authorize_admin_project!, only: [:edit, :update, :destroy, :transfer, :archive, :unarchive]
+ before_action :authorize_admin_project!, only: [:edit, :update]
before_action :event_filter, only: [:show, :activity]
layout :determine_layout
@@ -56,6 +59,8 @@ class ProjectsController < ApplicationController
end
def transfer
+ return access_denied! unless can?(current_user, :change_namespace, @project)
+
namespace = Namespace.find_by(id: params[:new_namespace_id])
::Projects::TransferService.new(project, current_user).execute(namespace)
@@ -64,6 +69,15 @@ class ProjectsController < ApplicationController
end
end
+ def remove_fork
+ return access_denied! unless can?(current_user, :remove_fork_project, @project)
+
+ if @project.forked?
+ @project.forked_project_link.destroy
+ flash[:notice] = 'The fork relationship has been removed.'
+ end
+ end
+
def activity
respond_to do |format|
format.html
@@ -87,7 +101,7 @@ class ProjectsController < ApplicationController
render 'projects/empty'
else
if current_user
- @membership = @project.project_member_by_id(current_user.id)
+ @membership = @project.team.find_member(current_user.id)
end
render :show
@@ -110,11 +124,7 @@ class ProjectsController < ApplicationController
::Projects::DestroyService.new(@project, current_user, {}).execute
flash[:alert] = "Project '#{@project.name}' was deleted."
- if request.referer.include?('/admin')
- redirect_to admin_namespaces_projects_path
- else
- redirect_to dashboard_projects_path
- end
+ redirect_back_or_default(default: dashboard_projects_path, options: {})
rescue Projects::DestroyService::DestroyError => ex
redirect_to edit_project_path(@project), alert: ex.message
end
@@ -139,6 +149,7 @@ class ProjectsController < ApplicationController
def archive
return access_denied! unless can?(current_user, :archive_project, @project)
+
@project.archive!
respond_to do |format|
@@ -148,6 +159,7 @@ class ProjectsController < ApplicationController
def unarchive
return access_denied! unless can?(current_user, :archive_project, @project)
+
@project.unarchive!
respond_to do |format|
@@ -225,4 +237,14 @@ class ProjectsController < ApplicationController
render "go_import", layout: false
end
+
+ def repo_exists?
+ project.repository_exists? && !project.empty_repo?
+ end
+
+ # Override get_id from ExtractsPath, which returns the branch and file path
+ # for the blob/tree, which in this case is just the root of the default branch.
+ def get_id
+ project.repository.root_ref
+ end
end
diff --git a/app/controllers/search_controller.rb b/app/controllers/search_controller.rb
index eb0408a95e5..9bb42ec86b3 100644
--- a/app/controllers/search_controller.rb
+++ b/app/controllers/search_controller.rb
@@ -23,8 +23,8 @@ class SearchController < ApplicationController
@search_results =
if @project
- unless %w(blobs notes issues merge_requests milestones wiki_blobs).
- include?(@scope)
+ unless %w(blobs notes issues merge_requests milestones wiki_blobs
+ commits).include?(@scope)
@scope = 'blobs'
end
diff --git a/app/controllers/uploads_controller.rb b/app/controllers/uploads_controller.rb
index 28536e359e5..868b05929d7 100644
--- a/app/controllers/uploads_controller.rb
+++ b/app/controllers/uploads_controller.rb
@@ -10,7 +10,7 @@ class UploadsController < ApplicationController
end
unless uploader.file && uploader.file.exists?
- return not_found!
+ return render_404
end
disposition = uploader.image? ? 'inline' : 'attachment'
@@ -21,7 +21,7 @@ class UploadsController < ApplicationController
def find_model
unless upload_model && upload_mount
- return not_found!
+ return render_404
end
@model = upload_model.find(params[:id])
@@ -44,7 +44,7 @@ class UploadsController < ApplicationController
return if authorized
if current_user
- not_found!
+ render_404
else
authenticate_user!
end
diff --git a/app/finders/issuable_finder.rb b/app/finders/issuable_finder.rb
index 97c7e74c294..c407dfc163a 100644
--- a/app/finders/issuable_finder.rb
+++ b/app/finders/issuable_finder.rb
@@ -53,15 +53,36 @@ class IssuableFinder
end
end
+ def project?
+ params[:project_id].present?
+ end
+
def project
return @project if defined?(@project)
- @project =
- if params[:project_id].present?
- Project.find(params[:project_id])
- else
- nil
- end
+ if project?
+ @project = Project.find(params[:project_id])
+
+ unless Ability.abilities.allowed?(current_user, :read_project, @project)
+ @project = nil
+ end
+ else
+ @project = nil
+ end
+
+ @project
+ end
+
+ def projects
+ return @projects if defined?(@projects)
+
+ if project?
+ project
+ elsif current_user && params[:authorized_only].presence && !current_user_related?
+ current_user.authorized_projects
+ else
+ ProjectsFinder.new.execute(current_user)
+ end
end
def search
@@ -72,7 +93,7 @@ class IssuableFinder
params[:milestone_title].present?
end
- def no_milestones?
+ def filter_by_no_milestone?
milestones? && params[:milestone_title] == Milestone::None.title
end
@@ -81,12 +102,22 @@ class IssuableFinder
@milestones =
if milestones?
- Milestone.where(title: params[:milestone_title])
+ scope = Milestone.where(project_id: projects)
+
+ scope.where(title: params[:milestone_title])
else
nil
end
end
+ def labels?
+ params[:label_name].present?
+ end
+
+ def filter_by_no_label?
+ labels? && params[:label_name] == Label::None.title
+ end
+
def assignee?
params[:assignee_id].present?
end
@@ -120,19 +151,7 @@ class IssuableFinder
private
def init_collection
- table_name = klass.table_name
-
- if project
- if Ability.abilities.allowed?(current_user, :read_project, project)
- project.send(table_name)
- else
- []
- end
- elsif current_user && params[:authorized_only].presence && !current_user_related?
- klass.of_projects(current_user.authorized_projects).references(:project)
- else
- klass.of_projects(ProjectsFinder.new.execute(current_user)).references(:project)
- end
+ klass.all
end
def by_scope(items)
@@ -170,7 +189,12 @@ class IssuableFinder
end
def by_project(items)
- items = items.of_projects(project.id) if project
+ items =
+ if projects
+ items.of_projects(projects).references(:project)
+ else
+ items.none
+ end
items
end
@@ -185,18 +209,6 @@ class IssuableFinder
items.sort(params[:sort])
end
- def by_milestone(items)
- if milestones?
- if no_milestones?
- items = items.where(milestone_id: [-1, nil])
- else
- items = items.where(milestone_id: milestones.try(:pluck, :id))
- end
- end
-
- items
- end
-
def by_assignee(items)
if assignee?
items = items.where(assignee_id: assignee.try(:id))
@@ -213,20 +225,36 @@ class IssuableFinder
items
end
- def by_label(items)
- if params[:label_name].present?
- if params[:label_name] == Label::None.title
- item_ids = LabelLink.where(target_type: klass.name).pluck(:target_id)
+ def by_milestone(items)
+ if milestones?
+ if filter_by_no_milestone?
+ items = items.where(milestone_id: [-1, nil])
+ else
+ items = items.joins(:milestone).where(milestones: { title: params[:milestone_title] })
+
+ if projects
+ items = items.where(milestones: { project_id: projects })
+ end
+ end
+ end
+
+ items
+ end
- items = items.where('id NOT IN (?)', item_ids)
+ def by_label(items)
+ if labels?
+ if filter_by_no_label?
+ items = items.
+ joins("LEFT OUTER JOIN label_links ON label_links.target_type = '#{klass.name}' AND label_links.target_id = #{klass.table_name}.id").
+ where(label_links: { id: nil })
else
label_names = params[:label_name].split(",")
- item_ids = LabelLink.joins(:label).
- where('labels.title in (?)', label_names).
- where(target_type: klass.name).pluck(:target_id)
+ items = items.joins(:labels).where(labels: { title: label_names })
- items = items.where(id: item_ids)
+ if projects
+ items = items.where(labels: { project_id: projects })
+ end
end
end
diff --git a/app/helpers/appearances_helper.rb b/app/helpers/appearances_helper.rb
index 14df8d4cbd7..c5820bf4c50 100644
--- a/app/helpers/appearances_helper.rb
+++ b/app/helpers/appearances_helper.rb
@@ -16,6 +16,6 @@ module AppearancesHelper
end
def brand_header_logo
- image_tag 'logo.svg'
+ render 'shared/logo.svg'
end
end
diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb
index cab2278adb7..8ecdeaf8e76 100644
--- a/app/helpers/application_helper.rb
+++ b/app/helpers/application_helper.rb
@@ -68,13 +68,17 @@ module ApplicationHelper
end
end
- def avatar_icon(user_email = '', size = nil)
- user = User.find_by(email: user_email)
+ def avatar_icon(user_or_email = nil, size = nil)
+ if user_or_email.is_a?(User)
+ user = user_or_email
+ else
+ user = User.find_by(email: user_or_email)
+ end
if user
user.avatar_url(size) || default_avatar
else
- gravatar_icon(user_email, size)
+ gravatar_icon(user_or_email, size)
end
end
diff --git a/app/helpers/ci_status_helper.rb b/app/helpers/ci_status_helper.rb
index dbd1e26fa79..ed88df5dd86 100644
--- a/app/helpers/ci_status_helper.rb
+++ b/app/helpers/ci_status_helper.rb
@@ -42,4 +42,13 @@ module CiStatusHelper
icon(icon_name)
end
+
+ def render_ci_status(ci_commit)
+ link_to ci_status_path(ci_commit),
+ class: "c#{ci_status_color(ci_commit)}",
+ title: "Build status: #{ci_commit.status}",
+ data: { toggle: 'tooltip', placement: 'left' } do
+ ci_status_icon(ci_commit)
+ end
+ end
end
diff --git a/app/helpers/clipboard_helper.rb b/app/helpers/clipboard_helper.rb
new file mode 100644
index 00000000000..3c1d7569fac
--- /dev/null
+++ b/app/helpers/clipboard_helper.rb
@@ -0,0 +1,8 @@
+module ClipboardHelper
+ def clipboard_button
+ content_tag :button,
+ icon('clipboard'),
+ class: 'btn btn-xs btn-clipboard js-clipboard-trigger',
+ type: :button
+ end
+end
diff --git a/app/helpers/diff_helper.rb b/app/helpers/diff_helper.rb
index b896fba3704..e65e37211c4 100644
--- a/app/helpers/diff_helper.rb
+++ b/app/helpers/diff_helper.rb
@@ -170,7 +170,8 @@ module DiffHelper
def commit_for_diff(diff)
if diff.deleted_file
- @merge_request ? @merge_request.commits.last : @commit.parents.first
+ first_commit = @first_commit || @commit
+ first_commit.parent
else
@commit
end
diff --git a/app/helpers/gitlab_markdown_helper.rb b/app/helpers/gitlab_markdown_helper.rb
index 12b87dca798..65813482120 100644
--- a/app/helpers/gitlab_markdown_helper.rb
+++ b/app/helpers/gitlab_markdown_helper.rb
@@ -19,7 +19,8 @@ module GitlabMarkdownHelper
escape_once(body)
end
- gfm_body = Gitlab::Markdown.gfm(escaped_body, project: @project, current_user: current_user)
+ user = current_user if defined?(current_user)
+ gfm_body = Gitlab::Markdown.gfm(escaped_body, project: @project, current_user: user)
fragment = Nokogiri::HTML::DocumentFragment.parse(gfm_body)
if fragment.children.size == 1 && fragment.children[0].name == 'a'
@@ -45,29 +46,39 @@ module GitlabMarkdownHelper
end
def markdown(text, context = {})
+ return "" unless text.present?
+
context.reverse_merge!(
- current_user: current_user,
path: @path,
+ pipeline: :default,
project: @project,
project_wiki: @project_wiki,
ref: @ref
)
- Gitlab::Markdown.render(text, context)
+ user = current_user if defined?(current_user)
+
+ html = Gitlab::Markdown.render(text, context)
+ Gitlab::Markdown.post_process(html, pipeline: context[:pipeline], project: @project, user: user)
end
# TODO (rspeicher): Remove all usages of this helper and just call `markdown`
# with a custom pipeline depending on the content being rendered
def gfm(text, options = {})
+ return "" unless text.present?
+
options.reverse_merge!(
- current_user: current_user,
path: @path,
+ pipeline: :default,
project: @project,
project_wiki: @project_wiki,
ref: @ref
)
- Gitlab::Markdown.gfm(text, options)
+ user = current_user if defined?(current_user)
+
+ html = Gitlab::Markdown.gfm(text, options)
+ Gitlab::Markdown.post_process(html, pipeline: options[:pipeline], project: @project, user: user)
end
def asciidoc(text)
diff --git a/app/helpers/gitlab_routing_helper.rb b/app/helpers/gitlab_routing_helper.rb
index 4d9da6ff837..b0b536d4649 100644
--- a/app/helpers/gitlab_routing_helper.rb
+++ b/app/helpers/gitlab_routing_helper.rb
@@ -25,6 +25,10 @@ module GitlabRoutingHelper
namespace_project_commits_path(project.namespace, project, @ref || project.repository.root_ref)
end
+ def project_builds_path(project, *args)
+ namespace_project_builds_path(project.namespace, project, *args)
+ end
+
def activity_project_path(project, *args)
activity_namespace_project_path(project.namespace, project, *args)
end
diff --git a/app/helpers/issues_helper.rb b/app/helpers/issues_helper.rb
index 6ddb37cd0dc..fda18e7b316 100644
--- a/app/helpers/issues_helper.rb
+++ b/app/helpers/issues_helper.rb
@@ -83,6 +83,10 @@ module IssuesHelper
end
end
+ def merge_requests_sentence(merge_requests)
+ merge_requests.map(&:to_reference).to_sentence(last_word_connector: ', or ')
+ end
+
# Required for Gitlab::Markdown::IssueReferenceFilter
module_function :url_for_issue
end
diff --git a/app/helpers/labels_helper.rb b/app/helpers/labels_helper.rb
index 66b18eea699..ee04ace35d0 100644
--- a/app/helpers/labels_helper.rb
+++ b/app/helpers/labels_helper.rb
@@ -92,11 +92,19 @@ module LabelsHelper
end
end
- def project_labels_options(project)
- labels = project.labels.to_a
- labels.unshift(Label::None)
- labels.unshift(Label::Any)
- options_from_collection_for_select(labels, 'name', 'title', params[:label_name])
+ def projects_labels_options
+ labels =
+ if @project
+ @project.labels
+ else
+ Label.where(project_id: @projects)
+ end
+
+ grouped_labels = Labels::GroupService.new(labels).execute
+ grouped_labels.unshift(Label::None)
+ grouped_labels.unshift(Label::Any)
+
+ options_from_collection_for_select(grouped_labels, 'name', 'title', params[:label_name])
end
# Required for Gitlab::Markdown::LabelReferenceFilter
diff --git a/app/helpers/merge_requests_helper.rb b/app/helpers/merge_requests_helper.rb
index 81773e7afcf..728d877ace2 100644
--- a/app/helpers/merge_requests_helper.rb
+++ b/app/helpers/merge_requests_helper.rb
@@ -47,7 +47,7 @@ module MergeRequestsHelper
end
def issues_sentence(issues)
- issues.map { |i| "##{i.iid}" }.to_sentence
+ issues.map(&:to_reference).to_sentence
end
def mr_change_branches_path(merge_request)
diff --git a/app/helpers/preferences_helper.rb b/app/helpers/preferences_helper.rb
index 4710171ebaa..c73cb3028ee 100644
--- a/app/helpers/preferences_helper.rb
+++ b/app/helpers/preferences_helper.rb
@@ -34,7 +34,8 @@ module PreferencesHelper
def project_view_choices
[
['Readme (default)', :readme],
- ['Activity view', :activity]
+ ['Activity view', :activity],
+ ['Files view', :files]
]
end
@@ -46,8 +47,7 @@ module PreferencesHelper
Gitlab::ColorSchemes.for_user(current_user).css_class
end
- def prefer_readme?
- !current_user ||
- current_user.project_view == 'readme'
+ def default_project_view
+ current_user ? current_user.project_view : 'readme'
end
end
diff --git a/app/helpers/projects_helper.rb b/app/helpers/projects_helper.rb
index a0220af4c30..5301c2ccf76 100644
--- a/app/helpers/projects_helper.rb
+++ b/app/helpers/projects_helper.rb
@@ -29,7 +29,7 @@ module ProjectsHelper
author_html = ""
# Build avatar image tag
- author_html << image_tag(avatar_icon(author.try(:email), opts[:size]), width: opts[:size], class: "avatar avatar-inline #{"s#{opts[:size]}" if opts[:size]}", alt:'') if opts[:avatar]
+ author_html << image_tag(avatar_icon(author, opts[:size]), width: opts[:size], class: "avatar avatar-inline #{"s#{opts[:size]}" if opts[:size]}", alt:'') if opts[:avatar]
# Build name span tag
author_html << content_tag(:span, sanitize(author.name), class: opts[:author_class]) if opts[:name]
@@ -70,6 +70,10 @@ module ProjectsHelper
"You are going to transfer #{project.name_with_namespace} to another owner. Are you ABSOLUTELY sure?"
end
+ def remove_fork_project_message(project)
+ "You are going to remove the fork relationship to source project #{@project.forked_from_project.name_with_namespace}. Are you ABSOLUTELY sure?"
+ end
+
def project_nav_tabs
@nav_tabs ||= get_project_nav_tabs(@project, current_user)
end
@@ -113,6 +117,10 @@ module ProjectsHelper
nav_tabs << :merge_requests
end
+ if project.gitlab_ci? && can?(current_user, :read_build, project)
+ nav_tabs << :builds
+ end
+
if can?(current_user, :admin_project, project)
nav_tabs << :settings
end
diff --git a/app/helpers/runners_helper.rb b/app/helpers/runners_helper.rb
index 5d7d06c8490..46eb82a354f 100644
--- a/app/helpers/runners_helper.rb
+++ b/app/helpers/runners_helper.rb
@@ -1,20 +1,29 @@
module RunnersHelper
def runner_status_icon(runner)
- unless runner.contacted_at
- return content_tag :i, nil,
- class: "fa fa-warning-sign",
- title: "New runner. Has not connected yet"
+ status = runner.status
+ case status
+ when :not_connected
+ content_tag :i, nil,
+ class: "fa fa-warning",
+ title: "New runner. Has not connected yet"
+
+ when :online, :offline, :paused
+ content_tag :i, nil,
+ class: "fa fa-circle runner-status-#{status}",
+ title: "Runner is #{status}, last contact was #{time_ago_in_words(runner.contacted_at)} ago"
end
+ end
- status =
- if runner.active?
- runner.contacted_at > 3.hour.ago ? :online : :offline
- else
- :paused
- end
+ def runner_link(runner)
+ display_name = truncate(runner.display_name, length: 15)
+ id = "\##{runner.id}"
- content_tag :i, nil,
- class: "fa fa-circle runner-status-#{status}",
- title: "Runner is #{status}, last contact was #{time_ago_in_words(runner.contacted_at)} ago"
+ if current_user && current_user.admin
+ link_to ci_admin_runner_path(runner) do
+ display_name + id
+ end
+ else
+ display_name + id
+ end
end
end
diff --git a/app/helpers/tab_helper.rb b/app/helpers/tab_helper.rb
index 0e7d8065ac7..04e53fe7c61 100644
--- a/app/helpers/tab_helper.rb
+++ b/app/helpers/tab_helper.rb
@@ -110,22 +110,4 @@ module TabHelper
'active'
end
end
-
- # Use nav_tab for save controller/action but different params
- def nav_tab(key, value, &block)
- o = {}
- o[:class] = ""
-
- if value.nil?
- o[:class] << " active" if params[key].blank?
- else
- o[:class] << " active" if params[key] == value
- end
-
- if block_given?
- content_tag(:li, capture(&block), o)
- else
- content_tag(:li, nil, o)
- end
- end
end
diff --git a/app/mailers/abuse_report_mailer.rb b/app/mailers/abuse_report_mailer.rb
new file mode 100644
index 00000000000..f0c41f69a5c
--- /dev/null
+++ b/app/mailers/abuse_report_mailer.rb
@@ -0,0 +1,12 @@
+class AbuseReportMailer < BaseMailer
+ include Gitlab::CurrentSettings
+
+ def notify(abuse_report_id)
+ @abuse_report = AbuseReport.find(abuse_report_id)
+
+ mail(
+ to: current_application_settings.admin_notification_email,
+ subject: "#{@abuse_report.user.name} (#{@abuse_report.user.username}) was reported for abuse"
+ )
+ end
+end
diff --git a/app/models/ability.rb b/app/models/ability.rb
index 77c121ca5e8..b72178fa126 100644
--- a/app/models/ability.rb
+++ b/app/models/ability.rb
@@ -41,6 +41,7 @@ class Ability
:read_project_member,
:read_merge_request,
:read_note,
+ :read_build,
:download_code
]
@@ -127,6 +128,7 @@ class Ability
:read_project_member,
:read_merge_request,
:read_note,
+ :read_build,
:create_project,
:create_issue,
:create_note
@@ -187,7 +189,8 @@ class Ability
:change_visibility_level,
:rename_project,
:remove_project,
- :archive_project
+ :archive_project,
+ :remove_fork_project
]
end
diff --git a/app/models/application_setting.rb b/app/models/application_setting.rb
index c8841178e93..05430c2ee18 100644
--- a/app/models/application_setting.rb
+++ b/app/models/application_setting.rb
@@ -44,6 +44,10 @@ class ApplicationSetting < ActiveRecord::Base
allow_blank: true,
format: { with: /\A#{URI.regexp(%w(http https))}\z/, message: "should be a valid url" }
+ validates :admin_notification_email,
+ allow_blank: true,
+ email: true
+
validates_each :restricted_visibility_levels do |record, attr, value|
unless value.nil?
value.each do |level|
diff --git a/app/models/ci/build.rb b/app/models/ci/build.rb
index f8c731a7bf7..b19e2ac1363 100644
--- a/app/models/ci/build.rb
+++ b/app/models/ci/build.rb
@@ -93,10 +93,7 @@ module Ci
Ci::WebHookService.new.build_end(build)
end
- if build.commit.should_create_next_builds?(build)
- build.commit.create_next_builds(build.ref, build.tag, build.user, build.trigger_request)
- end
-
+ build.commit.create_next_builds(build)
project.execute_services(build)
if project.coverage_enabled?
@@ -119,7 +116,7 @@ module Ci
end
def variables
- yaml_variables + project_variables + trigger_variables
+ predefined_variables + yaml_variables + project_variables + trigger_variables
end
def project
@@ -220,17 +217,29 @@ module Ci
def cancel_url
if active?
Gitlab::Application.routes.url_helpers.
- cancel_namespace_project_build_path(gl_project.namespace, gl_project, self, return_to: request.original_url)
+ cancel_namespace_project_build_path(gl_project.namespace, gl_project, self)
end
end
def retry_url
if commands.present?
Gitlab::Application.routes.url_helpers.
- cancel_namespace_project_build_path(gl_project.namespace, gl_project, self, return_to: request.original_url)
+ retry_namespace_project_build_path(gl_project.namespace, gl_project, self)
end
end
+ def can_be_served?(runner)
+ (tag_list - runner.tag_list).empty?
+ end
+
+ def any_runners_online?
+ project.any_runners? { |runner| runner.active? && runner.online? && can_be_served?(runner) }
+ end
+
+ def show_warning?
+ pending? && !any_runners_online?
+ end
+
private
def yaml_variables
@@ -258,5 +267,14 @@ module Ci
[]
end
end
+
+ def predefined_variables
+ variables = []
+ variables << { key: :CI_BUILD_TAG, value: ref, public: true } if tag?
+ variables << { key: :CI_BUILD_NAME, value: name, public: true }
+ variables << { key: :CI_BUILD_STAGE, value: stage, public: true }
+ variables << { key: :CI_BUILD_TRIGGERED, value: 'true', public: true } if trigger_request
+ variables
+ end
end
end
diff --git a/app/models/ci/commit.rb b/app/models/ci/commit.rb
index 68864edfbbf..e58420d82d4 100644
--- a/app/models/ci/commit.rb
+++ b/app/models/ci/commit.rb
@@ -24,6 +24,8 @@ module Ci
has_many :builds, class_name: 'Ci::Build'
has_many :trigger_requests, dependent: :destroy, class_name: 'Ci::TriggerRequest'
+ scope :ordered, -> { order('CASE WHEN ci_commits.committed_at IS NULL THEN 0 ELSE 1 END', :committed_at, :id) }
+
validates_presence_of :sha
validate :valid_commit_sha
@@ -89,19 +91,28 @@ module Ci
def create_builds(ref, tag, user, trigger_request = nil)
return unless config_processor
config_processor.stages.any? do |stage|
- CreateBuildsService.new.execute(self, stage, ref, tag, user, trigger_request).present?
+ CreateBuildsService.new.execute(self, stage, ref, tag, user, trigger_request, 'success').present?
end
end
- def create_next_builds(ref, tag, user, trigger_request)
+ def create_next_builds(build)
return unless config_processor
- stages = builds.where(ref: ref, tag: tag, trigger_request: trigger_request).group_by(&:stage)
+ # don't create other builds if this one is retried
+ latest_builds = builds.similar(build).latest
+ return unless latest_builds.exists?(build.id)
- config_processor.stages.any? do |stage|
- unless stages.include?(stage)
- CreateBuildsService.new.execute(self, stage, ref, tag, user, trigger_request).present?
- end
+ # get list of stages after this build
+ next_stages = config_processor.stages.drop_while { |stage| stage != build.stage }
+ next_stages.delete(build.stage)
+
+ # get status for all prior builds
+ prior_builds = latest_builds.reject { |other_build| next_stages.include?(other_build.stage) }
+ status = Ci::Status.get_status(prior_builds)
+
+ # create builds for next stages based
+ next_stages.any? do |stage|
+ CreateBuildsService.new.execute(self, stage, build.ref, build.tag, build.user, build.trigger_request, status).present?
end
end
@@ -130,24 +141,7 @@ module Ci
return 'failed'
end
- @status ||= begin
- latest = latest_statuses
- latest.reject! { |status| status.try(&:allow_failure?) }
-
- if latest.none?
- 'skipped'
- elsif latest.all?(&:success?)
- 'success'
- elsif latest.all?(&:pending?)
- 'pending'
- elsif latest.any?(&:running?) || latest.any?(&:pending?)
- 'running'
- elsif latest.all?(&:canceled?)
- 'canceled'
- else
- 'failed'
- end
- end
+ @status ||= Ci::Status.get_status(latest_statuses)
end
def pending?
@@ -193,7 +187,7 @@ module Ci
end
def config_processor
- @config_processor ||= Ci::GitlabCiYamlProcessor.new(ci_yaml_file)
+ @config_processor ||= Ci::GitlabCiYamlProcessor.new(ci_yaml_file, gl_project.path_with_namespace)
rescue Ci::GitlabCiYamlProcessor::ValidationError => e
save_yaml_error(e.message)
nil
@@ -217,16 +211,6 @@ module Ci
update!(committed_at: DateTime.now)
end
- def should_create_next_builds?(build)
- # don't create other builds if this one is retried
- other_builds = builds.similar(build).latest
- return false unless other_builds.include?(build)
-
- other_builds.all? do |build|
- build.success? || build.ignored?
- end
- end
-
private
def save_yaml_error(error)
diff --git a/app/models/ci/project.rb b/app/models/ci/project.rb
index 88ba933a434..4e806ca1a68 100644
--- a/app/models/ci/project.rb
+++ b/app/models/ci/project.rb
@@ -99,6 +99,7 @@ module Ci
def ordered_by_last_commit_date
last_commit_subquery = "(SELECT gl_project_id, MAX(committed_at) committed_at FROM #{Ci::Commit.table_name} GROUP BY gl_project_id)"
joins("LEFT JOIN #{last_commit_subquery} AS last_commit ON #{Ci::Project.table_name}.gitlab_id = last_commit.gl_project_id").
+ joins(:gl_project).
order("CASE WHEN last_commit.committed_at IS NULL THEN 1 ELSE 0 END, last_commit.committed_at DESC")
end
end
@@ -115,12 +116,12 @@ module Ci
web_url
end
- def any_runners?
- if runners.active.any?
+ def any_runners?(&block)
+ if runners.active.any?(&block)
return true
end
- shared_runners_enabled && Ci::Runner.shared.active.any?
+ shared_runners_enabled && Ci::Runner.shared.active.any?(&block)
end
def set_default_values
@@ -205,7 +206,7 @@ module Ci
end
def commits
- gl_project.ci_commits
+ gl_project.ci_commits.ordered
end
def builds
diff --git a/app/models/ci/project_status.rb b/app/models/ci/project_status.rb
index b66f1212f23..2d35aeac225 100644
--- a/app/models/ci/project_status.rb
+++ b/app/models/ci/project_status.rb
@@ -27,9 +27,5 @@ module Ci
def human_status
status
end
-
- def last_commit_for_ref(ref)
- commits.where(ref: ref).last
- end
end
end
diff --git a/app/models/ci/runner.rb b/app/models/ci/runner.rb
index 6838ccfaaab..b719ad3c87e 100644
--- a/app/models/ci/runner.rb
+++ b/app/models/ci/runner.rb
@@ -20,6 +20,8 @@
module Ci
class Runner < ActiveRecord::Base
extend Ci::Model
+
+ LAST_CONTACT_TIME = 5.minutes.ago
has_many :builds, class_name: 'Ci::Build'
has_many :runner_projects, dependent: :destroy, class_name: 'Ci::RunnerProject'
@@ -33,6 +35,8 @@ module Ci
scope :shared, ->() { where(is_shared: true) }
scope :active, ->() { where(active: true) }
scope :paused, ->() { where(active: false) }
+ scope :online, ->() { where('contacted_at > ?', LAST_CONTACT_TIME) }
+ scope :ordered, ->() { order(id: :desc) }
acts_as_taggable
@@ -56,7 +60,7 @@ module Ci
end
def display_name
- return token unless !description.blank?
+ return short_sha unless !description.blank?
description
end
@@ -65,6 +69,20 @@ module Ci
is_shared
end
+ def online?
+ contacted_at && contacted_at > LAST_CONTACT_TIME
+ end
+
+ def status
+ if contacted_at.nil?
+ :not_connected
+ elsif active?
+ online? ? :online : :offline
+ else
+ :paused
+ end
+ end
+
def belongs_to_one_project?
runner_projects.count == 1
end
@@ -78,7 +96,7 @@ module Ci
end
def short_sha
- token[0...10]
+ token[0...8] if token
end
end
end
diff --git a/app/models/commit.rb b/app/models/commit.rb
index d5c50013525..492f6be1ce3 100644
--- a/app/models/commit.rb
+++ b/app/models/commit.rb
@@ -2,13 +2,13 @@ class Commit
extend ActiveModel::Naming
include ActiveModel::Conversion
- include Mentionable
include Participable
+ include Mentionable
include Referable
include StaticModel
attr_mentionable :safe_message
- participant :author, :committer, :notes, :mentioned_users
+ participant :author, :committer, :notes
attr_accessor :project
@@ -164,6 +164,14 @@ class Commit
@committer ||= User.find_by_any_email(committer_email)
end
+ def parents
+ @parents ||= parent_ids.map { |id| project.commit(id) }
+ end
+
+ def parent
+ @parent ||= project.commit(self.parent_id) if self.parent_id
+ end
+
def notes
project.notes.for_commit_id(self.id)
end
@@ -181,10 +189,6 @@ class Commit
@raw.short_id(7)
end
- def parents
- @parents ||= Commit.decorate(super, project)
- end
-
def ci_commit
project.ci_commit(sha)
end
diff --git a/app/models/commit_status.rb b/app/models/commit_status.rb
index b4d91b1b0c3..0b73ab6d2eb 100644
--- a/app/models/commit_status.rb
+++ b/app/models/commit_status.rb
@@ -16,10 +16,10 @@ class CommitStatus < ActiveRecord::Base
scope :success, -> { where(status: 'success') }
scope :failed, -> { where(status: 'failed') }
scope :running_or_pending, -> { where(status:[:running, :pending]) }
+ scope :finished, -> { where(status:[:success, :failed, :canceled]) }
scope :latest, -> { where(id: unscope(:select).select('max(id)').group(:name, :ref)) }
scope :ordered, -> { order(:ref, :stage_idx, :name) }
scope :for_ref, ->(ref) { where(ref: ref) }
- scope :running_or_pending, -> { where(status: [:running, :pending]) }
state_machine :status, initial: :pending do
event :run do
@@ -27,7 +27,7 @@ class CommitStatus < ActiveRecord::Base
end
event :drop do
- transition running: :failed
+ transition [:pending, :running] => :failed
end
event :success do
@@ -88,4 +88,8 @@ class CommitStatus < ActiveRecord::Base
def retry_url
nil
end
+
+ def show_warning?
+ false
+ end
end
diff --git a/app/models/concerns/issuable.rb b/app/models/concerns/issuable.rb
index 4db4ffb2e79..5e964f04ef5 100644
--- a/app/models/concerns/issuable.rb
+++ b/app/models/concerns/issuable.rb
@@ -6,8 +6,8 @@
#
module Issuable
extend ActiveSupport::Concern
- include Mentionable
include Participable
+ include Mentionable
included do
belongs_to :author, class_name: "User"
@@ -47,7 +47,7 @@ module Issuable
prefix: true
attr_mentionable :title, :description
- participant :author, :assignee, :notes, :mentioned_users
+ participant :author, :assignee, :notes_with_associations
end
module ClassMethods
@@ -85,6 +85,10 @@ module Issuable
assignee_id_changed?
end
+ def open?
+ opened? || reopened?
+ end
+
#
# Votes
#
@@ -176,6 +180,10 @@ module Issuable
self.class.to_s.underscore
end
+ def notes_with_associations
+ notes.includes(:author, :project)
+ end
+
private
def filter_superceded_votes(votes, notes)
diff --git a/app/models/concerns/mentionable.rb b/app/models/concerns/mentionable.rb
index 5b0ae411642..193c91f1742 100644
--- a/app/models/concerns/mentionable.rb
+++ b/app/models/concerns/mentionable.rb
@@ -20,6 +20,12 @@ module Mentionable
end
end
+ included do
+ if self < Participable
+ participant ->(current_user) { mentioned_users(current_user, load_lazy_references: false) }
+ end
+ end
+
# Returns the text used as the body of a Note when this object is referenced
#
# By default this will be the class name and the result of calling
@@ -41,55 +47,49 @@ module Mentionable
self
end
- # Determine whether or not a cross-reference Note has already been created between this Mentionable and
- # the specified target.
- def has_mentioned?(target)
- SystemNoteService.cross_reference_exists?(target, local_reference)
+ def all_references(current_user = self.author, text = self.mentionable_text, load_lazy_references: true)
+ ext = Gitlab::ReferenceExtractor.new(self.project, current_user, load_lazy_references: load_lazy_references)
+ ext.analyze(text)
+ ext
end
- def mentioned_users(current_user = nil)
- return [] if mentionable_text.blank?
-
- ext = Gitlab::ReferenceExtractor.new(self.project, current_user)
- ext.analyze(mentionable_text)
- ext.users.uniq
+ def mentioned_users(current_user = nil, load_lazy_references: true)
+ all_references(current_user, load_lazy_references: load_lazy_references).users
end
# Extract GFM references to other Mentionables from this Mentionable. Always excludes its #local_reference.
- def references(p = project, current_user = self.author, text = mentionable_text)
+ def referenced_mentionables(current_user = self.author, text = self.mentionable_text, load_lazy_references: true)
return [] if text.blank?
- ext = Gitlab::ReferenceExtractor.new(p, current_user)
- ext.analyze(text)
-
- (ext.issues + ext.merge_requests + ext.commits).uniq - [local_reference]
+ refs = all_references(current_user, text, load_lazy_references: load_lazy_references)
+ (refs.issues + refs.merge_requests + refs.commits) - [local_reference]
end
# Create a cross-reference Note for each GFM reference to another Mentionable found in +mentionable_text+.
- def create_cross_references!(p = project, a = author, without = [])
- refs = references(p)
-
+ def create_cross_references!(author = self.author, without = [], text = self.mentionable_text)
+ refs = referenced_mentionables(author, text)
+
# We're using this method instead of Array diffing because that requires
# both of the object's `hash` values to be the same, which may not be the
# case for otherwise identical Commit objects.
- refs.reject! { |ref| without.include?(ref) }
+ refs.reject! { |ref| without.include?(ref) || cross_reference_exists?(ref) }
refs.each do |ref|
- SystemNoteService.cross_reference(ref, local_reference, a)
+ SystemNoteService.cross_reference(ref, local_reference, author)
end
end
# When a mentionable field is changed, creates cross-reference notes that
# don't already exist
- def create_new_cross_references!(p = project, a = author)
+ def create_new_cross_references!(author = self.author)
changes = detect_mentionable_changes
return if changes.empty?
original_text = changes.collect { |_, vals| vals.first }.join(' ')
- preexisting = references(p, self.author, original_text)
- create_cross_references!(p, a, preexisting)
+ preexisting = referenced_mentionables(author, original_text)
+ create_cross_references!(author, preexisting)
end
private
@@ -111,4 +111,10 @@ module Mentionable
# Only include changed fields that are mentionable
source.select { |key, val| mentionable.include?(key) }
end
+
+ # Determine whether or not a cross-reference Note has already been created between this Mentionable and
+ # the specified target.
+ def cross_reference_exists?(target)
+ SystemNoteService.cross_reference_exists?(target, local_reference)
+ end
end
diff --git a/app/models/concerns/participable.rb b/app/models/concerns/participable.rb
index 7c9597333dd..85367f89f4f 100644
--- a/app/models/concerns/participable.rb
+++ b/app/models/concerns/participable.rb
@@ -12,7 +12,7 @@
#
# # ...
#
-# participant :author, :assignee, :mentioned_users, :notes
+# participant :author, :assignee, :notes, ->(current_user) { mentioned_users(current_user) }
# end
#
# issue = Issue.last
@@ -27,7 +27,7 @@ module Participable
module ClassMethods
def participant(*attrs)
- participant_attrs.concat(attrs.map(&:to_s))
+ participant_attrs.concat(attrs)
end
def participant_attrs
@@ -37,21 +37,21 @@ module Participable
# Be aware that this method makes a lot of sql queries.
# Save result into variable if you are going to reuse it inside same request
- def participants(current_user = self.author, project = self.project)
+ def participants(current_user = self.author, load_lazy_references: true)
participants = self.class.participant_attrs.flat_map do |attr|
- meth = method(attr)
-
value =
- if meth.arity == 1 || meth.arity == -1
- meth.call(current_user)
+ if attr.respond_to?(:call)
+ instance_exec(current_user, &attr)
else
- meth.call
+ send(attr)
end
- participants_for(value, current_user, project)
+ participants_for(value, current_user)
end.compact.uniq
- if project
+ if load_lazy_references
+ participants = Gitlab::Markdown::ReferenceFilter::LazyReference.load(participants).uniq
+
participants.select! do |user|
user.can?(:read_project, project)
end
@@ -62,14 +62,14 @@ module Participable
private
- def participants_for(value, current_user = nil, project = nil)
+ def participants_for(value, current_user = nil)
case value
- when User
+ when User, Gitlab::Markdown::ReferenceFilter::LazyReference
[value]
when Enumerable, ActiveRecord::Relation
- value.flat_map { |v| participants_for(v, current_user, project) }
+ value.flat_map { |v| participants_for(v, current_user) }
when Participable
- value.participants(current_user, project)
+ value.participants(current_user, load_lazy_references: false)
end
end
end
diff --git a/app/models/group.rb b/app/models/group.rb
index 9cd146bb73b..465c22d23ac 100644
--- a/app/models/group.rb
+++ b/app/models/group.rb
@@ -64,7 +64,7 @@ class Group < Namespace
end
def owners
- @owners ||= group_members.owners.map(&:user)
+ @owners ||= group_members.owners.includes(:user).map(&:user)
end
def add_users(user_ids, access_level, current_user = nil)
diff --git a/app/models/group_label.rb b/app/models/group_label.rb
new file mode 100644
index 00000000000..0fc39cb8771
--- /dev/null
+++ b/app/models/group_label.rb
@@ -0,0 +1,9 @@
+class GroupLabel
+ attr_accessor :title, :labels
+ alias_attribute :name, :title
+
+ def initialize(title, labels)
+ @title = title
+ @labels = labels
+ end
+end
diff --git a/app/models/group_milestone.rb b/app/models/group_milestone.rb
index 1dd2be68ebf..91844da62e2 100644
--- a/app/models/group_milestone.rb
+++ b/app/models/group_milestone.rb
@@ -1,5 +1,5 @@
class GroupMilestone
-
+ attr_accessor :title, :milestones
alias_attribute :name, :title
def initialize(title, milestones)
@@ -7,18 +7,10 @@ class GroupMilestone
@milestones = milestones
end
- def title
- @title
- end
-
def safe_title
@title.parameterize
end
-
- def milestones
- @milestones
- end
-
+
def projects
milestones.map { |milestone| milestone.project }
end
diff --git a/app/models/issue.rb b/app/models/issue.rb
index fc7e9abe29e..72183108033 100644
--- a/app/models/issue.rb
+++ b/app/models/issue.rb
@@ -95,4 +95,14 @@ class Issue < ActiveRecord::Base
def source_project
project
end
+
+ # From all notes on this issue, we'll select the system notes about linked
+ # merge requests. Of those, the MRs closing `self` are returned.
+ def closed_by_merge_requests(current_user = nil)
+ return [] unless open?
+
+ notes.system.flat_map do |note|
+ note.all_references(current_user).merge_requests
+ end.uniq.select { |mr| mr.open? && mr.closes_issue?(self) }
+ end
end
diff --git a/app/models/merge_request.rb b/app/models/merge_request.rb
index c83b15c7d39..85f37e49e62 100644
--- a/app/models/merge_request.rb
+++ b/app/models/merge_request.rb
@@ -40,7 +40,7 @@ class MergeRequest < ActiveRecord::Base
after_create :create_merge_request_diff
after_update :update_merge_request_diff
- delegate :commits, :diffs, :last_commit, :last_commit_short_sha, to: :merge_request_diff, prefix: nil
+ delegate :commits, :diffs, to: :merge_request_diff, prefix: nil
# When this attribute is true some MR validation is ignored
# It allows us to close or modify broken merge requests
@@ -157,6 +157,18 @@ class MergeRequest < ActiveRecord::Base
reference
end
+ def last_commit
+ merge_request_diff ? merge_request_diff.last_commit : compare_commits.last
+ end
+
+ def first_commit
+ merge_request_diff ? merge_request_diff.first_commit : compare_commits.first
+ end
+
+ def last_commit_short_sha
+ last_commit.short_id
+ end
+
def validate_branches
if target_project == source_project && target_branch == source_branch
errors.add :branch_conflict, "You can not use same project/branch for source and target"
@@ -222,10 +234,6 @@ class MergeRequest < ActiveRecord::Base
self.target_project.events.where(target_id: self.id, target_type: "MergeRequest", action: Event::CLOSED).last
end
- def open?
- opened? || reopened?
- end
-
def work_in_progress?
!!(title =~ /\A\[?WIP\]?:? /i)
end
@@ -249,7 +257,7 @@ class MergeRequest < ActiveRecord::Base
Note.where(
"(project_id = :target_project_id AND noteable_type = 'MergeRequest' AND noteable_id = :mr_id) OR" +
- "(project_id = :source_project_id AND noteable_type = 'Commit' AND commit_id IN (:commit_ids))",
+ "((project_id = :source_project_id OR project_id = :target_project_id) AND noteable_type = 'Commit' AND commit_id IN (:commit_ids))",
mr_id: id,
commit_ids: commit_ids,
target_project_id: target_project_id,
@@ -294,6 +302,10 @@ class MergeRequest < ActiveRecord::Base
target_project
end
+ def closes_issue?(issue)
+ closes_issues.include?(issue)
+ end
+
# Return the set of issues that will be closed if this merge request is accepted.
def closes_issues(current_user = self.author)
if target_branch == project.default_branch
@@ -458,4 +470,10 @@ class MergeRequest < ActiveRecord::Base
unlock_mr if locked?
end
end
+
+ def ci_commit
+ if last_commit
+ source_project.ci_commit(last_commit.id)
+ end
+ end
end
diff --git a/app/models/merge_request_diff.rb b/app/models/merge_request_diff.rb
index c9ef8023aea..6575d0bc81f 100644
--- a/app/models/merge_request_diff.rb
+++ b/app/models/merge_request_diff.rb
@@ -55,6 +55,10 @@ class MergeRequestDiff < ActiveRecord::Base
commits.first
end
+ def first_commit
+ commits.last
+ end
+
def last_commit_short_sha
@last_commit_short_sha ||= last_commit.short_id
end
@@ -163,7 +167,8 @@ class MergeRequestDiff < ActiveRecord::Base
merge_request.fetch_ref
# Get latest sha of branch from source project
- source_sha = merge_request.source_project.commit(source_branch).sha
+ source_commit = merge_request.source_project.commit(source_branch)
+ source_sha = source_commit.try(:sha)
Gitlab::CompareResult.new(
Gitlab::Git::Compare.new(
diff --git a/app/models/milestone.rb b/app/models/milestone.rb
index 84acba30b6b..2ff16e2825c 100644
--- a/app/models/milestone.rb
+++ b/app/models/milestone.rb
@@ -105,4 +105,36 @@ class Milestone < ActiveRecord::Base
def author_id
nil
end
+
+ # Sorts the issues for the given IDs.
+ #
+ # This method runs a single SQL query using a CASE statement to update the
+ # position of all issues in the current milestone (scoped to the list of IDs).
+ #
+ # Given the ids [10, 20, 30] this method produces a SQL query something like
+ # the following:
+ #
+ # UPDATE issues
+ # SET position = CASE
+ # WHEN id = 10 THEN 1
+ # WHEN id = 20 THEN 2
+ # WHEN id = 30 THEN 3
+ # ELSE position
+ # END
+ # WHERE id IN (10, 20, 30);
+ #
+ # This method expects that the IDs given in `ids` are already Fixnums.
+ def sort_issues(ids)
+ pairs = []
+
+ ids.each_with_index do |id, index|
+ pairs << id
+ pairs << index + 1
+ end
+
+ conditions = 'WHEN id = ? THEN ? ' * ids.length
+
+ issues.where(id: ids).
+ update_all(["position = CASE #{conditions} ELSE position END", *pairs])
+ end
end
diff --git a/app/models/namespace.rb b/app/models/namespace.rb
index bc8525df5a5..5782e649f8b 100644
--- a/app/models/namespace.rb
+++ b/app/models/namespace.rb
@@ -118,6 +118,8 @@ class Namespace < ActiveRecord::Base
gitlab_shell.add_namespace(path_was)
if gitlab_shell.mv_namespace(path_was, path)
+ Gitlab::UploadsTransfer.new.rename_namespace(path_was, path)
+
# If repositories moved successfully we need to
# send update instructions to users.
# However we cannot allow rollback since we moved namespace dir
diff --git a/app/models/note.rb b/app/models/note.rb
index de3b6df88f7..0b3aa30abd7 100644
--- a/app/models/note.rb
+++ b/app/models/note.rb
@@ -22,14 +22,14 @@ require 'carrierwave/orm/activerecord'
require 'file_size_validator'
class Note < ActiveRecord::Base
- include Mentionable
include Gitlab::CurrentSettings
include Participable
+ include Mentionable
default_value_for :system, false
attr_mentionable :note
- participant :author, :mentioned_users
+ participant :author
belongs_to :project
belongs_to :noteable, polymorphic: true
@@ -60,9 +60,13 @@ class Note < ActiveRecord::Base
scope :inc_author_project, ->{ includes(:project, :author) }
scope :inc_author, ->{ includes(:author) }
+ scope :with_associations, -> do
+ includes(:author, :noteable, :updated_by,
+ project: [:project_members, { group: [:group_members] }])
+ end
+
serialize :st_diff
before_create :set_diff, if: ->(n) { n.line_code.present? }
- after_update :set_references
class << self
def discussions_from_notes(notes)
@@ -333,15 +337,13 @@ class Note < ActiveRecord::Base
end
def noteable_type_name
- if noteable_type.present?
- noteable_type.downcase
- end
+ noteable_type.downcase if noteable_type.present?
end
# FIXME: Hack for polymorphic associations with STI
# For more information visit http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html#label-Polymorphic+Associations
- def noteable_type=(sType)
- super(sType.to_s.classify.constantize.base_class.to_s)
+ def noteable_type=(noteable_type)
+ super(noteable_type.to_s.classify.constantize.base_class.to_s)
end
# Reset notes events cache
@@ -357,10 +359,6 @@ class Note < ActiveRecord::Base
Event.reset_event_cache_for(self)
end
- def set_references
- create_new_cross_references!(project, author)
- end
-
def system?
read_attribute(:system)
end
diff --git a/app/models/project.rb b/app/models/project.rb
index 021920008ad..74b89aad499 100644
--- a/app/models/project.rb
+++ b/app/models/project.rb
@@ -119,7 +119,7 @@ class Project < ActiveRecord::Base
has_many :deploy_keys, through: :deploy_keys_projects
has_many :users_star_projects, dependent: :destroy
has_many :starrers, through: :users_star_projects, source: :user
- has_many :ci_commits, ->() { order('CASE WHEN ci_commits.committed_at IS NULL THEN 0 ELSE 1 END', :committed_at, :id) }, dependent: :destroy, class_name: 'Ci::Commit', foreign_key: :gl_project_id
+ has_many :ci_commits, dependent: :destroy, class_name: 'Ci::Commit', foreign_key: :gl_project_id
has_many :ci_builds, through: :ci_commits, source: :builds, dependent: :destroy, class_name: 'Ci::Build'
has_one :import_data, dependent: :destroy, class_name: "ProjectImportData"
@@ -243,11 +243,12 @@ class Project < ActiveRecord::Base
# Use of unscoped ensures we're not secretly adding any ORDER BYs, which
# have a negative impact on performance (and aren't needed for this
# query).
- unscoped.
+ projects = unscoped.
joins(:namespace).
- iwhere('namespaces.path' => namespace_path).
- iwhere('projects.path' => project_path).
- take
+ iwhere('namespaces.path' => namespace_path)
+
+ projects.where('projects.path' => project_path).take ||
+ projects.iwhere('projects.path' => project_path).take
end
def visibility_levels
@@ -567,7 +568,7 @@ class Project < ActiveRecord::Base
end
def empty_repo?
- !repository.exists? || repository.empty?
+ !repository.exists? || !repository.has_visible_content?
end
def repo
@@ -656,6 +657,8 @@ class Project < ActiveRecord::Base
# db changes in order to prevent out of sync between db and fs
raise Exception.new('repository cannot be renamed')
end
+
+ Gitlab::UploadsTransfer.new.rename_project(path_was, path, namespace.path)
end
def hook_attrs
diff --git a/app/models/project_services/bamboo_service.rb b/app/models/project_services/bamboo_service.rb
index 5f5255ab487..d31b12f539e 100644
--- a/app/models/project_services/bamboo_service.rb
+++ b/app/models/project_services/bamboo_service.rb
@@ -48,7 +48,7 @@ class BambooService < CiService
end
def reset_password
- if prop_updated?(:bamboo_url)
+ if bamboo_url_changed? && !password_touched?
self.password = nil
end
end
diff --git a/app/models/project_services/teamcity_service.rb b/app/models/project_services/teamcity_service.rb
index fb11cad352e..0b022461250 100644
--- a/app/models/project_services/teamcity_service.rb
+++ b/app/models/project_services/teamcity_service.rb
@@ -45,7 +45,7 @@ class TeamcityService < CiService
end
def reset_password
- if prop_updated?(:teamcity_url)
+ if teamcity_url_changed? && !password_touched?
self.password = nil
end
end
diff --git a/app/models/project_team.rb b/app/models/project_team.rb
index f602a965364..9f380a382cb 100644
--- a/app/models/project_team.rb
+++ b/app/models/project_team.rb
@@ -139,15 +139,28 @@ class ProjectTeam
Gitlab::Access.options.key max_member_access(user_id)
end
+ # This method assumes project and group members are eager loaded for optimal
+ # performance.
def max_member_access(user_id)
access = []
- access << project.project_members.find_by(user_id: user_id).try(:access_field)
+
+ project.project_members.each do |member|
+ if member.user_id == user_id
+ access << member.access_field if member.access_field
+ break
+ end
+ end
if group
- access << group.group_members.find_by(user_id: user_id).try(:access_field)
+ group.group_members.each do |member|
+ if member.user_id == user_id
+ access << member.access_field if member.access_field
+ break
+ end
+ end
end
- access.compact.max
+ access.max
end
private
diff --git a/app/models/repository.rb b/app/models/repository.rb
index 8b51602bc23..9266ba27f0a 100644
--- a/app/models/repository.rb
+++ b/app/models/repository.rb
@@ -8,6 +8,14 @@ class Repository
attr_accessor :raw_repository, :path_with_namespace, :project
+ def self.clean_old_archives
+ repository_downloads_path = Gitlab.config.gitlab.repository_downloads_path
+
+ return unless File.directory?(repository_downloads_path)
+
+ Gitlab::Popen.popen(%W(find #{repository_downloads_path} -not -path #{repository_downloads_path} -mmin +120 -delete))
+ end
+
def initialize(path_with_namespace, default_branch = nil, project = nil)
@path_with_namespace = path_with_namespace
@project = project
@@ -36,6 +44,19 @@ class Repository
raw_repository.empty?
end
+ #
+ # Git repository can contains some hidden refs like:
+ # /refs/notes/*
+ # /refs/git-as-svn/*
+ # /refs/pulls/*
+ # This refs by default not visible in project page and not cloned to client side.
+ #
+ # This method return true if repository contains some content visible in project page.
+ #
+ def has_visible_content?
+ !raw_repository.branches.empty?
+ end
+
def commit(id = 'HEAD')
return nil unless raw_repository
commit = Gitlab::Git::Commit.find(raw_repository, id)
@@ -46,13 +67,16 @@ class Repository
end
def commits(ref, path = nil, limit = nil, offset = nil, skip_merges = false)
- commits = Gitlab::Git::Commit.where(
+ options = {
repo: raw_repository,
ref: ref,
path: path,
limit: limit,
offset: offset,
- )
+ follow: path.present?
+ }
+
+ commits = Gitlab::Git::Commit.where(options)
commits = Commit.decorate(commits, @project) if commits.present?
commits
end
@@ -63,6 +87,15 @@ class Repository
commits
end
+ def find_commits_by_message(query)
+ # Limited to 1000 commits for now, could be parameterized?
+ args = %W(git log --pretty=%H --max-count 1000 --grep=#{query})
+
+ git_log_results = Gitlab::Popen.popen(args, path_to_repo).first.lines.map(&:chomp)
+ commits = git_log_results.map { |c| commit(c) }
+ commits
+ end
+
def find_branch(name)
branches.find { |branch| branch.name == name }
end
@@ -269,14 +302,6 @@ class Repository
end
# Remove archives older than 2 hours
- def clean_old_archives
- repository_downloads_path = Gitlab.config.gitlab.repository_downloads_path
-
- return unless File.directory?(repository_downloads_path)
-
- Gitlab::Popen.popen(%W(find #{repository_downloads_path} -not -path #{repository_downloads_path} -mmin +120 -delete))
- end
-
def branches_sorted_by(value)
case value
when 'recently_updated'
@@ -312,13 +337,7 @@ class Repository
end
def blob_for_diff(commit, diff)
- file = blob_at(commit.id, diff.new_path)
-
- unless file
- file = prev_blob_for_diff(commit, diff)
- end
-
- file
+ blob_at(commit.id, diff.file_path)
end
def prev_blob_for_diff(commit, diff)
@@ -480,9 +499,13 @@ class Repository
end
end
+ def merge_base(first_commit_id, second_commit_id)
+ rugged.merge_base(first_commit_id, second_commit_id)
+ end
+
def search_files(query, ref)
offset = 2
- args = %W(git grep -i -n --before-context #{offset} --after-context #{offset} #{query} #{ref || root_ref})
+ args = %W(git grep -i -n --before-context #{offset} --after-context #{offset} -e #{query} #{ref || root_ref})
Gitlab::Popen.popen(args, path_to_repo).first.scrub.split(/^--$/)
end
@@ -514,7 +537,7 @@ class Repository
end
def fetch_ref(source_path, source_ref, target_ref)
- args = %W(git fetch #{source_path} #{source_ref}:#{target_ref})
+ args = %W(git fetch -f #{source_path} #{source_ref}:#{target_ref})
Gitlab::Popen.popen(args, path_to_repo)
end
diff --git a/app/models/service.rb b/app/models/service.rb
index 7e845d565b1..d610abd1683 100644
--- a/app/models/service.rb
+++ b/app/models/service.rb
@@ -33,6 +33,8 @@ class Service < ActiveRecord::Base
after_initialize :initialize_properties
+ after_commit :reset_updated_properties
+
belongs_to :project
has_one :service_hook
@@ -103,6 +105,7 @@ class Service < ActiveRecord::Base
# Provide convenient accessor methods
# for each serialized property.
+ # Also keep track of updated properties in a similar way as ActiveModel::Dirty
def self.prop_accessor(*args)
args.each do |arg|
class_eval %{
@@ -111,21 +114,39 @@ class Service < ActiveRecord::Base
end
def #{arg}=(value)
+ updated_properties['#{arg}'] = #{arg} unless #{arg}_changed?
self.properties['#{arg}'] = value
end
+
+ def #{arg}_changed?
+ #{arg}_touched? && #{arg} != #{arg}_was
+ end
+
+ def #{arg}_touched?
+ updated_properties.include?('#{arg}')
+ end
+
+ def #{arg}_was
+ updated_properties['#{arg}']
+ end
}
end
end
- # ActiveRecord does not provide a mechanism to track changes in serialized keys.
- # This is why we need to perform extra query to do it mannually.
- def prop_updated?(prop_name)
- relation_name = self.type.underscore
- previous_value = project.send(relation_name).send(prop_name)
- return false if previous_value.nil?
- previous_value != send(prop_name)
+ # Returns a hash of the properties that have been assigned a new value since last save,
+ # indicating their original values (attr => original value).
+ # ActiveRecord does not provide a mechanism to track changes in serialized keys,
+ # so we need a specific implementation for service properties.
+ # This allows to track changes to properties set with the accessor methods,
+ # but not direct manipulation of properties hash.
+ def updated_properties
+ @updated_properties ||= ActiveSupport::HashWithIndifferentAccess.new
end
+ def reset_updated_properties
+ @updated_properties = nil
+ end
+
def async_execute(data)
return unless supported_events.include?(data[:object_kind])
diff --git a/app/models/user.rb b/app/models/user.rb
index 889d2d3b867..67fef1c1e6a 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -68,6 +68,7 @@ class User < ActiveRecord::Base
include Referable
include Sortable
include TokenAuthenticatable
+ include CaseSensitivity
default_value_for :admin, false
default_value_for :can_create_group, gitlab_config.default_can_create_group
@@ -182,7 +183,7 @@ class User < ActiveRecord::Base
# User's Project preference
# Note: When adding an option, it MUST go on the end of the array.
- enum project_view: [:readme, :activity]
+ enum project_view: [:readme, :activity, :files]
alias_attribute :private_token, :authentication_token
@@ -234,21 +235,16 @@ class User < ActiveRecord::Base
# Find a User by their primary email or any associated secondary email
def find_by_any_email(email)
- user_table = arel_table
- email_table = Email.arel_table
-
- # Use ARel to build a query:
- query = user_table.
- # SELECT "users".* FROM "users"
- project(user_table[Arel.star]).
- # LEFT OUTER JOIN "emails"
- join(email_table, Arel::Nodes::OuterJoin).
- # ON "users"."id" = "emails"."user_id"
- on(user_table[:id].eq(email_table[:user_id])).
- # WHERE ("user"."email" = '<email>' OR "emails"."email" = '<email>')
- where(user_table[:email].eq(email).or(email_table[:email].eq(email)))
-
- find_by_sql(query.to_sql).first
+ sql = 'SELECT *
+ FROM users
+ WHERE id IN (
+ SELECT id FROM users WHERE email = :email
+ UNION
+ SELECT emails.user_id FROM emails WHERE email = :email
+ )
+ LIMIT 1;'
+
+ User.find_by_sql([sql, { email: email }]).first
end
def filter(filter_name)
@@ -273,8 +269,13 @@ class User < ActiveRecord::Base
end
def by_login(login)
- where('lower(username) = :value OR lower(email) = :value',
- value: login.to_s.downcase).first
+ return nil unless login
+
+ if login.include?('@'.freeze)
+ unscoped.iwhere(email: login).take
+ else
+ unscoped.iwhere(username: login).take
+ end
end
def find_by_username!(username)
@@ -395,15 +396,17 @@ class User < ActiveRecord::Base
end
end
+ def authorized_projects_id
+ @authorized_projects_id ||= begin
+ project_ids = personal_projects.pluck(:id)
+ project_ids.push(*groups_projects.pluck(:id))
+ project_ids.push(*projects.pluck(:id).uniq)
+ end
+ end
# Projects user has access to
def authorized_projects
- @authorized_projects ||= begin
- project_ids = personal_projects.pluck(:id)
- project_ids.push(*groups_projects.pluck(:id))
- project_ids.push(*projects.pluck(:id).uniq)
- Project.where(id: project_ids)
- end
+ @authorized_projects ||= Project.where(id: authorized_projects_id)
end
def owned_projects
@@ -700,12 +703,15 @@ class User < ActiveRecord::Base
end
def toggle_star(project)
- user_star_project = users_star_projects.
- where(project: project, user: self).take
- if user_star_project
- user_star_project.destroy
- else
- UsersStarProject.create!(project: project, user: self)
+ UsersStarProject.transaction do
+ user_star_project = users_star_projects.
+ where(project: project, user: self).lock(true).first
+
+ if user_star_project
+ user_star_project.destroy
+ else
+ UsersStarProject.create!(project: project, user: self)
+ end
end
end
@@ -759,11 +765,14 @@ class User < ActiveRecord::Base
end
def ci_authorized_projects
- @ci_authorized_projects ||= Ci::Project.where(gitlab_id: authorized_projects)
+ @ci_authorized_projects ||= Ci::Project.where(gitlab_id: authorized_projects_id)
end
def ci_authorized_runners
- Ci::Runner.specific.includes(:runner_projects).
- where(ci_runner_projects: { project_id: ci_authorized_projects } )
+ @ci_authorized_runners ||= begin
+ runner_ids = Ci::RunnerProject.joins(:project).
+ where(ci_projects: { gitlab_id: authorized_projects_id }).select(:runner_id)
+ Ci::Runner.specific.where(id: runner_ids)
+ end
end
end
diff --git a/app/services/archive_repository_service.rb b/app/services/archive_repository_service.rb
index e1b41527d8d..2160bf13e6d 100644
--- a/app/services/archive_repository_service.rb
+++ b/app/services/archive_repository_service.rb
@@ -7,19 +7,12 @@ class ArchiveRepositoryService
end
def execute(options = {})
- project.repository.clean_old_archives
+ RepositoryArchiveCacheWorker.perform_async
- raise "No archive file path" unless file_path
+ metadata = project.repository.archive_metadata(ref, storage_path, format)
+ raise "Repository or ref not found" if metadata.empty?
- return file_path if archived?
-
- unless archiving?
- RepositoryArchiveWorker.perform_async(project.id, ref, format)
- end
-
- archived = wait_until_archived(options[:timeout] || 5.0)
-
- file_path if archived
+ metadata
end
private
@@ -27,36 +20,4 @@ class ArchiveRepositoryService
def storage_path
Gitlab.config.gitlab.repository_downloads_path
end
-
- def file_path
- @file_path ||= project.repository.archive_file_path(ref, storage_path, format)
- end
-
- def pid_file_path
- @pid_file_path ||= project.repository.archive_pid_file_path(ref, storage_path, format)
- end
-
- def archived?
- File.exist?(file_path)
- end
-
- def archiving?
- File.exist?(pid_file_path)
- end
-
- def wait_until_archived(timeout = 5.0)
- return archived? if timeout == 0.0
-
- t1 = Time.now
-
- begin
- sleep 0.1
-
- success = archived?
-
- t2 = Time.now
- end until success || t2 - t1 >= timeout
-
- success
- end
end
diff --git a/app/services/ci/create_builds_service.rb b/app/services/ci/create_builds_service.rb
index c420f3268fd..912eb6258a4 100644
--- a/app/services/ci/create_builds_service.rb
+++ b/app/services/ci/create_builds_service.rb
@@ -1,8 +1,20 @@
module Ci
class CreateBuildsService
- def execute(commit, stage, ref, tag, user, trigger_request)
+ def execute(commit, stage, ref, tag, user, trigger_request, status)
builds_attrs = commit.config_processor.builds_for_stage_and_ref(stage, ref, tag)
+ # check when to create next build
+ builds_attrs = builds_attrs.select do |build_attrs|
+ case build_attrs[:when]
+ when 'on_success'
+ status == 'success'
+ when 'on_failure'
+ status == 'failed'
+ when 'always'
+ %w(success failed).include?(status)
+ end
+ end
+
builds_attrs.map do |build_attrs|
# don't create the same build twice
unless commit.builds.find_by(ref: ref, tag: tag, trigger_request: trigger_request, name: build_attrs[:name])
diff --git a/app/services/ci/image_for_build_service.rb b/app/services/ci/image_for_build_service.rb
index b95835ba093..b8d24193035 100644
--- a/app/services/ci/image_for_build_service.rb
+++ b/app/services/ci/image_for_build_service.rb
@@ -1,17 +1,15 @@
module Ci
class ImageForBuildService
def execute(project, params)
- image_name =
- if params[:sha]
- commit = project.commits.find_by(sha: params[:sha])
- image_for_commit(commit)
- elsif params[:ref]
- commit = project.last_commit_for_ref(params[:ref])
- image_for_commit(commit)
- else
- 'build-unknown.svg'
+ sha = params[:sha]
+ sha ||=
+ if params[:ref]
+ project.gl_project.commit(params[:ref]).try(:sha)
end
+ commit = project.commits.ordered.find_by(sha: sha)
+ image_name = image_for_commit(commit)
+
image_path = Rails.root.join('public/ci', image_name)
OpenStruct.new(
diff --git a/app/services/ci/register_build_service.rb b/app/services/ci/register_build_service.rb
index 71b61bbe389..7beb098659c 100644
--- a/app/services/ci/register_build_service.rb
+++ b/app/services/ci/register_build_service.rb
@@ -17,7 +17,7 @@ module Ci
builds = builds.order('created_at ASC')
build = builds.find do |build|
- (build.tag_list - current_runner.tag_list).empty?
+ build.can_be_served?(current_runner)
end
diff --git a/app/services/files/create_dir_service.rb b/app/services/files/create_dir_service.rb
index 71272fb5707..6107254a34e 100644
--- a/app/services/files/create_dir_service.rb
+++ b/app/services/files/create_dir_service.rb
@@ -5,5 +5,16 @@ module Files
def commit
repository.commit_dir(current_user, @file_path, @commit_message, @target_branch)
end
+
+ def validate
+ super
+
+ unless @file_path =~ Gitlab::Regex.file_path_regex
+ raise_error(
+ 'Your changes could not be committed, because the file path ' +
+ Gitlab::Regex.file_path_regex_message
+ )
+ end
+ end
end
end
diff --git a/app/services/files/create_service.rb b/app/services/files/create_service.rb
index c8e3a910bba..2348920cc58 100644
--- a/app/services/files/create_service.rb
+++ b/app/services/files/create_service.rb
@@ -9,12 +9,17 @@ module Files
def validate
super
- file_name = File.basename(@file_path)
+ if @file_path =~ Gitlab::Regex.directory_traversal_regex
+ raise_error(
+ 'Your changes could not be committed, because the file name ' +
+ Gitlab::Regex.directory_traversal_regex_message
+ )
+ end
- unless file_name =~ Gitlab::Regex.file_name_regex
+ unless @file_path =~ Gitlab::Regex.file_path_regex
raise_error(
'Your changes could not be committed, because the file name ' +
- Gitlab::Regex.file_name_regex_message
+ Gitlab::Regex.file_path_regex_message
)
end
diff --git a/app/services/git_push_service.rb b/app/services/git_push_service.rb
index f9a8265d2d4..3de7bb9dcaa 100644
--- a/app/services/git_push_service.rb
+++ b/app/services/git_push_service.rb
@@ -49,10 +49,13 @@ class GitPushService
elsif push_to_existing_branch?(ref, oldrev)
# Collect data for this git push
@push_commits = project.repository.commits_between(oldrev, newrev)
- project.update_merge_requests(oldrev, newrev, ref, @user)
process_commit_messages(ref)
end
+ # Update merge requests that may be affected by this push. A new branch
+ # could cause the last commit of a merge request to change.
+ project.update_merge_requests(oldrev, newrev, ref, @user)
+
@push_data = build_push_data(oldrev, newrev, ref)
# If CI was disabled but .gitlab-ci.yml file was pushed
@@ -74,48 +77,30 @@ class GitPushService
def process_commit_messages(ref)
is_default_branch = is_default_branch?(ref)
- @push_commits.each do |commit|
- # Close issues if these commits were pushed to the project's default branch and the commit message matches the
- # closing regex. Exclude any mentioned Issues from cross-referencing even if the commits are being pushed to
- # a different branch.
- issues_to_close = commit.closes_issues(user)
+ authors = Hash.new do |hash, commit|
+ email = commit.author_email
+ next hash[email] if hash.has_key?(email)
- # Load commit author only if needed.
- # For push with 1k commits it prevents 900+ requests in database
- author = nil
+ hash[email] = commit_user(commit)
+ end
+ @push_commits.each do |commit|
# Keep track of the issues that will be actually closed because they are on a default branch.
# Hence, when creating cross-reference notes, the not-closed issues (on non-default branches)
# will also have cross-reference.
- actually_closed_issues = []
-
- if issues_to_close.present? && is_default_branch
- author ||= commit_user(commit)
- actually_closed_issues = issues_to_close
- issues_to_close.each do |issue|
- Issues::CloseService.new(project, author, {}).execute(issue, commit)
+ closed_issues = []
+
+ if is_default_branch
+ # Close issues if these commits were pushed to the project's default branch and the commit message matches the
+ # closing regex. Exclude any mentioned Issues from cross-referencing even if the commits are being pushed to
+ # a different branch.
+ closed_issues = commit.closes_issues(user)
+ closed_issues.each do |issue|
+ Issues::CloseService.new(project, authors[commit], {}).execute(issue, commit)
end
end
- if project.default_issues_tracker?
- create_cross_reference_notes(commit, actually_closed_issues)
- end
- end
- end
-
- def create_cross_reference_notes(commit, issues_to_close)
- # Create cross-reference notes for any other references than those given in issues_to_close.
- # Omit any issues that were referenced in an issue-closing phrase, or have already been
- # mentioned from this commit (probably from this commit being pushed to a different branch).
- refs = commit.references(project, user) - issues_to_close
- refs.reject! { |r| commit.has_mentioned?(r) }
-
- if refs.present?
- author ||= commit_user(commit)
-
- refs.each do |r|
- SystemNoteService.cross_reference(r, commit, author)
- end
+ commit.create_cross_references!(authors[commit], closed_issues)
end
end
diff --git a/app/services/issues/create_service.rb b/app/services/issues/create_service.rb
index 1ea4b72216c..bcb380d3215 100644
--- a/app/services/issues/create_service.rb
+++ b/app/services/issues/create_service.rb
@@ -10,7 +10,7 @@ module Issues
issue.update_attributes(label_ids: label_params)
notification_service.new_issue(issue, current_user)
event_service.open_issue(issue, current_user)
- issue.create_cross_references!(issue.project, current_user)
+ issue.create_cross_references!(current_user)
execute_hooks(issue, 'open')
end
diff --git a/app/services/issues/update_service.rb b/app/services/issues/update_service.rb
index 2fc6ef7f356..551325e4cab 100644
--- a/app/services/issues/update_service.rb
+++ b/app/services/issues/update_service.rb
@@ -35,7 +35,7 @@ module Issues
create_title_change_note(issue, issue.previous_changes['title'].first)
end
- issue.create_new_cross_references!(issue.project, current_user)
+ issue.create_new_cross_references!(current_user)
execute_hooks(issue, 'update')
end
diff --git a/app/services/labels/group_service.rb b/app/services/labels/group_service.rb
new file mode 100644
index 00000000000..b26cee24d56
--- /dev/null
+++ b/app/services/labels/group_service.rb
@@ -0,0 +1,26 @@
+module Labels
+ class GroupService < ::BaseService
+ def initialize(project_labels)
+ @project_labels = project_labels.group_by(&:title)
+ end
+
+ def execute
+ build(@project_labels)
+ end
+
+ def label(title)
+ if title
+ group_label = @project_labels[title].group_by(&:title)
+ build(group_label).first
+ else
+ nil
+ end
+ end
+
+ private
+
+ def build(label)
+ label.map { |title, labels| GroupLabel.new(title, labels) }
+ end
+ end
+end
diff --git a/app/services/merge_requests/create_service.rb b/app/services/merge_requests/create_service.rb
index 9651b16462c..009d5a6867e 100644
--- a/app/services/merge_requests/create_service.rb
+++ b/app/services/merge_requests/create_service.rb
@@ -18,7 +18,7 @@ module MergeRequests
merge_request.update_attributes(label_ids: label_params)
event_service.open_mr(merge_request, current_user)
notification_service.new_merge_request(merge_request, current_user)
- merge_request.create_cross_references!(merge_request.project, current_user)
+ merge_request.create_cross_references!(current_user)
execute_hooks(merge_request)
end
diff --git a/app/services/merge_requests/post_merge_service.rb b/app/services/merge_requests/post_merge_service.rb
index aceb8cb9021..8f25c5e2496 100644
--- a/app/services/merge_requests/post_merge_service.rb
+++ b/app/services/merge_requests/post_merge_service.rb
@@ -6,6 +6,7 @@ module MergeRequests
#
class PostMergeService < MergeRequests::BaseService
def execute(merge_request)
+ close_issues(merge_request)
merge_request.mark_as_merged
create_merge_event(merge_request, current_user)
create_note(merge_request)
@@ -15,6 +16,15 @@ module MergeRequests
private
+ def close_issues(merge_request)
+ return unless merge_request.target_branch == project.default_branch
+
+ closed_issues = merge_request.closes_issues(current_user)
+ closed_issues.each do |issue|
+ Issues::CloseService.new(project, current_user, {}).execute(issue, merge_request)
+ end
+ end
+
def create_merge_event(merge_request, current_user)
EventCreateService.new.merge_mr(merge_request, current_user)
end
diff --git a/app/services/merge_requests/refresh_service.rb b/app/services/merge_requests/refresh_service.rb
index e903e48e3cd..d68bc79ecc0 100644
--- a/app/services/merge_requests/refresh_service.rb
+++ b/app/services/merge_requests/refresh_service.rb
@@ -5,13 +5,20 @@ module MergeRequests
@oldrev, @newrev = oldrev, newrev
@branch_name = Gitlab::Git.ref_name(ref)
- @fork_merge_requests = @project.fork_merge_requests.opened
- @commits = @project.repository.commits_between(oldrev, newrev)
- close_merge_requests
+ find_new_commits
reload_merge_requests
+
+ # Leave a system note if a branch was deleted/added
+ if branch_added? || branch_removed?
+ comment_mr_branch_presence_changed
+ comment_mr_with_commits
+ else
+ comment_mr_with_commits
+ close_merge_requests
+ end
+
execute_mr_web_hooks
- comment_mr_with_commits
true
end
@@ -31,7 +38,6 @@ module MergeRequests
commit_ids.include?(merge_request.last_commit.id)
end
-
merge_requests.uniq.select(&:source_project).each do |merge_request|
MergeRequests::PostMergeService.
new(merge_request.target_project, @current_user).
@@ -47,7 +53,7 @@ module MergeRequests
# Note: we should update merge requests from forks too
def reload_merge_requests
merge_requests = @project.merge_requests.opened.by_branch(@branch_name).to_a
- merge_requests += @fork_merge_requests.by_branch(@branch_name).to_a
+ merge_requests += fork_merge_requests.by_branch(@branch_name).to_a
merge_requests = filter_merge_requests(merge_requests)
merge_requests.each do |merge_request|
@@ -70,13 +76,48 @@ module MergeRequests
end
end
+ def find_new_commits
+ if branch_added?
+ @commits = []
+
+ merge_request = merge_requests_for_source_branch.first
+ return unless merge_request
+
+ last_commit = merge_request.last_commit
+
+ begin
+ # Since any number of commits could have been made to the restored branch,
+ # find the common root to see what has been added.
+ common_ref = @project.repository.merge_base(last_commit.id, @newrev)
+ # If the a commit no longer exists in this repo, gitlab_git throws
+ # a Rugged::OdbError. This is fixed in https://gitlab.com/gitlab-org/gitlab_git/merge_requests/52
+ @commits = @project.repository.commits_between(common_ref, @newrev) if common_ref
+ rescue
+ end
+ elsif branch_removed?
+ # No commits for a deleted branch.
+ @commits = []
+ else
+ @commits = @project.repository.commits_between(@oldrev, @newrev)
+ end
+ end
+
+ # Add comment about branches being deleted or added to merge requests
+ def comment_mr_branch_presence_changed
+ presence = branch_added? ? :add : :delete
+
+ merge_requests_for_source_branch.each do |merge_request|
+ SystemNoteService.change_branch_presence(
+ merge_request, merge_request.project, @current_user,
+ :source, @branch_name, presence)
+ end
+ end
+
# Add comment about pushing new commits to merge requests
def comment_mr_with_commits
- merge_requests = @project.origin_merge_requests.opened.where(source_branch: @branch_name).to_a
- merge_requests += @fork_merge_requests.where(source_branch: @branch_name).to_a
- merge_requests = filter_merge_requests(merge_requests)
+ return unless @commits.present?
- merge_requests.each do |merge_request|
+ merge_requests_for_source_branch.each do |merge_request|
mr_commit_ids = Set.new(merge_request.commits.map(&:id))
new_commits, existing_commits = @commits.partition do |commit|
@@ -91,14 +132,7 @@ module MergeRequests
# Call merge request webhook with update branches
def execute_mr_web_hooks
- merge_requests = @project.origin_merge_requests.opened
- .where(source_branch: @branch_name)
- .to_a
- merge_requests += @fork_merge_requests.where(source_branch: @branch_name)
- .to_a
- merge_requests = filter_merge_requests(merge_requests)
-
- merge_requests.each do |merge_request|
+ merge_requests_for_source_branch.each do |merge_request|
execute_hooks(merge_request, 'update')
end
end
@@ -106,5 +140,25 @@ module MergeRequests
def filter_merge_requests(merge_requests)
merge_requests.uniq.select(&:source_project)
end
+
+ def merge_requests_for_source_branch
+ @source_merge_requests ||= begin
+ merge_requests = @project.origin_merge_requests.opened.where(source_branch: @branch_name).to_a
+ merge_requests += fork_merge_requests.where(source_branch: @branch_name).to_a
+ filter_merge_requests(merge_requests)
+ end
+ end
+
+ def fork_merge_requests
+ @fork_merge_requests ||= @project.fork_merge_requests.opened
+ end
+
+ def branch_added?
+ Gitlab::Git.blank_ref?(@oldrev)
+ end
+
+ def branch_removed?
+ Gitlab::Git.blank_ref?(@newrev)
+ end
end
end
diff --git a/app/services/merge_requests/update_service.rb b/app/services/merge_requests/update_service.rb
index 25d79e22e39..61f7d2bbe89 100644
--- a/app/services/merge_requests/update_service.rb
+++ b/app/services/merge_requests/update_service.rb
@@ -59,7 +59,7 @@ module MergeRequests
merge_request.mark_as_unchecked
end
- merge_request.create_new_cross_references!(merge_request.project, current_user)
+ merge_request.create_new_cross_references!(current_user)
execute_hooks(merge_request, 'update')
end
diff --git a/app/services/notes/create_service.rb b/app/services/notes/create_service.rb
index 482c0444049..2001dc89c33 100644
--- a/app/services/notes/create_service.rb
+++ b/app/services/notes/create_service.rb
@@ -11,13 +11,7 @@ module Notes
# Skip system notes, like status changes and cross-references.
unless note.system
event_service.leave_note(note, note.author)
-
- # Create a cross-reference note if this Note contains GFM that names an
- # issue, merge request, or commit.
- note.references.each do |mentioned|
- SystemNoteService.cross_reference(mentioned, note.noteable, note.author)
- end
-
+ note.create_cross_references!
execute_hooks(note)
end
end
diff --git a/app/services/notes/update_service.rb b/app/services/notes/update_service.rb
index c22a9333ef6..72e2f78008d 100644
--- a/app/services/notes/update_service.rb
+++ b/app/services/notes/update_service.rb
@@ -4,7 +4,7 @@ module Notes
return note unless note.editable?
note.update_attributes(params.merge(updated_by: current_user))
-
+ note.create_new_cross_references!(current_user)
note.reset_events_cache
note
diff --git a/app/services/projects/transfer_service.rb b/app/services/projects/transfer_service.rb
index c327c244f0d..64ea6dd42eb 100644
--- a/app/services/projects/transfer_service.rb
+++ b/app/services/projects/transfer_service.rb
@@ -27,6 +27,7 @@ module Projects
def transfer(project, new_namespace)
Project.transaction do
old_path = project.path_with_namespace
+ old_namespace = project.namespace
new_path = File.join(new_namespace.try(:path) || '', project.path)
if Project.where(path: project.path, namespace_id: new_namespace.try(:id)).present?
@@ -51,6 +52,9 @@ module Projects
# clear project cached events
project.reset_events_cache
+ # Move uploads
+ Gitlab::UploadsTransfer.new.move_project(project.path, old_namespace.path, new_namespace.path)
+
true
end
end
diff --git a/app/services/system_note_service.rb b/app/services/system_note_service.rb
index 8253c1f780d..708c2f00486 100644
--- a/app/services/system_note_service.rb
+++ b/app/services/system_note_service.rb
@@ -168,6 +168,31 @@ class SystemNoteService
create_note(noteable: noteable, project: project, author: author, note: body)
end
+ # Called when a branch in Noteable is added or deleted
+ #
+ # noteable - Noteable object
+ # project - Project owning noteable
+ # author - User performing the change
+ # branch_type - :source or :target
+ # branch - branch name
+ # presence - :add or :delete
+ #
+ # Example Note text:
+ #
+ # "Restored target branch `feature`"
+ #
+ # Returns the created Note object
+ def self.change_branch_presence(noteable, project, author, branch_type, branch, presence)
+ verb =
+ if presence == :add
+ 'restored'
+ else
+ 'deleted'
+ end
+ body = "#{verb} #{branch_type.to_s} branch `#{branch}`".capitalize
+ create_note(noteable: noteable, project: project, author: author, note: body)
+ end
+
# Called when a Mentionable references a Noteable
#
# noteable - Noteable object being referenced
@@ -302,7 +327,7 @@ class SystemNoteService
commit_ids = if count == 1
existing_commits.first.short_id
else
- if oldrev
+ if oldrev && !Gitlab::Git.blank_ref?(oldrev)
"#{Commit.truncate_sha(oldrev)}...#{existing_commits.last.short_id}"
else
"#{existing_commits.first.short_id}..#{existing_commits.last.short_id}"
diff --git a/app/uploaders/file_uploader.rb b/app/uploaders/file_uploader.rb
index f9673abbfe8..e8211585834 100644
--- a/app/uploaders/file_uploader.rb
+++ b/app/uploaders/file_uploader.rb
@@ -26,7 +26,7 @@ class FileUploader < CarrierWave::Uploader::Base
end
def secure_url
- File.join(Gitlab.config.gitlab.url, @project.path_with_namespace, "uploads", @secret, file.filename)
+ File.join("/uploads", @secret, file.filename)
end
def file_storage?
diff --git a/app/views/abuse_report_mailer/notify.html.haml b/app/views/abuse_report_mailer/notify.html.haml
new file mode 100644
index 00000000000..619533e09a7
--- /dev/null
+++ b/app/views/abuse_report_mailer/notify.html.haml
@@ -0,0 +1,11 @@
+%p
+ #{link_to @abuse_report.user.name, user_url(@abuse_report.user)}
+ (@#{@abuse_report.user.username}) was reported for abuse by
+ #{link_to @abuse_report.reporter.name, user_url(@abuse_report.reporter)}
+ (@#{@abuse_report.reporter.username}).
+
+%blockquote
+ = @abuse_report.message
+
+%p
+ = link_to "View details", abuse_reports_url
diff --git a/app/views/abuse_report_mailer/notify.text.haml b/app/views/abuse_report_mailer/notify.text.haml
new file mode 100644
index 00000000000..7dacf857035
--- /dev/null
+++ b/app/views/abuse_report_mailer/notify.text.haml
@@ -0,0 +1,5 @@
+#{@abuse_report.user.name} (@#{@abuse_report.user.username}) was reported for abuse by #{@abuse_report.reporter.name} (@#{@abuse_report.reporter.username}).
+\
+> #{@abuse_report.message}
+\
+View details: #{admin_abuse_reports_url}
diff --git a/app/views/admin/abuse_reports/index.html.haml b/app/views/admin/abuse_reports/index.html.haml
index 2e8746146d1..40a5fe4628b 100644
--- a/app/views/admin/abuse_reports/index.html.haml
+++ b/app/views/admin/abuse_reports/index.html.haml
@@ -2,16 +2,17 @@
%h3.page-title Abuse Reports
%hr
- if @abuse_reports.present?
- %table.table
- %thead
- %tr
- %th Reported by
- %th Reported at
- %th Message
- %th User
- %th Primary action
- %th
- = render @abuse_reports
+ .table-holder
+ %table.table
+ %thead
+ %tr
+ %th Reported by
+ %th Reported at
+ %th Message
+ %th User
+ %th Primary action
+ %th
+ = render @abuse_reports
= paginate @abuse_reports
- else
%h4 There are no abuse reports
diff --git a/app/views/admin/application_settings/_form.html.haml b/app/views/admin/application_settings/_form.html.haml
index a36ae0b766c..7a78526e09a 100644
--- a/app/views/admin/application_settings/_form.html.haml
+++ b/app/views/admin/application_settings/_form.html.haml
@@ -47,6 +47,12 @@
= f.label :version_check_enabled do
= f.check_box :version_check_enabled
Version check enabled
+ .form-group
+ = f.label :admin_notification_email, class: 'control-label col-sm-2'
+ .col-sm-10
+ = f.text_field :admin_notification_email, class: 'form-control'
+ .help-block
+ Abuse reports will be sent to this address if it is set. Abuse reports are always available in the admin area.
%fieldset
%legend Account and Limit Settings
diff --git a/app/views/admin/applications/show.html.haml b/app/views/admin/applications/show.html.haml
index 0ea2ffeda99..3eb9d61972b 100644
--- a/app/views/admin/applications/show.html.haml
+++ b/app/views/admin/applications/show.html.haml
@@ -3,25 +3,26 @@
Application: #{@application.name}
-%table.table
- %tr
- %td
- Application Id
- %td
- %code#application_id= @application.uid
- %tr
- %td
- Secret:
- %td
- %code#secret= @application.secret
+.table-holder
+ %table.table
+ %tr
+ %td
+ Application Id
+ %td
+ %code#application_id= @application.uid
+ %tr
+ %td
+ Secret:
+ %td
+ %code#secret= @application.secret
- %tr
- %td
- Callback url
- %td
- - @application.redirect_uri.split.each do |uri|
- %div
- %span.monospace= uri
+ %tr
+ %td
+ Callback url
+ %td
+ - @application.redirect_uri.split.each do |uri|
+ %div
+ %span.monospace= uri
.form-actions
= link_to 'Edit', edit_admin_application_path(@application), class: 'btn btn-primary wide pull-left'
= render 'delete_form', application: @application, submit_btn_css: 'btn btn-danger prepend-left-10'
diff --git a/app/views/admin/background_jobs/show.html.haml b/app/views/admin/background_jobs/show.html.haml
index 3a01e115109..de5bc050cf0 100644
--- a/app/views/admin/background_jobs/show.html.haml
+++ b/app/views/admin/background_jobs/show.html.haml
@@ -12,24 +12,25 @@
%i.fa.fa-exclamation-triangle
There are no running sidekiq processes. Please restart GitLab
- else
- %table.table
- %thead
- %th USER
- %th PID
- %th CPU
- %th MEM
- %th STATE
- %th START
- %th COMMAND
- %tbody
- - @sidekiq_processes.each do |process|
- - next unless process.match(/(sidekiq \d+\.\d+\.\d+.+$)/)
- - data = process.strip.split(' ')
- %tr
- %td= gitlab_config.user
- - 5.times do
- %td= data.shift
- %td= data.join(' ')
+ .table-holder
+ %table.table
+ %thead
+ %th USER
+ %th PID
+ %th CPU
+ %th MEM
+ %th STATE
+ %th START
+ %th COMMAND
+ %tbody
+ - @sidekiq_processes.each do |process|
+ - next unless process.match(/(sidekiq \d+\.\d+\.\d+.+$)/)
+ - data = process.strip.split(' ')
+ %tr
+ %td= gitlab_config.user
+ - 5.times do
+ %td= data.shift
+ %td= data.join(' ')
.clearfix
%p
diff --git a/app/views/admin/deploy_keys/index.html.haml b/app/views/admin/deploy_keys/index.html.haml
index 2bf1689cbc6..841e6971fb2 100644
--- a/app/views/admin/deploy_keys/index.html.haml
+++ b/app/views/admin/deploy_keys/index.html.haml
@@ -5,22 +5,23 @@
.panel-head-actions
= link_to 'New Deploy Key', new_admin_deploy_key_path, class: "btn btn-new btn-sm"
- if @deploy_keys.any?
- %table.table
- %thead.panel-heading
- %tr
- %th Title
- %th Fingerprint
- %th Added at
- %th
- %tbody
- - @deploy_keys.each do |deploy_key|
+ .table-holder
+ %table.table
+ %thead.panel-heading
%tr
- %td
- %strong= deploy_key.title
- %td
- %code.key-fingerprint= deploy_key.fingerprint
- %td
- %span.cgray
- added #{time_ago_with_tooltip(deploy_key.created_at)}
- %td
- = link_to 'Remove', admin_deploy_key_path(deploy_key), data: { confirm: 'Are you sure?'}, method: :delete, class: "btn btn-sm btn-remove delete-key pull-right"
+ %th Title
+ %th Fingerprint
+ %th Added at
+ %th
+ %tbody
+ - @deploy_keys.each do |deploy_key|
+ %tr
+ %td
+ %strong= deploy_key.title
+ %td
+ %code.key-fingerprint= deploy_key.fingerprint
+ %td
+ %span.cgray
+ added #{time_ago_with_tooltip(deploy_key.created_at)}
+ %td
+ = link_to 'Remove', admin_deploy_key_path(deploy_key), data: { confirm: 'Are you sure?'}, method: :delete, class: "btn btn-sm btn-remove delete-key pull-right"
diff --git a/app/views/admin/identities/index.html.haml b/app/views/admin/identities/index.html.haml
index ae57e3adc4d..8358a14445b 100644
--- a/app/views/admin/identities/index.html.haml
+++ b/app/views/admin/identities/index.html.haml
@@ -2,12 +2,13 @@
= render 'admin/users/head'
- if @identities.present?
- %table.table
- %thead
- %tr
- %th Provider
- %th Identifier
- %th
- = render @identities
+ .table-holder
+ %table.table
+ %thead
+ %tr
+ %th Provider
+ %th Identifier
+ %th
+ = render @identities
- else
%h4 This user has no identities
diff --git a/app/views/admin/services/index.html.haml b/app/views/admin/services/index.html.haml
index e2377291142..6a5986f496a 100644
--- a/app/views/admin/services/index.html.haml
+++ b/app/views/admin/services/index.html.haml
@@ -2,22 +2,23 @@
%h3.page-title Service templates
%p.light Service template allows you to set default values for project services
-%table.table
- %thead
- %tr
- %th
- %th Service
- %th Description
- %th Last edit
- - @services.sort_by(&:title).each do |service|
- %tr
- %td
- = icon("copy", class: 'clgray')
- %td
- = link_to edit_admin_application_settings_service_path(service.id) do
- %strong= service.title
- %td
- = service.description
- %td.light
- = time_ago_in_words service.updated_at
- ago
+.table-holder
+ %table.table
+ %thead
+ %tr
+ %th
+ %th Service
+ %th Description
+ %th Last edit
+ - @services.sort_by(&:title).each do |service|
+ %tr
+ %td
+ = icon("copy", class: 'clgray')
+ %td
+ = link_to edit_admin_application_settings_service_path(service.id) do
+ %strong= service.title
+ %td
+ = service.description
+ %td.light
+ = time_ago_in_words service.updated_at
+ ago
diff --git a/app/views/users/_profile.html.haml b/app/views/admin/users/_profile.html.haml
index 90d9980c85c..90d9980c85c 100644
--- a/app/views/users/_profile.html.haml
+++ b/app/views/admin/users/_profile.html.haml
diff --git a/app/views/admin/users/show.html.haml b/app/views/admin/users/show.html.haml
index a383ea57384..0848504b7a6 100644
--- a/app/views/admin/users/show.html.haml
+++ b/app/views/admin/users/show.html.haml
@@ -8,13 +8,13 @@
= @user.name
%ul.well-list
%li
- = image_tag avatar_icon(@user.email, 60), class: "avatar s60"
+ = image_tag avatar_icon(@user, 60), class: "avatar s60"
%li
%span.light Profile page:
%strong
= link_to user_path(@user) do
= @user.username
- = render 'users/profile', user: @user
+ = render 'admin/users/profile', user: @user
.panel.panel-default
.panel-heading
diff --git a/app/views/ci/admin/events/index.html.haml b/app/views/ci/admin/events/index.html.haml
index f9ab0994304..5a5b4dc7c35 100644
--- a/app/views/ci/admin/events/index.html.haml
+++ b/app/views/ci/admin/events/index.html.haml
@@ -1,17 +1,18 @@
-%table.table
- %thead
- %tr
- %th User ID
- %th Description
- %th When
- - @events.each do |event|
- %tr
- %td
- = event.user_id
- %td
- = event.description
- %td.light
- = time_ago_in_words event.updated_at
- ago
+.table-holder
+ %table.table
+ %thead
+ %tr
+ %th User ID
+ %th Description
+ %th When
+ - @events.each do |event|
+ %tr
+ %td
+ = event.user_id
+ %td
+ = event.description
+ %td.light
+ = time_ago_in_words event.updated_at
+ ago
-= paginate @events \ No newline at end of file
+= paginate @events
diff --git a/app/views/ci/admin/projects/index.html.haml b/app/views/ci/admin/projects/index.html.haml
index dc7b041473b..0da8547924b 100644
--- a/app/views/ci/admin/projects/index.html.haml
+++ b/app/views/ci/admin/projects/index.html.haml
@@ -1,15 +1,16 @@
-%table.table
- %thead
- %tr
- %th ID
- %th Name
- %th Last build
- %th Access
- %th Builds
- %th
+.table-holder
+ %table.table
+ %thead
+ %tr
+ %th ID
+ %th Name
+ %th Last build
+ %th Access
+ %th Builds
+ %th
- - @projects.each do |project|
- = render "ci/admin/projects/project", project: project
+ - @projects.each do |project|
+ = render "ci/admin/projects/project", project: project
= paginate @projects
diff --git a/app/views/ci/admin/runner_projects/index.html.haml b/app/views/ci/admin/runner_projects/index.html.haml
index f049b4f4c4e..6b4e3b2cb38 100644
--- a/app/views/ci/admin/runner_projects/index.html.haml
+++ b/app/views/ci/admin/runner_projects/index.html.haml
@@ -1,5 +1,5 @@
%p.lead
- To register new runner visit #{link_to 'this page ', ci_runners_path}
+ To register a new runner visit #{link_to 'this page ', ci_runners_path}
.row
.col-md-8
diff --git a/app/views/ci/admin/runners/index.html.haml b/app/views/ci/admin/runners/index.html.haml
index 01ce81b4476..bacaccfbffa 100644
--- a/app/views/ci/admin/runners/index.html.haml
+++ b/app/views/ci/admin/runners/index.html.haml
@@ -1,5 +1,5 @@
%p.lead
- %span To register new runner you should enter the following registration token. With this token the runner will request a unique runner token and use that for future communication.
+ %span To register a new runner you should enter the following registration token. With this token the runner will request a unique runner token and use that for future communication.
%code #{GitlabCi::REGISTRATION_TOKEN}
.bs-callout
@@ -21,7 +21,7 @@
\- run builds from assigned projects
%li
%span.label.label-danger paused
- \- runner will not receive any new build
+ \- runner will not receive any new builds
.append-bottom-20.clearfix
.pull-left
@@ -35,18 +35,19 @@
%br
-%table.table
- %thead
- %tr
- %th Type
- %th Runner token
- %th Description
- %th Projects
- %th Builds
- %th Tags
- %th Last contact
- %th
+.table-holder
+ %table.table
+ %thead
+ %tr
+ %th Type
+ %th Runner token
+ %th Description
+ %th Projects
+ %th Builds
+ %th Tags
+ %th Last contact
+ %th
- - @runners.each do |runner|
- = render "ci/admin/runners/runner", runner: runner
+ - @runners.each do |runner|
+ = render "ci/admin/runners/runner", runner: runner
= paginate @runners
diff --git a/app/views/ci/admin/runners/show.html.haml b/app/views/ci/admin/runners/show.html.haml
index 92787b2e6ac..1498db46a80 100644
--- a/app/views/ci/admin/runners/show.html.haml
+++ b/app/views/ci/admin/runners/show.html.haml
@@ -13,13 +13,13 @@
- if @runner.shared?
.bs-callout.bs-callout-success
- %h4 This runner will process build from ALL UNASSIGNED projects
+ %h4 This runner will process builds from ALL UNASSIGNED projects
%p
If you want runners to build only specific projects, enable them in the table below.
Keep in mind that this is a one way transition.
- else
.bs-callout.bs-callout-info
- %h4 This runner will process build only from ASSIGNED projects
+ %h4 This runner will process builds only from ASSIGNED projects
%p You can't make this a shared runner.
%hr
= form_for @runner, url: ci_admin_runner_path(@runner), html: { class: 'form-horizontal' } do |f|
@@ -53,13 +53,14 @@
%th
- @runner.runner_projects.each do |runner_project|
- project = runner_project.project
- %tr.alert-info
- %td
- %strong
- = project.name
- %td
- .pull-right
- = link_to 'Disable', [:ci, :admin, project, runner_project], method: :delete, class: 'btn btn-danger btn-xs'
+ - if project.gl_project
+ %tr.alert-info
+ %td
+ %strong
+ = project.name
+ %td
+ .pull-right
+ = link_to 'Disable', [:ci, :admin, project, runner_project], method: :delete, class: 'btn btn-danger btn-xs'
%table.table
%thead
@@ -103,21 +104,26 @@
%th Finished at
- @builds.each do |build|
+ - gl_project = build.gl_project
%tr.build
%td.id
- - gl_project = build.project.gl_project
- = link_to namespace_project_build_path(gl_project.namespace, gl_project, build) do
+ - if gl_project
+ = link_to namespace_project_build_path(gl_project.namespace, gl_project, build) do
+ = build.id
+ - else
= build.id
%td.status
= ci_status_with_icon(build.status)
%td.status
- = build.project.name
+ - if gl_project
+ = gl_project.name_with_namespace
%td.build-link
- = link_to ci_status_path(build.commit) do
- %strong #{build.commit.short_sha}
+ - if gl_project
+ = link_to ci_status_path(build.commit) do
+ %strong #{build.commit.short_sha}
%td.timestamp
- if build.finished_at
diff --git a/app/views/ci/events/index.html.haml b/app/views/ci/events/index.html.haml
deleted file mode 100644
index 779f49b3d3a..00000000000
--- a/app/views/ci/events/index.html.haml
+++ /dev/null
@@ -1,19 +0,0 @@
-%h3.page-title Events
-
-%table.table
- %thead
- %tr
- %th User ID
- %th Description
- %th When
- - @events.each do |event|
- %tr
- %td
- = event.user_id
- %td
- = event.description
- %td.light
- = time_ago_in_words event.updated_at
- ago
-
-= paginate @events \ No newline at end of file
diff --git a/app/views/ci/lints/_create.html.haml b/app/views/ci/lints/_create.html.haml
index e2179e60f3e..77f78caa8d8 100644
--- a/app/views/ci/lints/_create.html.haml
+++ b/app/views/ci/lints/_create.html.haml
@@ -4,29 +4,35 @@
syntax is correct
%i.fa.fa-ok.correct-syntax
- %table.table.table-bordered
- %thead
- %tr
- %th Parameter
- %th Value
- %tbody
- - @stages.each do |stage|
- - @builds.select { |build| build[:stage] == stage }.each do |build|
- %tr
- %td #{stage.capitalize} Job - #{build[:name]}
- %td
- %pre
- = simple_format build[:script]
+ .table-holder
+ %table.table.table-bordered
+ %thead
+ %tr
+ %th Parameter
+ %th Value
+ %tbody
+ - @stages.each do |stage|
+ - @builds.select { |build| build[:stage] == stage }.each do |build|
+ %tr
+ %td #{stage.capitalize} Job - #{build[:name]}
+ %td
+ %pre
+ = simple_format build[:commands]
- %br
- %b Tag list:
- = build[:tags]
- %br
- %b Refs only:
- = build[:only] && build[:only].join(", ")
- %br
- %b Refs except:
- = build[:except] && build[:except].join(", ")
+ %br
+ %b Tag list:
+ = build[:tags]
+ %br
+ %b Refs only:
+ = build[:only] && build[:only].join(", ")
+ %br
+ %b Refs except:
+ = build[:except] && build[:except].join(", ")
+ %br
+ %b When:
+ = build[:when]
+ - if build[:allow_failure]
+ %b Allowed to fail
-else
%p
diff --git a/app/views/ci/projects/index.html.haml b/app/views/ci/projects/index.html.haml
new file mode 100644
index 00000000000..9c2290bc4a5
--- /dev/null
+++ b/app/views/ci/projects/index.html.haml
@@ -0,0 +1,20 @@
+.wiki
+ %h1
+ GitLab CI is now integrated in GitLab UI
+ %h2 For existing projects
+
+ %p
+ Check the following pages to find the CI status you're looking for:
+
+ %ul
+ %li Projects page - shows CI status for each project.
+ %li Project commits page - show CI status for each commit.
+
+
+
+ %h2 For new projects
+
+ %p
+ If you want to enable CI for a new project it is easy as adding
+ = link_to ".gitlab-ci.yml", "http://doc.gitlab.com/ce/ci/yaml/README.html"
+ file to your repository
diff --git a/app/views/ci/user_sessions/new.html.haml b/app/views/ci/user_sessions/new.html.haml
index 308b217ea78..b8d9a1d7089 100644
--- a/app/views/ci/user_sessions/new.html.haml
+++ b/app/views/ci/user_sessions/new.html.haml
@@ -1,8 +1,7 @@
.login-block
%h2 Login using GitLab account
%p.light
- Make sure you have account on GitLab server
+ Make sure you have an account on the GitLab server
= link_to GitlabCi.config.gitlab_server.url, GitlabCi.config.gitlab_server.url, no_turbolink
%hr
= link_to "Login with GitLab", auth_ci_user_sessions_path(state: params[:state]), no_turbolink.merge( class: 'btn btn-login btn-success' )
-
diff --git a/app/views/dashboard/milestones/_issue.html.haml b/app/views/dashboard/milestones/_issue.html.haml
index f689b9698eb..1408ebdd5dc 100644
--- a/app/views/dashboard/milestones/_issue.html.haml
+++ b/app/views/dashboard/milestones/_issue.html.haml
@@ -7,4 +7,4 @@
= link_to_gfm issue.title, [project.namespace.becomes(Namespace), project, issue], title: issue.title
.pull-right.assignee-icon
- if issue.assignee
- = image_tag avatar_icon(issue.assignee.email, 16), class: "avatar s16"
+ = image_tag avatar_icon(issue.assignee, 16), class: "avatar s16"
diff --git a/app/views/dashboard/milestones/_merge_request.html.haml b/app/views/dashboard/milestones/_merge_request.html.haml
index 8f5c4cce529..77c46de030b 100644
--- a/app/views/dashboard/milestones/_merge_request.html.haml
+++ b/app/views/dashboard/milestones/_merge_request.html.haml
@@ -7,4 +7,4 @@
= link_to_gfm merge_request.title, [project.namespace.becomes(Namespace), project, merge_request], title: merge_request.title
.pull-right.assignee-icon
- if merge_request.assignee
- = image_tag avatar_icon(merge_request.assignee.email, 16), class: "avatar s16"
+ = image_tag avatar_icon(merge_request.assignee, 16), class: "avatar s16"
diff --git a/app/views/dashboard/milestones/show.html.haml b/app/views/dashboard/milestones/show.html.haml
index 0d204ced7ea..2fe14c6388c 100644
--- a/app/views/dashboard/milestones/show.html.haml
+++ b/app/views/dashboard/milestones/show.html.haml
@@ -13,26 +13,28 @@
%span All issues for this milestone are closed. You may close the milestone now.
.description
-%table.table
- %thead
- %tr
- %th Project
- %th Open issues
- %th State
- %th Due date
- - @dashboard_milestone.milestones.each do |milestone|
- %tr
- %td
- = link_to "#{milestone.project.name_with_namespace}", namespace_project_milestone_path(milestone.project.namespace, milestone.project, milestone)
- %td
- = milestone.issues.opened.count
- %td
- - if milestone.closed?
- Closed
- - else
- Open
- %td
- = milestone.expires_at
+
+.table-holder
+ %table.table
+ %thead
+ %tr
+ %th Project
+ %th Open issues
+ %th State
+ %th Due date
+ - @dashboard_milestone.milestones.each do |milestone|
+ %tr
+ %td
+ = link_to "#{milestone.project.name_with_namespace}", namespace_project_milestone_path(milestone.project.namespace, milestone.project, milestone)
+ %td
+ = milestone.issues.opened.count
+ %td
+ - if milestone.closed?
+ Closed
+ - else
+ Open
+ %td
+ = milestone.expires_at
.context
%p.lead
@@ -79,7 +81,7 @@
- @dashboard_milestone.participants.each do |user|
%li
= link_to user, title: user.name, class: "darken" do
- = image_tag avatar_icon(user.email, 32), class: "avatar s32"
+ = image_tag avatar_icon(user, 32), class: "avatar s32"
%strong= truncate(user.name, lenght: 40)
%br
%small.cgray= user.username
diff --git a/app/views/dashboard/projects/_projects.html.haml b/app/views/dashboard/projects/_projects.html.haml
index d0194a17b01..81a5909e2d2 100644
--- a/app/views/dashboard/projects/_projects.html.haml
+++ b/app/views/dashboard/projects/_projects.html.haml
@@ -5,6 +5,7 @@
- if current_user.can_create_project?
%span.input-group-btn
= link_to new_project_path, class: 'btn btn-green' do
- New project
+ %i.fa.fa-plus
+ New Project
= render 'shared/projects/list', projects: @projects, ci: true
diff --git a/app/views/dashboard/snippets/index.html.haml b/app/views/dashboard/snippets/index.html.haml
index d3908062f43..07b6d57932e 100644
--- a/app/views/dashboard/snippets/index.html.haml
+++ b/app/views/dashboard/snippets/index.html.haml
@@ -6,33 +6,29 @@
.gray-content-block
.pull-right
= link_to new_snippet_path, class: "btn btn-new", title: "New Snippet" do
- Add new snippet
+ = icon('plus')
+ New Snippet
- .oneline
- Share code pastes with others out of git repository
-
-%ul.nav.nav-tabs.prepend-top-20
- = nav_tab :scope, nil do
- = link_to dashboard_snippets_path do
+ .btn-group.btn-group-next.snippet-scope-menu
+ = link_to dashboard_snippets_path, class: "btn btn-default #{"active" unless params[:scope]}" do
All
%span.badge
= current_user.snippets.count
- = nav_tab :scope, 'are_private' do
- = link_to dashboard_snippets_path(scope: 'are_private') do
+
+ = link_to dashboard_snippets_path(scope: 'are_private'), class: "btn btn-default #{"active" if params[:scope] == "are_private"}" do
Private
%span.badge
= current_user.snippets.are_private.count
- = nav_tab :scope, 'are_internal' do
- = link_to dashboard_snippets_path(scope: 'are_internal') do
+
+ = link_to dashboard_snippets_path(scope: 'are_internal'), class: "btn btn-default #{"active" if params[:scope] == "are_internal"}" do
Internal
%span.badge
= current_user.snippets.are_internal.count
- = nav_tab :scope, 'are_public' do
- = link_to dashboard_snippets_path(scope: 'are_public') do
+
+ = link_to dashboard_snippets_path(scope: 'are_public'), class: "btn btn-default #{"active" if params[:scope] == "are_public"}" do
Public
%span.badge
= current_user.snippets.are_public.count
-.my-snippets
- = render 'snippets/snippets'
+= render 'snippets/snippets'
diff --git a/app/views/doorkeeper/applications/index.html.haml b/app/views/doorkeeper/applications/index.html.haml
index 3b0b19107ca..ba4c5b86efb 100644
--- a/app/views/doorkeeper/applications/index.html.haml
+++ b/app/views/doorkeeper/applications/index.html.haml
@@ -1,17 +1,19 @@
- page_title "Applications"
%h3.page-title Your applications
%p= link_to 'New Application', new_oauth_application_path, class: 'btn btn-success'
-%table.table.table-striped
- %thead
- %tr
- %th Name
- %th Callback URL
- %th
- %th
- %tbody
- - @applications.each do |application|
- %tr{:id => "application_#{application.id}"}
- %td= link_to application.name, oauth_application_path(application)
- %td= application.redirect_uri
- %td= link_to 'Edit', edit_oauth_application_path(application), class: 'btn btn-link'
- %td= render 'delete_form', application: application
+
+.table-holder
+ %table.table.table-striped
+ %thead
+ %tr
+ %th Name
+ %th Callback URL
+ %th
+ %th
+ %tbody
+ - @applications.each do |application|
+ %tr{:id => "application_#{application.id}"}
+ %td= link_to application.name, oauth_application_path(application)
+ %td= application.redirect_uri
+ %td= link_to 'Edit', edit_oauth_application_path(application), class: 'btn btn-link'
+ %td= render 'delete_form', application: application
diff --git a/app/views/doorkeeper/applications/show.html.haml b/app/views/doorkeeper/applications/show.html.haml
index 80340aca54c..47442b78d48 100644
--- a/app/views/doorkeeper/applications/show.html.haml
+++ b/app/views/doorkeeper/applications/show.html.haml
@@ -2,26 +2,26 @@
%h3.page-title
Application: #{@application.name}
+.table-holder
+ %table.table
+ %tr
+ %td
+ Application Id
+ %td
+ %code#application_id= @application.uid
+ %tr
+ %td
+ Secret:
+ %td
+ %code#secret= @application.secret
-%table.table
- %tr
- %td
- Application Id
- %td
- %code#application_id= @application.uid
- %tr
- %td
- Secret:
- %td
- %code#secret= @application.secret
-
- %tr
- %td
- Callback url
- %td
- - @application.redirect_uri.split.each do |uri|
- %div
- %span.monospace= uri
+ %tr
+ %td
+ Callback url
+ %td
+ - @application.redirect_uri.split.each do |uri|
+ %div
+ %span.monospace= uri
.form-actions
= link_to 'Edit', edit_oauth_application_path(@application), class: 'btn btn-primary wide pull-left'
= render 'delete_form', application: @application, submit_btn_css: 'btn btn-danger prepend-left-10'
diff --git a/app/views/doorkeeper/authorized_applications/index.html.haml b/app/views/doorkeeper/authorized_applications/index.html.haml
index 814cdc987ef..b184b9c01d4 100644
--- a/app/views/doorkeeper/authorized_applications/index.html.haml
+++ b/app/views/doorkeeper/authorized_applications/index.html.haml
@@ -1,16 +1,17 @@
%header.page-header
%h1 Your authorized applications
%main{:role => "main"}
- %table.table.table-striped
- %thead
- %tr
- %th Application
- %th Created At
- %th
- %th
- %tbody
- - @applications.each do |application|
+ .table-holder
+ %table.table.table-striped
+ %thead
%tr
- %td= application.name
- %td= application.created_at.strftime('%Y-%m-%d %H:%M:%S')
- %td= render 'delete_form', application: application \ No newline at end of file
+ %th Application
+ %th Created At
+ %th
+ %th
+ %tbody
+ - @applications.each do |application|
+ %tr
+ %td= application.name
+ %td= application.created_at.strftime('%Y-%m-%d %H:%M:%S')
+ %td= render 'delete_form', application: application
diff --git a/app/views/events/_event_issue.atom.haml b/app/views/events/_event_issue.atom.haml
index 4259f64c191..fad65310021 100644
--- a/app/views/events/_event_issue.atom.haml
+++ b/app/views/events/_event_issue.atom.haml
@@ -1,3 +1,2 @@
%div{xmlns: "http://www.w3.org/1999/xhtml"}
- - if issue.description.present?
- = markdown(issue.description, xhtml: true, reference_only_path: false, project: issue.project)
+ = markdown(issue.description, pipeline: :atom, project: issue.project)
diff --git a/app/views/events/_event_merge_request.atom.haml b/app/views/events/_event_merge_request.atom.haml
index e8ed13df783..19bdc7b9ca5 100644
--- a/app/views/events/_event_merge_request.atom.haml
+++ b/app/views/events/_event_merge_request.atom.haml
@@ -1,3 +1,2 @@
%div{xmlns: "http://www.w3.org/1999/xhtml"}
- - if merge_request.description.present?
- = markdown(merge_request.description, xhtml: true, reference_only_path: false, project: merge_request.project)
+ = markdown(merge_request.description, pipeline: :atom, project: merge_request.project)
diff --git a/app/views/events/_event_note.atom.haml b/app/views/events/_event_note.atom.haml
index cfbfba50202..b730ebbd5f9 100644
--- a/app/views/events/_event_note.atom.haml
+++ b/app/views/events/_event_note.atom.haml
@@ -1,2 +1,2 @@
%div{xmlns: "http://www.w3.org/1999/xhtml"}
- = markdown(note.note, xhtml: true, reference_only_path: false, project: note.project)
+ = markdown(note.note, pipeline: :atom, project: note.project)
diff --git a/app/views/events/_event_push.atom.haml b/app/views/events/_event_push.atom.haml
index 3625cb49d8b..b271b9daff1 100644
--- a/app/views/events/_event_push.atom.haml
+++ b/app/views/events/_event_push.atom.haml
@@ -6,7 +6,7 @@
%i
at
= commit[:timestamp].to_time.to_s(:short)
- %blockquote= markdown(escape_once(commit[:message]), xhtml: true, reference_only_path: false, project: event.project)
+ %blockquote= markdown(escape_once(commit[:message]), pipeline: :atom, project: event.project)
- if event.commits_count > 15
%p
%i
diff --git a/app/views/explore/snippets/index.html.haml b/app/views/explore/snippets/index.html.haml
index 7e4fa7d4873..0f100c39ffb 100644
--- a/app/views/explore/snippets/index.html.haml
+++ b/app/views/explore/snippets/index.html.haml
@@ -10,7 +10,8 @@
- if current_user
.pull-right
= link_to new_snippet_path, class: "btn btn-new", title: "New Snippet" do
- Add new snippet
+ = icon('plus')
+ New Snippet
.oneline
Public snippets created by you and other users are listed here
diff --git a/app/views/groups/_projects.html.haml b/app/views/groups/_projects.html.haml
index 133f3e2d5a8..11d69977ef9 100644
--- a/app/views/groups/_projects.html.haml
+++ b/app/views/groups/_projects.html.haml
@@ -5,6 +5,7 @@
- if can? current_user, :create_projects, @group
%span.input-group-btn
= link_to new_project_path(namespace_id: @group.id), class: 'btn btn-green' do
- New project
+ %i.fa.fa-plus
+ New Project
= render 'shared/projects/list', projects: @projects, projects_limit: 20, stars: false, skip_namespace: true
diff --git a/app/views/groups/group_members/_group_member.html.haml b/app/views/groups/group_members/_group_member.html.haml
index b5f359279d5..3c19381321a 100644
--- a/app/views/groups/group_members/_group_member.html.haml
+++ b/app/views/groups/group_members/_group_member.html.haml
@@ -5,7 +5,7 @@
%li{class: "#{dom_class(member)} js-toggle-container", id: dom_id(member)}
%span{class: ("list-item-name" if show_controls)}
- if member.user
- = image_tag avatar_icon(user.email, 16), class: "avatar s16", alt: ''
+ = image_tag avatar_icon(user, 16), class: "avatar s16", alt: ''
%strong
= link_to user.name, user_path(user)
%span.cgray= user.username
diff --git a/app/views/groups/milestones/_issue.html.haml b/app/views/groups/milestones/_issue.html.haml
index 09f9b4b8969..9b85d83d6d8 100644
--- a/app/views/groups/milestones/_issue.html.haml
+++ b/app/views/groups/milestones/_issue.html.haml
@@ -7,4 +7,4 @@
= link_to_gfm issue.title, [project.namespace.becomes(Namespace), project, issue], title: issue.title
.pull-right.assignee-icon
- if issue.assignee
- = image_tag avatar_icon(issue.assignee.email, 16), class: "avatar s16", alt: ''
+ = image_tag avatar_icon(issue.assignee, 16), class: "avatar s16", alt: ''
diff --git a/app/views/groups/milestones/_merge_request.html.haml b/app/views/groups/milestones/_merge_request.html.haml
index d0d1426762b..e3aa4aad198 100644
--- a/app/views/groups/milestones/_merge_request.html.haml
+++ b/app/views/groups/milestones/_merge_request.html.haml
@@ -7,4 +7,4 @@
= link_to_gfm merge_request.title, [project.namespace.becomes(Namespace), project, merge_request], title: merge_request.title
.pull-right.assignee-icon
- if merge_request.assignee
- = image_tag avatar_icon(merge_request.assignee.email, 16), class: "avatar s16", alt: ''
+ = image_tag avatar_icon(merge_request.assignee, 16), class: "avatar s16", alt: ''
diff --git a/app/views/groups/milestones/show.html.haml b/app/views/groups/milestones/show.html.haml
index 0c213f42186..a92ad5d751b 100644
--- a/app/views/groups/milestones/show.html.haml
+++ b/app/views/groups/milestones/show.html.haml
@@ -21,26 +21,28 @@
%span All issues for this milestone are closed. You may close the milestone now.
.description
-%table.table
- %thead
- %tr
- %th Project
- %th Open issues
- %th State
- %th Due date
- - @group_milestone.milestones.each do |milestone|
- %tr
- %td
- = link_to "#{milestone.project.name}", namespace_project_milestone_path(milestone.project.namespace, milestone.project, milestone)
- %td
- = milestone.issues.opened.count
- %td
- - if milestone.closed?
- Closed
- - else
- Open
- %td
- = milestone.expires_at
+
+.table-holder
+ %table.table
+ %thead
+ %tr
+ %th Project
+ %th Open issues
+ %th State
+ %th Due date
+ - @group_milestone.milestones.each do |milestone|
+ %tr
+ %td
+ = link_to "#{milestone.project.name}", namespace_project_milestone_path(milestone.project.namespace, milestone.project, milestone)
+ %td
+ = milestone.issues.opened.count
+ %td
+ - if milestone.closed?
+ Closed
+ - else
+ Open
+ %td
+ = milestone.expires_at
.context
%p.lead
@@ -87,7 +89,7 @@
- @group_milestone.participants.each do |user|
%li
= link_to user, title: user.name, class: "darken" do
- = image_tag avatar_icon(user.email, 32), class: "avatar s32"
+ = image_tag avatar_icon(user, 32), class: "avatar s32"
%strong= truncate(user.name, lenght: 40)
%br
%small.cgray= user.username
diff --git a/app/views/help/_shortcuts.html.haml b/app/views/help/_shortcuts.html.haml
index e809d99ba71..67349fcbd78 100644
--- a/app/views/help/_shortcuts.html.haml
+++ b/app/views/help/_shortcuts.html.haml
@@ -102,6 +102,12 @@
%tr
%td.shortcut
.key g
+ .key b
+ %td
+ Go to builds
+ %tr
+ %td.shortcut
+ .key g
.key n
%td
Go to network graph
diff --git a/app/views/import/bitbucket/status.html.haml b/app/views/import/bitbucket/status.html.haml
index 777eb482714..30bcdb86827 100644
--- a/app/views/import/bitbucket/status.html.haml
+++ b/app/views/import/bitbucket/status.html.haml
@@ -14,45 +14,46 @@
= button_tag 'Import all projects', class: "btn btn-success js-import-all"
-%table.table.import-jobs
- %thead
- %tr
- %th From Bitbucket
- %th To GitLab
- %th Status
- %tbody
- - @already_added_projects.each do |project|
- %tr{id: "project_#{project.id}", class: "#{project_status_css_class(project.import_status)}"}
- %td
- = link_to project.import_source, "https://bitbucket.org/#{project.import_source}", target: "_blank"
- %td
- %strong= link_to project.path_with_namespace, [project.namespace.becomes(Namespace), project]
- %td.job-status
- - if project.import_status == 'finished'
- %span
- %i.fa.fa-check
- done
- - elsif project.import_status == 'started'
- %i.fa.fa-spinner.fa-spin
- started
- - else
- = project.human_import_status_name
+.table-holder
+ %table.table.import-jobs
+ %thead
+ %tr
+ %th From Bitbucket
+ %th To GitLab
+ %th Status
+ %tbody
+ - @already_added_projects.each do |project|
+ %tr{id: "project_#{project.id}", class: "#{project_status_css_class(project.import_status)}"}
+ %td
+ = link_to project.import_source, "https://bitbucket.org/#{project.import_source}", target: "_blank"
+ %td
+ %strong= link_to project.path_with_namespace, [project.namespace.becomes(Namespace), project]
+ %td.job-status
+ - if project.import_status == 'finished'
+ %span
+ %i.fa.fa-check
+ done
+ - elsif project.import_status == 'started'
+ %i.fa.fa-spinner.fa-spin
+ started
+ - else
+ = project.human_import_status_name
- - @repos.each do |repo|
- %tr{id: "repo_#{repo["owner"]}___#{repo["slug"]}"}
- %td
- = link_to "#{repo["owner"]}/#{repo["slug"]}", "https://bitbucket.org/#{repo["owner"]}/#{repo["slug"]}", target: "_blank"
- %td.import-target
- = "#{repo["owner"]}/#{repo["slug"]}"
- %td.import-actions.job-status
- = button_tag "Import", class: "btn js-add-to-import"
- - @incompatible_repos.each do |repo|
- %tr{id: "repo_#{repo["owner"]}___#{repo["slug"]}"}
- %td
- = link_to "#{repo["owner"]}/#{repo["slug"]}", "https://bitbucket.org/#{repo["owner"]}/#{repo["slug"]}", target: "_blank"
- %td.import-target
- %td.import-actions-job-status
- = label_tag "Incompatible Project", nil, class: "label label-danger"
+ - @repos.each do |repo|
+ %tr{id: "repo_#{repo["owner"]}___#{repo["slug"]}"}
+ %td
+ = link_to "#{repo["owner"]}/#{repo["slug"]}", "https://bitbucket.org/#{repo["owner"]}/#{repo["slug"]}", target: "_blank"
+ %td.import-target
+ = "#{repo["owner"]}/#{repo["slug"]}"
+ %td.import-actions.job-status
+ = button_tag "Import", class: "btn js-add-to-import"
+ - @incompatible_repos.each do |repo|
+ %tr{id: "repo_#{repo["owner"]}___#{repo["slug"]}"}
+ %td
+ = link_to "#{repo["owner"]}/#{repo["slug"]}", "https://bitbucket.org/#{repo["owner"]}/#{repo["slug"]}", target: "_blank"
+ %td.import-target
+ %td.import-actions-job-status
+ = label_tag "Incompatible Project", nil, class: "label label-danger"
- if @incompatible_repos.any?
%p
diff --git a/app/views/import/fogbugz/new_user_map.html.haml b/app/views/import/fogbugz/new_user_map.html.haml
index 25cebfb3665..a701e49ac56 100644
--- a/app/views/import/fogbugz/new_user_map.html.haml
+++ b/app/views/import/fogbugz/new_user_map.html.haml
@@ -25,22 +25,23 @@
of issues and comments (e.g. "By <a href="#">@johnsmith</a>"). It will also
associate and/or assign these issues and comments with the selected user.
- %table.table
- %thead
- %tr
- %th ID
- %th Name
- %th Email
- %th GitLab User
- %tbody
- - @user_map.each do |id, user|
+ .table-holder
+ %table.table
+ %thead
%tr
- %td= id
- %td= text_field_tag "users[#{id}][name]", user[:name], class: 'form-control'
- %td= text_field_tag "users[#{id}][email]", user[:email], class: 'form-control'
- %td
- = users_select_tag("users[#{id}][gitlab_user]", class: 'custom-form-control',
- scope: :all, email_user: true, selected: user[:gitlab_user])
+ %th ID
+ %th Name
+ %th Email
+ %th GitLab User
+ %tbody
+ - @user_map.each do |id, user|
+ %tr
+ %td= id
+ %td= text_field_tag "users[#{id}][name]", user[:name], class: 'form-control'
+ %td= text_field_tag "users[#{id}][email]", user[:email], class: 'form-control'
+ %td
+ = users_select_tag("users[#{id}][gitlab_user]", class: 'custom-form-control',
+ scope: :all, email_user: true, selected: user[:gitlab_user])
.form-actions
= submit_tag 'Continue to the next step', class: 'btn btn-create'
diff --git a/app/views/import/fogbugz/status.html.haml b/app/views/import/fogbugz/status.html.haml
index f179ece402d..beca6ab1423 100644
--- a/app/views/import/fogbugz/status.html.haml
+++ b/app/views/import/fogbugz/status.html.haml
@@ -14,38 +14,39 @@
%p
= button_tag 'Import all projects', class: 'btn btn-success js-import-all'
-%table.table.import-jobs
- %thead
- %tr
- %th From FogBugz
- %th To GitLab
- %th Status
- %tbody
- - @already_added_projects.each do |project|
- %tr{id: "project_#{project.id}", class: "#{project_status_css_class(project.import_status)}"}
- %td
- = project.import_source
- %td
- %strong= link_to project.path_with_namespace, [project.namespace.becomes(Namespace), project]
- %td.job-status
- - if project.import_status == 'finished'
- %span
- %i.fa.fa-check
- done
- - elsif project.import_status == 'started'
- %i.fa.fa-spinner.fa-spin
- started
- - else
- = project.human_import_status_name
+.table-holder
+ %table.table.import-jobs
+ %thead
+ %tr
+ %th From FogBugz
+ %th To GitLab
+ %th Status
+ %tbody
+ - @already_added_projects.each do |project|
+ %tr{id: "project_#{project.id}", class: "#{project_status_css_class(project.import_status)}"}
+ %td
+ = project.import_source
+ %td
+ %strong= link_to project.path_with_namespace, [project.namespace.becomes(Namespace), project]
+ %td.job-status
+ - if project.import_status == 'finished'
+ %span
+ %i.fa.fa-check
+ done
+ - elsif project.import_status == 'started'
+ %i.fa.fa-spinner.fa-spin
+ started
+ - else
+ = project.human_import_status_name
- - @repos.each do |repo|
- %tr{id: "repo_#{repo.id}"}
- %td
- = repo.name
- %td.import-target
- = "#{current_user.username}/#{repo.name}"
- %td.import-actions.job-status
- = button_tag "Import", class: "btn js-add-to-import"
+ - @repos.each do |repo|
+ %tr{id: "repo_#{repo.id}"}
+ %td
+ = repo.name
+ %td.import-target
+ = "#{current_user.username}/#{repo.name}"
+ %td.import-actions.job-status
+ = button_tag "Import", class: "btn js-add-to-import"
:coffeescript
new ImporterStatus("#{jobs_import_fogbugz_path}", "#{import_fogbugz_path}")
diff --git a/app/views/import/github/status.html.haml b/app/views/import/github/status.html.haml
index ef552498239..0669b05adca 100644
--- a/app/views/import/github/status.html.haml
+++ b/app/views/import/github/status.html.haml
@@ -9,38 +9,39 @@
%p
= button_tag 'Import all projects', class: "btn btn-success js-import-all"
-%table.table.import-jobs
- %thead
- %tr
- %th From GitHub
- %th To GitLab
- %th Status
- %tbody
- - @already_added_projects.each do |project|
- %tr{id: "project_#{project.id}", class: "#{project_status_css_class(project.import_status)}"}
- %td
- = link_to project.import_source, "https://github.com/#{project.import_source}", target: "_blank"
- %td
- %strong= link_to project.path_with_namespace, [project.namespace.becomes(Namespace), project]
- %td.job-status
- - if project.import_status == 'finished'
- %span
- %i.fa.fa-check
- done
- - elsif project.import_status == 'started'
- %i.fa.fa-spinner.fa-spin
- started
- - else
- = project.human_import_status_name
+.table-holder
+ %table.table.import-jobs
+ %thead
+ %tr
+ %th From GitHub
+ %th To GitLab
+ %th Status
+ %tbody
+ - @already_added_projects.each do |project|
+ %tr{id: "project_#{project.id}", class: "#{project_status_css_class(project.import_status)}"}
+ %td
+ = link_to project.import_source, "https://github.com/#{project.import_source}", target: "_blank"
+ %td
+ %strong= link_to project.path_with_namespace, [project.namespace.becomes(Namespace), project]
+ %td.job-status
+ - if project.import_status == 'finished'
+ %span
+ %i.fa.fa-check
+ done
+ - elsif project.import_status == 'started'
+ %i.fa.fa-spinner.fa-spin
+ started
+ - else
+ = project.human_import_status_name
- - @repos.each do |repo|
- %tr{id: "repo_#{repo.id}"}
- %td
- = link_to repo.full_name, "https://github.com/#{repo.full_name}", target: "_blank"
- %td.import-target
- = repo.full_name
- %td.import-actions.job-status
- = button_tag "Import", class: "btn js-add-to-import"
+ - @repos.each do |repo|
+ %tr{id: "repo_#{repo.id}"}
+ %td
+ = link_to repo.full_name, "https://github.com/#{repo.full_name}", target: "_blank"
+ %td.import-target
+ = repo.full_name
+ %td.import-actions.job-status
+ = button_tag "Import", class: "btn js-add-to-import"
:coffeescript
new ImporterStatus("#{jobs_import_github_path}", "#{import_github_path}")
diff --git a/app/views/import/gitlab/status.html.haml b/app/views/import/gitlab/status.html.haml
index 727f3c7e7fa..3bc85059e7d 100644
--- a/app/views/import/gitlab/status.html.haml
+++ b/app/views/import/gitlab/status.html.haml
@@ -9,38 +9,39 @@
%p
= button_tag 'Import all projects', class: "btn btn-success js-import-all"
-%table.table.import-jobs
- %thead
- %tr
- %th From GitLab.com
- %th To this GitLab instance
- %th Status
- %tbody
- - @already_added_projects.each do |project|
- %tr{id: "project_#{project.id}", class: "#{project_status_css_class(project.import_status)}"}
- %td
- = link_to project.import_source, "https://gitlab.com/#{project.import_source}", target: "_blank"
- %td
- %strong= link_to project.path_with_namespace, [project.namespace.becomes(Namespace), project]
- %td.job-status
- - if project.import_status == 'finished'
- %span
- %i.fa.fa-check
- done
- - elsif project.import_status == 'started'
- %i.fa.fa-spinner.fa-spin
- started
- - else
- = project.human_import_status_name
+.table-holder
+ %table.table.import-jobs
+ %thead
+ %tr
+ %th From GitLab.com
+ %th To this GitLab instance
+ %th Status
+ %tbody
+ - @already_added_projects.each do |project|
+ %tr{id: "project_#{project.id}", class: "#{project_status_css_class(project.import_status)}"}
+ %td
+ = link_to project.import_source, "https://gitlab.com/#{project.import_source}", target: "_blank"
+ %td
+ %strong= link_to project.path_with_namespace, [project.namespace.becomes(Namespace), project]
+ %td.job-status
+ - if project.import_status == 'finished'
+ %span
+ %i.fa.fa-check
+ done
+ - elsif project.import_status == 'started'
+ %i.fa.fa-spinner.fa-spin
+ started
+ - else
+ = project.human_import_status_name
- - @repos.each do |repo|
- %tr{id: "repo_#{repo["id"]}"}
- %td
- = link_to repo["path_with_namespace"], "https://gitlab.com/#{repo["path_with_namespace"]}", target: "_blank"
- %td.import-target
- = repo["path_with_namespace"]
- %td.import-actions.job-status
- = button_tag "Import", class: "btn js-add-to-import"
+ - @repos.each do |repo|
+ %tr{id: "repo_#{repo["id"]}"}
+ %td
+ = link_to repo["path_with_namespace"], "https://gitlab.com/#{repo["path_with_namespace"]}", target: "_blank"
+ %td.import-target
+ = repo["path_with_namespace"]
+ %td.import-actions.job-status
+ = button_tag "Import", class: "btn js-add-to-import"
:coffeescript
new ImporterStatus("#{jobs_import_gitlab_path}", "#{import_gitlab_path}")
diff --git a/app/views/import/gitorious/status.html.haml b/app/views/import/gitorious/status.html.haml
index bff7ee7c85d..2e3a535737f 100644
--- a/app/views/import/gitorious/status.html.haml
+++ b/app/views/import/gitorious/status.html.haml
@@ -9,38 +9,39 @@
%p
= button_tag 'Import all projects', class: "btn btn-success js-import-all"
-%table.table.import-jobs
- %thead
- %tr
- %th From Gitorious.org
- %th To GitLab
- %th Status
- %tbody
- - @already_added_projects.each do |project|
- %tr{id: "project_#{project.id}", class: "#{project_status_css_class(project.import_status)}"}
- %td
- = link_to project.import_source, "https://gitorious.org/#{project.import_source}", target: "_blank"
- %td
- %strong= link_to project.path_with_namespace, [project.namespace.becomes(Namespace), project]
- %td.job-status
- - if project.import_status == 'finished'
- %span
- %i.fa.fa-check
- done
- - elsif project.import_status == 'started'
- %i.fa.fa-spinner.fa-spin
- started
- - else
- = project.human_import_status_name
+.table-holder
+ %table.table.import-jobs
+ %thead
+ %tr
+ %th From Gitorious.org
+ %th To GitLab
+ %th Status
+ %tbody
+ - @already_added_projects.each do |project|
+ %tr{id: "project_#{project.id}", class: "#{project_status_css_class(project.import_status)}"}
+ %td
+ = link_to project.import_source, "https://gitorious.org/#{project.import_source}", target: "_blank"
+ %td
+ %strong= link_to project.path_with_namespace, [project.namespace.becomes(Namespace), project]
+ %td.job-status
+ - if project.import_status == 'finished'
+ %span
+ %i.fa.fa-check
+ done
+ - elsif project.import_status == 'started'
+ %i.fa.fa-spinner.fa-spin
+ started
+ - else
+ = project.human_import_status_name
- - @repos.each do |repo|
- %tr{id: "repo_#{repo.id}"}
- %td
- = link_to repo.full_name, "https://gitorious.org/#{repo.full_name}", target: "_blank"
- %td.import-target
- = repo.full_name
- %td.import-actions.job-status
- = button_tag "Import", class: "btn js-add-to-import"
+ - @repos.each do |repo|
+ %tr{id: "repo_#{repo.id}"}
+ %td
+ = link_to repo.full_name, "https://gitorious.org/#{repo.full_name}", target: "_blank"
+ %td.import-target
+ = repo.full_name
+ %td.import-actions.job-status
+ = button_tag "Import", class: "btn js-add-to-import"
:coffeescript
new ImporterStatus("#{jobs_import_gitorious_path}", "#{import_gitorious_path}")
diff --git a/app/views/import/google_code/status.html.haml b/app/views/import/google_code/status.html.haml
index e8ec79e72f7..c5af06edf87 100644
--- a/app/views/import/google_code/status.html.haml
+++ b/app/views/import/google_code/status.html.haml
@@ -17,45 +17,46 @@
- else
= button_tag 'Import all projects', class: "btn btn-success js-import-all"
-%table.table.import-jobs
- %thead
- %tr
- %th From Google Code
- %th To GitLab
- %th Status
- %tbody
- - @already_added_projects.each do |project|
- %tr{id: "project_#{project.id}", class: "#{project_status_css_class(project.import_status)}"}
- %td
- = link_to project.import_source, "https://code.google.com/p/#{project.import_source}", target: "_blank"
- %td
- %strong= link_to project.path_with_namespace, [project.namespace.becomes(Namespace), project]
- %td.job-status
- - if project.import_status == 'finished'
- %span
- %i.fa.fa-check
- done
- - elsif project.import_status == 'started'
- %i.fa.fa-spinner.fa-spin
- started
- - else
- = project.human_import_status_name
+.table-holder
+ %table.table.import-jobs
+ %thead
+ %tr
+ %th From Google Code
+ %th To GitLab
+ %th Status
+ %tbody
+ - @already_added_projects.each do |project|
+ %tr{id: "project_#{project.id}", class: "#{project_status_css_class(project.import_status)}"}
+ %td
+ = link_to project.import_source, "https://code.google.com/p/#{project.import_source}", target: "_blank"
+ %td
+ %strong= link_to project.path_with_namespace, [project.namespace.becomes(Namespace), project]
+ %td.job-status
+ - if project.import_status == 'finished'
+ %span
+ %i.fa.fa-check
+ done
+ - elsif project.import_status == 'started'
+ %i.fa.fa-spinner.fa-spin
+ started
+ - else
+ = project.human_import_status_name
- - @repos.each do |repo|
- %tr{id: "repo_#{repo.id}"}
- %td
- = link_to repo.name, "https://code.google.com/p/#{repo.name}", target: "_blank"
- %td.import-target
- = "#{current_user.username}/#{repo.name}"
- %td.import-actions.job-status
- = button_tag "Import", class: "btn js-add-to-import"
- - @incompatible_repos.each do |repo|
- %tr{id: "repo_#{repo.id}"}
- %td
- = link_to repo.name, "https://code.google.com/p/#{repo.name}", target: "_blank"
- %td.import-target
- %td.import-actions-job-status
- = label_tag "Incompatible Project", nil, class: "label label-danger"
+ - @repos.each do |repo|
+ %tr{id: "repo_#{repo.id}"}
+ %td
+ = link_to repo.name, "https://code.google.com/p/#{repo.name}", target: "_blank"
+ %td.import-target
+ = "#{current_user.username}/#{repo.name}"
+ %td.import-actions.job-status
+ = button_tag "Import", class: "btn js-add-to-import"
+ - @incompatible_repos.each do |repo|
+ %tr{id: "repo_#{repo.id}"}
+ %td
+ = link_to repo.name, "https://code.google.com/p/#{repo.name}", target: "_blank"
+ %td.import-target
+ %td.import-actions-job-status
+ = label_tag "Incompatible Project", nil, class: "label label-danger"
- if @incompatible_repos.any?
%p
diff --git a/app/views/layouts/_page.html.haml b/app/views/layouts/_page.html.haml
index 1a883e20e89..352b8040cf4 100644
--- a/app/views/layouts/_page.html.haml
+++ b/app/views/layouts/_page.html.haml
@@ -18,7 +18,7 @@
= render partial: 'layouts/collapse_button'
- if current_user
= link_to current_user, class: 'sidebar-user' do
- = image_tag avatar_icon(current_user.email, 60), alt: 'User activity', class: 'avatar avatar s36'
+ = image_tag avatar_icon(current_user, 60), alt: 'User activity', class: 'avatar avatar s36'
.username
= current_user.username
.content-wrapper
diff --git a/app/views/layouts/_search.html.haml b/app/views/layouts/_search.html.haml
index ceb64ce3157..d1aa8f62463 100644
--- a/app/views/layouts/_search.html.haml
+++ b/app/views/layouts/_search.html.haml
@@ -11,6 +11,8 @@
= hidden_field_tag :scope, 'merge_requests'
- elsif current_controller?(:wikis)
= hidden_field_tag :scope, 'wiki_blobs'
+ - elsif current_controller?(:commits)
+ = hidden_field_tag :scope, 'commits'
- else
= hidden_field_tag :search_code, true
diff --git a/app/views/layouts/ci/_page.html.haml b/app/views/layouts/ci/_page.html.haml
index bb5ec727bff..ab3e29c3f42 100644
--- a/app/views/layouts/ci/_page.html.haml
+++ b/app/views/layouts/ci/_page.html.haml
@@ -15,7 +15,7 @@
= render partial: 'layouts/collapse_button'
- if current_user
= link_to current_user, class: 'sidebar-user' do
- = image_tag avatar_icon(current_user.email, 60), alt: 'User activity', class: 'avatar avatar s36'
+ = image_tag avatar_icon(current_user, 60), alt: 'User activity', class: 'avatar avatar s36'
.username
= current_user.username
.content-wrapper
diff --git a/app/views/layouts/ci/project.html.haml b/app/views/layouts/ci/project.html.haml
deleted file mode 100644
index 15478c3f5bc..00000000000
--- a/app/views/layouts/ci/project.html.haml
+++ /dev/null
@@ -1,11 +0,0 @@
-!!! 5
-%html{ lang: "en"}
- = render 'layouts/head'
- %body{class: "ci-body #{user_application_theme}", 'data-page' => body_data_page}
- - header_title @project.name, ci_project_path(@project)
- - if current_user
- = render "layouts/header/default", title: header_title
- - else
- = render "layouts/header/public", title: header_title
-
- = render 'layouts/ci/page', sidebar: 'nav_project'
diff --git a/app/views/layouts/nav/_group.html.haml b/app/views/layouts/nav/_group.html.haml
index eb35af22b93..319352876b4 100644
--- a/app/views/layouts/nav/_group.html.haml
+++ b/app/views/layouts/nav/_group.html.haml
@@ -1,9 +1,9 @@
%ul.nav.nav-sidebar
= nav_link do
- = link_to root_path, title: 'Back to dashboard', data: {placement: 'right'}, class: 'back-link' do
+ = link_to root_path, title: 'Go to dashboard', data: {placement: 'right'}, class: 'back-link' do
= icon('caret-square-o-left fw')
%span
- Back to dashboard
+ Go to dashboard
%li.separate-item
diff --git a/app/views/layouts/nav/_group_settings.html.haml b/app/views/layouts/nav/_group_settings.html.haml
index 8075fe32fbc..c8411521f36 100644
--- a/app/views/layouts/nav/_group_settings.html.haml
+++ b/app/views/layouts/nav/_group_settings.html.haml
@@ -1,9 +1,9 @@
%ul.nav.nav-sidebar
= nav_link do
- = link_to group_path(@group), title: 'Back to group', data: {placement: 'right'}, class: 'back-link' do
+ = link_to group_path(@group), title: 'Go to group', data: {placement: 'right'}, class: 'back-link' do
= icon('caret-square-o-left fw')
%span
- Back to group
+ Go to group
%li.separate-item
diff --git a/app/views/layouts/nav/_profile.html.haml b/app/views/layouts/nav/_profile.html.haml
index 5a47b8e6db2..0f3a793e30b 100644
--- a/app/views/layouts/nav/_profile.html.haml
+++ b/app/views/layouts/nav/_profile.html.haml
@@ -1,9 +1,9 @@
%ul.nav.nav-sidebar
= nav_link do
- = link_to root_path, title: 'Back to dashboard', data: {placement: 'right'}, class: 'back-link' do
+ = link_to root_path, title: 'Go to dashboard', data: {placement: 'right'}, class: 'back-link' do
= icon('caret-square-o-left fw')
%span
- Back to dashboard
+ Go to dashboard
%li.separate-item
diff --git a/app/views/layouts/nav/_project.html.haml b/app/views/layouts/nav/_project.html.haml
index e4c285d8023..20db2866d1f 100644
--- a/app/views/layouts/nav/_project.html.haml
+++ b/app/views/layouts/nav/_project.html.haml
@@ -1,16 +1,16 @@
%ul.nav.nav-sidebar
- if @project.group
= nav_link do
- = link_to group_path(@project.group), title: 'Back to group', data: {placement: 'right'}, class: 'back-link' do
+ = link_to group_path(@project.group), title: 'Go to group', data: {placement: 'right'}, class: 'back-link' do
= icon('caret-square-o-left fw')
%span
- Back to group
+ Go to group
- else
= nav_link do
- = link_to root_path, title: 'Back to dashboard', data: {placement: 'right'}, class: 'back-link' do
+ = link_to root_path, title: 'Go to dashboard', data: {placement: 'right'}, class: 'back-link' do
= icon('caret-square-o-left fw')
%span
- Back to dashboard
+ Go to dashboard
%li.separate-item
@@ -32,12 +32,20 @@
Files
- if project_nav_tab? :commits
- = nav_link(controller: %w(commit commits compare repositories tags branches builds)) do
+ = nav_link(controller: %w(commit commits compare repositories tags branches)) do
= link_to project_commits_path(@project), title: 'Commits', class: 'shortcuts-commits', data: {placement: 'right'} do
= icon('history fw')
%span
Commits
+ - if project_nav_tab? :builds
+ = nav_link(controller: %w(builds)) do
+ = link_to project_builds_path(@project), title: 'Builds', class: 'shortcuts-builds', data: {placement: 'right'} do
+ = icon('cubes fw')
+ %span
+ Builds
+ %span.count.builds_counter= @project.ci_builds.running_or_pending.count(:all)
+
- if project_nav_tab? :network
= nav_link(controller: %w(network)) do
= link_to namespace_project_network_path(@project.namespace, @project, current_ref), title: 'Network', class: 'shortcuts-network', data: {placement: 'right'} do
diff --git a/app/views/layouts/nav/_project_settings.html.haml b/app/views/layouts/nav/_project_settings.html.haml
index 954dbe5d2b9..a59939ccd31 100644
--- a/app/views/layouts/nav/_project_settings.html.haml
+++ b/app/views/layouts/nav/_project_settings.html.haml
@@ -1,9 +1,9 @@
%ul.nav.nav-sidebar
= nav_link do
- = link_to project_path(@project), title: 'Back to project', data: {placement: 'right'}, class: 'back-link' do
+ = link_to project_path(@project), title: 'Go to project', data: {placement: 'right'}, class: 'back-link' do
= icon('caret-square-o-left fw')
%span
- Back to project
+ Go to project
%li.separate-item
@@ -65,8 +65,3 @@
= icon('share fw')
%span
CI Services
- = nav_link path: 'events#index' do
- = link_to ci_project_events_path(@project.gitlab_ci_project) do
- = icon('book fw')
- %span
- CI Events
diff --git a/app/views/layouts/notify.html.haml b/app/views/layouts/notify.html.haml
index 2f7d7e86f56..854cda57c39 100644
--- a/app/views/layouts/notify.html.haml
+++ b/app/views/layouts/notify.html.haml
@@ -41,4 +41,8 @@
#{link_to "view it on GitLab", @target_url}.
- else
#{link_to "View it on GitLab", @target_url}
+ %br
+ You're receiving this email because of your account on #{link_to Gitlab.config.gitlab.host, root_url}.
+ If you'd like to receive fewer emails, you can adjust your notification settings.
+
= email_action @target_url
diff --git a/app/views/notify/_note_message.html.haml b/app/views/notify/_note_message.html.haml
index 3fd4b04ac84..00cb4aa24cc 100644
--- a/app/views/notify/_note_message.html.haml
+++ b/app/views/notify/_note_message.html.haml
@@ -1,2 +1,2 @@
%div
- = markdown(@note.note, reference_only_path: false)
+ = markdown(@note.note, pipeline: :email)
diff --git a/app/views/notify/new_issue_email.html.haml b/app/views/notify/new_issue_email.html.haml
index 53a068be52e..d3b799fca23 100644
--- a/app/views/notify/new_issue_email.html.haml
+++ b/app/views/notify/new_issue_email.html.haml
@@ -1,5 +1,5 @@
-if @issue.description
- = markdown(@issue.description, reference_only_path: false)
+ = markdown(@issue.description, pipeline: :email)
- if @issue.assignee_id.present?
%p
diff --git a/app/views/notify/new_merge_request_email.html.haml b/app/views/notify/new_merge_request_email.html.haml
index 5b7dd117c16..90ebdfc3fe2 100644
--- a/app/views/notify/new_merge_request_email.html.haml
+++ b/app/views/notify/new_merge_request_email.html.haml
@@ -6,4 +6,4 @@
Assignee: #{@merge_request.author_name} &rarr; #{@merge_request.assignee_name}
-if @merge_request.description
- = markdown(@merge_request.description, reference_only_path: false)
+ = markdown(@merge_request.description, pipeline: :email)
diff --git a/app/views/profiles/_event_table.html.haml b/app/views/profiles/_event_table.html.haml
index c19ac429d52..58af79716a7 100644
--- a/app/views/profiles/_event_table.html.haml
+++ b/app/views/profiles/_event_table.html.haml
@@ -1,16 +1,17 @@
-%table.table#audits
- %thead
- %tr
- %th Action
- %th When
-
- %tbody
- - events.each do |event|
+.table-holder
+ %table.table#audits
+ %thead
%tr
- %td
- %span
- Signed in with
- %b= event.details[:with]
- authentication
- %td #{time_ago_in_words event.created_at} ago
+ %th Action
+ %th When
+
+ %tbody
+ - events.each do |event|
+ %tr
+ %td
+ %span
+ Signed in with
+ %b= event.details[:with]
+ authentication
+ %td #{time_ago_in_words event.created_at} ago
= paginate events, theme: "gitlab"
diff --git a/app/views/profiles/preferences/show.html.haml b/app/views/profiles/preferences/show.html.haml
index 01e285a8dfa..cc41d7dd813 100644
--- a/app/views/profiles/preferences/show.html.haml
+++ b/app/views/profiles/preferences/show.html.haml
@@ -38,7 +38,7 @@
.col-sm-10
= f.select :layout, layout_choices, {}, class: 'form-control'
.help-block
- Choose between fixed (max. 1200px) and fluid (100%) application layout
+ Choose between fixed (max. 1200px) and fluid (100%) application layout.
.form-group
= f.label :dashboard, class: 'control-label' do
Default Dashboard
@@ -52,6 +52,6 @@
.col-sm-10
= f.select :project_view, project_view_choices, {}, class: 'form-control'
.help-block
- Choose what content you want to see when visit project page
+ Choose what content you want to see on a project's home page.
.panel-footer
= f.submit 'Save', class: 'btn btn-save'
diff --git a/app/views/profiles/show.html.haml b/app/views/profiles/show.html.haml
index 47412e2ef0c..ac7355dde1f 100644
--- a/app/views/profiles/show.html.haml
+++ b/app/views/profiles/show.html.haml
@@ -68,7 +68,7 @@
.col-md-5
.light-well
- = image_tag avatar_icon(@user.email, 160), alt: '', class: 'avatar s160'
+ = image_tag avatar_icon(@user, 160), alt: '', class: 'avatar s160'
.clearfix
.profile-avatar-form-option
diff --git a/app/views/projects/_activity.html.haml b/app/views/projects/_activity.html.haml
index c2683bc6219..012858f70b4 100644
--- a/app/views/projects/_activity.html.haml
+++ b/app/views/projects/_activity.html.haml
@@ -1,4 +1,3 @@
-= render 'projects/last_push'
.gray-content-block.activity-filter-block
- if current_user
.pull-right
diff --git a/app/views/projects/_files.html.haml b/app/views/projects/_files.html.haml
new file mode 100644
index 00000000000..fa978325ddd
--- /dev/null
+++ b/app/views/projects/_files.html.haml
@@ -0,0 +1,6 @@
+#tree-holder.tree-holder.clearfix
+ .gray-content-block.second-block
+ = render 'projects/tree/tree_header', tree: @tree
+
+ = render 'projects/tree/tree_content', tree: @tree
+
diff --git a/app/views/projects/_last_commit.html.haml b/app/views/projects/_last_commit.html.haml
new file mode 100644
index 00000000000..d7b20bfc6b1
--- /dev/null
+++ b/app/views/projects/_last_commit.html.haml
@@ -0,0 +1,12 @@
+.project-last-commit
+ - ci_commit = project.ci_commit(commit.sha)
+ - if ci_commit
+ = link_to ci_status_path(ci_commit), class: "ci-status ci-#{ci_commit.status}" do
+ = ci_status_icon(ci_commit)
+ = ci_commit.status
+
+ = link_to commit.short_id, namespace_project_commit_path(project.namespace, project, commit), class: "commit_short_id"
+ = link_to_gfm commit.title, namespace_project_commit_path(project.namespace, project, commit.id), class: "commit-row-message"
+ &middot;
+ #{time_ago_with_tooltip(commit.committed_date, skip_js: true)} by
+ = commit_author_link(commit, avatar: true, size: 24)
diff --git a/app/views/projects/_md_preview.html.haml b/app/views/projects/_md_preview.html.haml
index 507757f6a2b..7b21095ea3e 100644
--- a/app/views/projects/_md_preview.html.haml
+++ b/app/views/projects/_md_preview.html.haml
@@ -2,10 +2,10 @@
.md-header.clearfix
%ul.center-top-menu
%li.active
- = link_to '#md-write-holder', class: 'js-md-write-button', tabindex: '-1' do
+ %a.js-md-write-button(href="#md-write-holder" tabindex="-1")
Write
%li
- = link_to '#md-preview-holder', class: 'js-md-preview-button', tabindex: '-1' do
+ %a.js-md-preview-button(href="md-preview-holder" tabindex="-1")
Preview
- if defined?(referenced_users) && referenced_users
diff --git a/app/views/projects/_readme.html.haml b/app/views/projects/_readme.html.haml
index 5bc1999ec9d..b5ef0aca540 100644
--- a/app/views/projects/_readme.html.haml
+++ b/app/views/projects/_readme.html.haml
@@ -1,12 +1,9 @@
- if readme = @repository.readme
- %article.readme-holder#README
- .clearfix
- .pull-right
- &nbsp;
- - if can?(current_user, :push_code, @project)
- = link_to namespace_project_edit_blob_path(@project.namespace, @project, tree_join(@repository.root_ref, readme.name)), class: 'light' do
- %i.fa-align.fa.fa-pencil
- .wiki
+ %article.readme-holder
+ .pull-right
+ - if can?(current_user, :push_code, @project)
+ = link_to icon('pencil'), namespace_project_edit_blob_path(@project.namespace, @project, tree_join(@repository.root_ref, readme.name)), class: 'light edit-project-readme'
+ .file-content.wiki
= cache(readme_cache_key) do
= render_readme(readme)
- else
diff --git a/app/views/projects/_zen.html.haml b/app/views/projects/_zen.html.haml
index 6a41cdbc907..63ebfc9381f 100644
--- a/app/views/projects/_zen.html.haml
+++ b/app/views/projects/_zen.html.haml
@@ -1,10 +1,10 @@
.zennable
- %input#zen-toggle-comment.zen-toggle-comment{ tabindex: '-1', type: 'checkbox' }
+ %input#zen-toggle-comment.zen-toggle-comment(tabindex="-1" type="checkbox")
.zen-backdrop
- classes << ' js-gfm-input markdown-area'
= f.text_area attr, class: classes, placeholder: ''
- = link_to nil, class: 'zen-enter-link', tabindex: '-1' do
+ %a.zen-enter-link(tabindex="-1" href="#")
%i.fa.fa-expand
Edit in fullscreen
- = link_to nil, class: 'zen-leave-link' do
+ %a.zen-leave-link(href="#")
%i.fa.fa-compress
diff --git a/app/views/projects/activity.html.haml b/app/views/projects/activity.html.haml
index 555ed76426d..69fa4ad37c4 100644
--- a/app/views/projects/activity.html.haml
+++ b/app/views/projects/activity.html.haml
@@ -1,4 +1,6 @@
- page_title "Activity"
- header_title project_title(@project, "Activity", activity_project_path(@project))
+= render 'projects/last_push'
+
= render 'projects/activity'
diff --git a/app/views/projects/blob/_blob.html.haml b/app/views/projects/blob/_blob.html.haml
index a1ae1397584..42f632b38ef 100644
--- a/app/views/projects/blob/_blob.html.haml
+++ b/app/views/projects/blob/_blob.html.haml
@@ -1,19 +1,22 @@
-%ul.breadcrumb.repo-breadcrumb
- %li
- %i.fa.fa-angle-right
- = link_to namespace_project_tree_path(@project.namespace, @project, @ref) do
- = @project.path
- - tree_breadcrumbs(@tree, 6) do |title, path|
+.gray-content-block.top-block
+ .tree-ref-holder
+ = render 'shared/ref_switcher', destination: 'blob', path: @path
+
+ %ul.breadcrumb.repo-breadcrumb
%li
- - if path
- - if path.end_with?(@path)
- = link_to namespace_project_blob_path(@project.namespace, @project, path) do
- %strong
- = truncate(title, length: 40)
+ = link_to namespace_project_tree_path(@project.namespace, @project, @ref) do
+ = @project.path
+ - tree_breadcrumbs(@tree, 6) do |title, path|
+ %li
+ - if path
+ - if path.end_with?(@path)
+ = link_to namespace_project_blob_path(@project.namespace, @project, path) do
+ %strong
+ = truncate(title, length: 40)
+ - else
+ = link_to truncate(title, length: 40), namespace_project_tree_path(@project.namespace, @project, path)
- else
- = link_to truncate(title, length: 40), namespace_project_tree_path(@project.namespace, @project, path)
- - else
- = link_to title, '#'
+ = link_to title, '#'
%ul.blob-commit-info.hidden-xs
- blob_commit = @repository.last_commit_for_path(@commit.id, blob.path)
diff --git a/app/views/projects/blob/show.html.haml b/app/views/projects/blob/show.html.haml
index fa4be4a1bc4..f52b89f6921 100644
--- a/app/views/projects/blob/show.html.haml
+++ b/app/views/projects/blob/show.html.haml
@@ -3,9 +3,6 @@
= render 'projects/last_push'
-%div.tree-ref-holder
- = render 'shared/ref_switcher', destination: 'blob', path: @path
-
%div#tree-holder.tree-holder
= render 'blob', blob: @blob
diff --git a/app/views/projects/builds/_build.html.haml b/app/views/projects/builds/_build.html.haml
new file mode 100644
index 00000000000..4ce4ed63b40
--- /dev/null
+++ b/app/views/projects/builds/_build.html.haml
@@ -0,0 +1,53 @@
+%tr.build
+ %td.status
+ = ci_status_with_icon(build.status)
+
+ %td.commit_status-link
+ - if build.target_url
+ = link_to build.target_url do
+ %strong Build ##{build.id}
+ - else
+ %strong Build ##{build.id}
+
+ - if build.show_warning?
+ %i.fa.fa-warning.text-warning
+
+ %td
+ = link_to build.short_sha, namespace_project_commit_path(@project.namespace, @project, build.sha)
+
+ %td
+ = link_to build.ref, namespace_project_commits_path(@project.namespace, @project, build.ref)
+
+ %td
+ - if build.runner
+ = runner_link(build.runner)
+ - else
+ .light none
+
+ %td
+ = build.name
+
+ .pull-right
+ - if build.tags.any?
+ - build.tags.each do |tag|
+ %span.label.label-primary
+ = tag
+ - if build.trigger_request
+ %span.label.label-info triggered
+ - if build.allow_failure
+ %span.label.label-danger allowed to fail
+
+ %td.duration
+ - if build.duration
+ #{duration_in_words(build.finished_at, build.started_at)}
+
+ %td.timestamp
+ - if build.finished_at
+ %span #{time_ago_in_words build.finished_at} ago
+
+ %td
+ .pull-right
+ - if current_user && can?(current_user, :manage_builds, @project)
+ - if build.cancel_url
+ = link_to build.cancel_url, title: 'Cancel' do
+ %i.fa.fa-remove.cred
diff --git a/app/views/projects/builds/index.html.haml b/app/views/projects/builds/index.html.haml
new file mode 100644
index 00000000000..e08556673ed
--- /dev/null
+++ b/app/views/projects/builds/index.html.haml
@@ -0,0 +1,53 @@
+- page_title "Builds"
+- header_title project_title(@project, "Builds", project_builds_path(@project))
+
+.project-issuable-filter
+ .controls
+ - if @ci_project && current_user && can?(current_user, :manage_builds, @project)
+ .pull-left.hidden-xs
+ - if @all_builds.running_or_pending.any?
+ = link_to 'Cancel all', cancel_all_namespace_project_builds_path(@project.namespace, @project), data: { confirm: 'Are you sure?' }, class: 'btn btn-danger'
+
+ %ul.center-top-menu
+ %li{class: ('active' if @scope.nil?)}
+ = link_to project_builds_path(@project) do
+ Running
+ %span.badge.js-running-count= @all_builds.running_or_pending.count(:id)
+
+ %li{class: ('active' if @scope == 'finished')}
+ = link_to project_builds_path(@project, scope: :finished) do
+ Finished
+ %span.badge.js-running-count= @all_builds.finished.count(:id)
+
+ %li{class: ('active' if @scope == 'all')}
+ = link_to project_builds_path(@project, scope: :all) do
+ All
+ %span.badge.js-totalbuilds-count= @all_builds.count(:id)
+
+.gray-content-block
+ List of #{@scope || 'running'} builds from this project
+
+%ul.content-list
+ - if @builds.blank?
+ %li
+ .nothing-here-block No builds to show
+ - else
+ .table-holder
+ %table.table.builds
+ %thead
+ %tr
+ %th Status
+ %th Build ID
+ %th Commit
+ %th Ref
+ %th Runner
+ %th Name
+ %th Duration
+ %th Finished at
+ %th
+
+ - @builds.each do |build|
+ = render 'projects/builds/build', build: build
+
+ = paginate @builds
+
diff --git a/app/views/projects/builds/show.html.haml b/app/views/projects/builds/show.html.haml
index 9c3ae622b72..e3d8d734913 100644
--- a/app/views/projects/builds/show.html.haml
+++ b/app/views/projects/builds/show.html.haml
@@ -25,7 +25,7 @@
%a
Build ##{@build.id}
&middot;
- %i.fa.fa-warning-sign
+ %i.fa.fa-warning
This build was retried.
.gray-content-block.second-block
@@ -39,6 +39,25 @@
.pull-right
= @build.updated_at.stamp('19:00 Aug 27')
+ - if @build.show_warning?
+ - unless @build.any_runners_online?
+ .bs-callout.bs-callout-warning
+ %p
+ - if no_runners_for_project?(@build.project)
+ This build is stuck, because the project doesn't have any runners online assigned to it.
+ - elsif @build.tags.any?
+ This build is stuck, because you don't have any active runners online with any of these tags assigned to them:
+ - @build.tags.each do |tag|
+ %span.label.label-primary
+ = tag
+ - else
+ This build is stuck, because you don't have any active runners that can run this build.
+
+ %br
+ Go to
+ = link_to namespace_project_runners_path(@build.gl_project.namespace, @build.gl_project) do
+ Runners page
+
.row.prepend-top-default
.col-md-9
.clearfix
@@ -136,7 +155,7 @@
- if @builds.present?
.build-widget
- %h4.title #{pluralize(@builds.count, "other build")} for #{@build.short_sha}:
+ %h4.title #{pluralize(@builds.count(:id), "other build")} for #{@build.short_sha}:
%table.table.builds
- @builds.each_with_index do |build, i|
%tr.build
@@ -156,4 +175,4 @@
:javascript
- new CiBuild("#{namespace_project_build_path(@project.namespace, @project, @build)}", "#{@build.status}")
+ new CiBuild("#{namespace_project_build_url(@project.namespace, @project, @build)}", "#{@build.status}")
diff --git a/app/views/projects/buttons/_dropdown.html.haml b/app/views/projects/buttons/_dropdown.html.haml
index 4580c912692..bed2b16249e 100644
--- a/app/views/projects/buttons/_dropdown.html.haml
+++ b/app/views/projects/buttons/_dropdown.html.haml
@@ -21,6 +21,10 @@
- if can?(current_user, :push_code, @project)
%li.divider
%li
+ = link_to namespace_project_new_blob_path(@project.namespace, @project, @project.default_branch || 'master'), title: 'New file' do
+ = icon('file fw')
+ New file
+ %li
= link_to new_namespace_project_branch_path(@project.namespace, @project) do
= icon('code-fork fw')
New branch
diff --git a/app/views/projects/buttons/_notifications.html.haml b/app/views/projects/buttons/_notifications.html.haml
index 3bc2daeec4e..3e83ec3912f 100644
--- a/app/views/projects/buttons/_notifications.html.haml
+++ b/app/views/projects/buttons/_notifications.html.haml
@@ -1,14 +1,20 @@
-- return unless @membership
+- case @membership
+- when ProjectMember
+ = form_tag profile_notifications_path, method: :put, remote: true, class: 'inline', id: 'notification-form' do
+ = hidden_field_tag :notification_type, 'project'
+ = hidden_field_tag :notification_id, @membership.id
+ = hidden_field_tag :notification_level
+ %span.dropdown
+ %a.dropdown-new.btn.notifications-btn#notifications-button{href: '#', "data-toggle" => "dropdown"}
+ = icon('bell')
+ = notification_label(@membership)
+ = icon('angle-down')
+ %ul.dropdown-menu.dropdown-menu-right.project-home-dropdown
+ - Notification.project_notification_levels.each do |level|
+ = notification_list_item(level, @membership)
-= form_tag profile_notifications_path, method: :put, remote: true, class: 'inline', id: 'notification-form' do
- = hidden_field_tag :notification_type, 'project'
- = hidden_field_tag :notification_id, @membership.id
- = hidden_field_tag :notification_level
- %span.dropdown
- %a.dropdown-new.btn.btn-new#notifications-button{href: '#', "data-toggle" => "dropdown"}
- = icon('bell')
- = notification_label(@membership)
- = icon('angle-down')
- %ul.dropdown-menu.dropdown-menu-right.project-home-dropdown
- - Notification.project_notification_levels.each do |level|
- = notification_list_item(level, @membership)
+- when GroupMember
+ .btn.disabled.notifications-btn.has_tooltip{title: "To change the notification level, you need to be a member of the project itself, not only its group."}
+ = icon('bell')
+ = notification_label(@membership)
+ = icon('angle-down')
diff --git a/app/views/projects/ci_services/index.html.haml b/app/views/projects/ci_services/index.html.haml
index c78b21884a3..c164b2d4bc0 100644
--- a/app/views/projects/ci_services/index.html.haml
+++ b/app/views/projects/ci_services/index.html.haml
@@ -6,7 +6,7 @@
%tr
%th
%th Service
- %th Desription
+ %th Description
%th Last edit
- @services.sort_by(&:title).each do |service|
%tr
diff --git a/app/views/projects/ci_settings/_no_runners.html.haml b/app/views/projects/ci_settings/_no_runners.html.haml
index 33038c52978..1374e6680f9 100644
--- a/app/views/projects/ci_settings/_no_runners.html.haml
+++ b/app/views/projects/ci_settings/_no_runners.html.haml
@@ -5,4 +5,4 @@
You can add Specific runner for this project on Runners page
- if current_user.admin
- or add Shared runner for whole application in admin are.
+ or add Shared runner for whole application in admin area.
diff --git a/app/views/projects/ci_web_hooks/index.html.haml b/app/views/projects/ci_web_hooks/index.html.haml
index 6aebd7cfc4d..369086b39ed 100644
--- a/app/views/projects/ci_web_hooks/index.html.haml
+++ b/app/views/projects/ci_web_hooks/index.html.haml
@@ -20,17 +20,18 @@
-if @web_hooks.any?
%h4 Activated web hooks (#{@web_hooks.count})
- %table.table
- - @web_hooks.each do |hook|
- %tr
- %td
- .clearfix
- %span.monospace= hook.url
- %td
- .pull-right
- - if @ci_project.commits.any?
- = link_to 'Test Hook', test_namespace_project_ci_web_hook_path(@project.namespace, @project, hook), class: "btn btn-sm btn-grouped"
- = link_to 'Remove', namespace_project_ci_web_hook_path(@project.namespace, @project, hook), data: { confirm: 'Are you sure?'}, method: :delete, class: "btn btn-remove btn-sm btn-grouped"
+ .table-holder
+ %table.table
+ - @web_hooks.each do |hook|
+ %tr
+ %td
+ .clearfix
+ %span.monospace= hook.url
+ %td
+ .pull-right
+ - if @ci_project.commits.any?
+ = link_to 'Test Hook', test_namespace_project_ci_web_hook_path(@project.namespace, @project, hook), class: "btn btn-sm btn-grouped"
+ = link_to 'Remove', namespace_project_ci_web_hook_path(@project.namespace, @project, hook), data: { confirm: 'Are you sure?'}, method: :delete, class: "btn btn-remove btn-sm btn-grouped"
%h4 Web Hook data example
diff --git a/app/views/projects/commit/ci.html.haml b/app/views/projects/commit/ci.html.haml
index 4a1ef378a30..43033cad24c 100644
--- a/app/views/projects/commit/ci.html.haml
+++ b/app/views/projects/commit/ci.html.haml
@@ -3,11 +3,6 @@
= render "commit_box"
= render "ci_menu"
-- if @ci_project && current_user && can?(current_user, :manage_builds, @project)
- .pull-right
- - if @ci_commit.builds.running_or_pending.any?
- = link_to "Cancel", cancel_builds_namespace_project_commit_path(@project.namespace, @project, @commit.sha), class: 'btn btn-sm btn-danger'
-
- if @ci_commit.yaml_errors.present?
.bs-callout.bs-callout-danger
@@ -22,31 +17,19 @@
.gray-content-block.second-block
Latest builds
- - if @ci_commit.duration > 0
- %small.pull-right
+
+ .pull-right
+ - if @ci_commit.duration > 0
%i.fa.fa-time
#{time_interval_in_words @ci_commit.duration}
-%table.table.builds
- %thead
- %tr
- %th Status
- %th Build ID
- %th Ref
- %th Stage
- %th Name
- %th Duration
- %th Finished at
- - if @ci_project && @ci_project.coverage_enabled?
- %th Coverage
- %th
- - @ci_commit.refs.each do |ref|
- = render partial: "projects/commit_statuses/commit_status", collection: @ci_commit.statuses.for_ref(ref).latest.ordered, coverage: @ci_project.try(:coverage_enabled?), controls: true
+ &nbsp;
-- if @ci_commit.retried.any?
- .gray-content-block.second-block
- Retried builds
+ - if @ci_project && current_user && can?(current_user, :manage_builds, @project)
+ - if @ci_commit.builds.running_or_pending.any?
+ = link_to "Cancel all", cancel_builds_namespace_project_commit_path(@project.namespace, @project, @commit.sha), class: 'btn btn-xs btn-danger'
+.table-holder
%table.table.builds
%thead
%tr
@@ -60,4 +43,27 @@
- if @ci_project && @ci_project.coverage_enabled?
%th Coverage
%th
- = render partial: "projects/commit_statuses/commit_status", collection: @ci_commit.retried, coverage: @ci_project.try(:coverage_enabled?)
+ - @ci_commit.refs.each do |ref|
+ = render partial: "projects/commit_statuses/commit_status", collection: @ci_commit.statuses.for_ref(ref).latest.ordered,
+ locals: { coverage: @ci_project.try(:coverage_enabled?), allow_retry: true }
+
+- if @ci_commit.retried.any?
+ .gray-content-block.second-block
+ Retried builds
+
+ .table-holder
+ %table.table.builds
+ %thead
+ %tr
+ %th Status
+ %th Build ID
+ %th Ref
+ %th Stage
+ %th Name
+ %th Duration
+ %th Finished at
+ - if @ci_project && @ci_project.coverage_enabled?
+ %th Coverage
+ %th
+ = render partial: "projects/commit_statuses/commit_status", collection: @ci_commit.retried,
+ locals: { coverage: @ci_project.try(:coverage_enabled?) }
diff --git a/app/views/projects/commit_statuses/_commit_status.html.haml b/app/views/projects/commit_statuses/_commit_status.html.haml
index e3a17faf0bd..637154f56aa 100644
--- a/app/views/projects/commit_statuses/_commit_status.html.haml
+++ b/app/views/projects/commit_statuses/_commit_status.html.haml
@@ -9,6 +9,9 @@
- else
%strong Build ##{commit_status.id}
+ - if commit_status.show_warning?
+ %i.fa.fa-warning.text-warning
+
%td
= commit_status.ref
@@ -41,11 +44,11 @@
#{commit_status.coverage}%
%td
- - if defined?(controls) && controls && current_user && can?(current_user, :manage_builds, gl_project)
- .pull-right
+ .pull-right
+ - if current_user && can?(current_user, :manage_builds, commit_status.gl_project)
- if commit_status.cancel_url
= link_to commit_status.cancel_url, title: 'Cancel' do
%i.fa.fa-remove.cred
- - elsif commit_status.retry_url
+ - elsif defined?(allow_retry) && allow_retry && commit_status.retry_url
= link_to commit_status.retry_url, method: :post, title: 'Retry' do
%i.fa.fa-repeat
diff --git a/app/views/projects/commits/_commit.html.haml b/app/views/projects/commits/_commit.html.haml
index cddd5aa3a83..805be332e64 100644
--- a/app/views/projects/commits/_commit.html.haml
+++ b/app/views/projects/commits/_commit.html.haml
@@ -18,10 +18,10 @@
.pull-right
- if ci_commit
- = link_to ci_status_path(ci_commit), class: "c#{ci_status_color(ci_commit)}" do
- = ci_status_icon(ci_commit)
+ = render_ci_status(ci_commit)
&nbsp;
- = link_to commit.short_id, namespace_project_commit_path(project.namespace, project, commit), class: "commit_short_id"
+ = clipboard_button
+ = link_to commit.short_id, namespace_project_commit_path(project.namespace, project, commit), class: "commit_short_id", data: {clipboard_text: commit.id}
.notes_count
- if note_count > 0
diff --git a/app/views/projects/diffs/_diffs.html.haml b/app/views/projects/diffs/_diffs.html.haml
index 4f1965bfb39..56b51f038ba 100644
--- a/app/views/projects/diffs/_diffs.html.haml
+++ b/app/views/projects/diffs/_diffs.html.haml
@@ -15,8 +15,8 @@
.files
- diff_files.each_with_index do |diff_file, index|
- - diff_commit = commit_for_diff(diff_file.diff)
- - blob = project.repository.blob_for_diff(diff_commit, diff_file.diff)
+ - diff_commit = commit_for_diff(diff_file)
+ - blob = project.repository.blob_for_diff(diff_commit, diff_file)
- next unless blob
= render 'projects/diffs/file', i: index, project: project,
diff --git a/app/views/projects/diffs/_file.html.haml b/app/views/projects/diffs/_file.html.haml
index 9698921f6da..410ff6abb43 100644
--- a/app/views/projects/diffs/_file.html.haml
+++ b/app/views/projects/diffs/_file.html.haml
@@ -1,5 +1,5 @@
.diff-file{id: "diff-#{i}", data: diff_file_html_data(project, diff_commit, diff_file)}
- .diff-header{id: "file-path-#{hexdigest(diff_file.new_path || diff_file.old_path)}"}
+ .diff-header{id: "file-path-#{hexdigest(diff_file.file_path)}"}
- if diff_file.diff.submodule?
%span
- submodule_item = project.repository.blob_at(@commit.id, diff_file.file_path)
@@ -38,7 +38,7 @@
- else
= render "projects/diffs/text_file", diff_file: diff_file, index: i
- elsif blob.image?
- - old_file = project.repository.prev_blob_for_diff(@commit, diff_file)
+ - old_file = project.repository.prev_blob_for_diff(diff_commit, diff_file)
= render "projects/diffs/image", diff_file: diff_file, old_file: old_file, file: blob, index: i
- else
.nothing-here-block No preview for this file type
diff --git a/app/views/projects/edit.html.haml b/app/views/projects/edit.html.haml
index 1882a82fba5..afbf88b5507 100644
--- a/app/views/projects/edit.html.haml
+++ b/app/views/projects/edit.html.haml
@@ -189,6 +189,21 @@
- else
.nothing-here-block Only the project owner can transfer a project
+ - if @project.forked?
+ - if can?(current_user, :remove_fork_project, @project)
+ = form_for([@project.namespace.becomes(Namespace), @project], url: remove_fork_namespace_project_path(@project.namespace, @project), method: :delete, remote: true, html: { class: 'transfer-project form-horizontal' }) do |f|
+ .panel.panel-default.panel.panel-danger
+ .panel-heading Remove fork relationship
+ .panel-body
+ %p
+ This will remove the fork relationship to source project
+ #{link_to @project.forked_from_project.name_with_namespace, project_path(@project.forked_from_project)}.
+ %br
+ %strong Once removed, the fork relationship cannot be restored and you will no longer be able to send merge requests to the source.
+ = button_to 'Remove fork relationship', '#', class: "btn btn-remove js-confirm-danger", data: { "confirm-danger-message" => remove_fork_project_message(@project) }
+ - else
+ .nothing-here-block Only the project owner can remove the fork relationship.
+
- if can?(current_user, :remove_project, @project)
.panel.panel-default.panel.panel-danger
.panel-heading Remove project
@@ -201,7 +216,8 @@
= button_to 'Remove project', '#', class: "btn btn-remove js-confirm-danger", data: { "confirm-danger-message" => remove_project_message(@project) }
- else
- .nothing-here-block Only project owner can remove a project
+ .nothing-here-block Only the project owner can remove a project.
+
.save-project-loader.hide
.center
diff --git a/app/views/projects/empty.html.haml b/app/views/projects/empty.html.haml
index e06454fd148..c3858e78cad 100644
--- a/app/views/projects/empty.html.haml
+++ b/app/views/projects/empty.html.haml
@@ -2,53 +2,56 @@
- if current_user && can?(current_user, :download_code, @project)
= render 'shared/no_ssh'
= render 'shared/no_password'
-
+
= render "home_panel"
.gray-content-block.center
%h3.page-title
The repository for this project is empty
- %p
- If you already have files you can push them using command line instructions below.
- %br
- Otherwise you can start with
- = link_to "adding README", new_readme_path, class: 'underlined-link'
- file to this project.
+ - if can?(current_user, :download_code, @project)
+ %p
+ If you already have files you can push them using command line instructions below.
+ %br
+ - if can?(current_user, :push_code, @project)
+ Otherwise you can start with
+ = link_to "adding README", new_readme_path, class: 'underlined-link'
+ file to this project.
-.prepend-top-20
-.empty_wrapper
- %h3.page-title-empty
- Command line instructions
- %div.git-empty
- %fieldset
- %h5 Git global setup
- %pre.light-well
- :preserve
- git config --global user.name "#{h git_user_name}"
- git config --global user.email "#{h git_user_email}"
+- if can?(current_user, :download_code, @project)
+ .prepend-top-20
+ .empty_wrapper
+ %h3.page-title-empty
+ Command line instructions
+ %div.git-empty
+ %fieldset
+ %h5 Git global setup
+ %pre.light-well
+ :preserve
+ git config --global user.name "#{h git_user_name}"
+ git config --global user.email "#{h git_user_email}"
- %fieldset
- %h5 Create a new repository
- %pre.light-well
- :preserve
- git clone #{ content_tag(:span, default_url_to_repo, class: 'clone')}
- cd #{h @project.path}
- touch README.md
- git add README.md
- git commit -m "add README"
- git push -u origin master
+ %fieldset
+ %h5 Create a new repository
+ %pre.light-well
+ :preserve
+ git clone #{ content_tag(:span, default_url_to_repo, class: 'clone')}
+ cd #{h @project.path}
+ touch README.md
+ git add README.md
+ git commit -m "add README"
+ git push -u origin master
- %fieldset
- %h5 Existing folder or Git repository
- %pre.light-well
- :preserve
- cd existing_folder
- git init
- git remote add origin #{ content_tag(:span, default_url_to_repo, class: 'clone')}
- git add .
- git commit
- git push -u origin master
+ %fieldset
+ %h5 Existing folder or Git repository
+ %pre.light-well
+ :preserve
+ cd existing_folder
+ git init
+ git remote add origin #{ content_tag(:span, default_url_to_repo, class: 'clone')}
+ git add .
+ git commit
+ git push -u origin master
- - if can? current_user, :remove_project, @project
- .prepend-top-20
- = link_to 'Remove project', [@project.namespace.becomes(Namespace), @project], data: { confirm: remove_project_message(@project)}, method: :delete, class: "btn btn-remove pull-right"
+ - if can? current_user, :remove_project, @project
+ .prepend-top-20
+ = link_to 'Remove project', [@project.namespace.becomes(Namespace), @project], data: { confirm: remove_project_message(@project)}, method: :delete, class: "btn btn-remove pull-right"
diff --git a/app/views/projects/imports/new.html.haml b/app/views/projects/imports/new.html.haml
index f8f2e192e29..92a87690c54 100644
--- a/app/views/projects/imports/new.html.haml
+++ b/app/views/projects/imports/new.html.haml
@@ -17,6 +17,6 @@
This URL must be publicly accessible or you can add a username and password like this: https://username:password@gitlab.com/company/project.git.
%br
The import will time out after 4 minutes. For big repositories, use a clone/push combination.
- For SVN repositories, check #{link_to "this migrating from SVN doc.", "http://doc.gitlab.com/ce/workflow/migrating_from_svn.html"}
+ For SVN repositories, check #{link_to "this migrating from SVN doc.", "http://doc.gitlab.com/ce/workflow/importing/migrating_from_svn.html"}
.form-actions
= f.submit 'Start import', class: "btn btn-create", tabindex: 4
diff --git a/app/views/projects/issues/_closed_by_box.html.haml b/app/views/projects/issues/_closed_by_box.html.haml
new file mode 100644
index 00000000000..aef352029d0
--- /dev/null
+++ b/app/views/projects/issues/_closed_by_box.html.haml
@@ -0,0 +1,3 @@
+.issue-closed-by-widget
+ = icon('check')
+ This issue will be closed automatically when merge request #{gfm(merge_requests_sentence(@closed_by_merge_requests.sort))} is accepted.
diff --git a/app/views/projects/issues/_discussion.html.haml b/app/views/projects/issues/_discussion.html.haml
index d4a98eca473..c5fd863ae99 100644
--- a/app/views/projects/issues/_discussion.html.haml
+++ b/app/views/projects/issues/_discussion.html.haml
@@ -17,8 +17,10 @@
- @participants.each do |participant|
= link_to_member(@project, participant, name: false, size: 24)
.col-md-3
- %span.slead.has_tooltip{title: 'Cross-project reference'}
- = cross_project_reference(@project, @issue)
+ .input-group.cross-project-reference
+ %span.slead.has_tooltip{title: 'Cross-project reference'}
+ = cross_project_reference(@project, @issue)
+ = clipboard_button
.row
%section.col-md-9
diff --git a/app/views/projects/issues/_issues.html.haml b/app/views/projects/issues/_issues.html.haml
index a3399c57aa2..ca5b1a8386d 100644
--- a/app/views/projects/issues/_issues.html.haml
+++ b/app/views/projects/issues/_issues.html.haml
@@ -5,8 +5,9 @@
.nothing-here-block No issues to show
- if @issues.present?
- .pull-right
- %span.issue_counter #{@issues.total_count}
- issues for this filter
+ .issuable-filter-count
+ %span.pull-right
+ = @issues.total_count
+ issues for this filter
= paginate @issues, theme: "gitlab"
diff --git a/app/views/projects/issues/show.html.haml b/app/views/projects/issues/show.html.haml
index 5cb814c9ea8..f01bf2505da 100644
--- a/app/views/projects/issues/show.html.haml
+++ b/app/views/projects/issues/show.html.haml
@@ -46,6 +46,7 @@
= markdown(@issue.description)
%textarea.hidden.js-task-list-field
= @issue.description
-
+ - if @closed_by_merge_requests.present?
+ = render 'projects/issues/closed_by_box'
.issue-discussion
= render 'projects/issues/discussion'
diff --git a/app/views/projects/labels/destroy.js.haml b/app/views/projects/labels/destroy.js.haml
index 1b4c83ab097..d59563b122a 100644
--- a/app/views/projects/labels/destroy.js.haml
+++ b/app/views/projects/labels/destroy.js.haml
@@ -1,2 +1,2 @@
- if @project.labels.size == 0
- $('.labels').load(document.URL + ' .light-well').hide().fadeIn(1000)
+ $('.labels').load(document.URL + ' .nothing-here-block').hide().fadeIn(1000)
diff --git a/app/views/projects/labels/index.html.haml b/app/views/projects/labels/index.html.haml
index 97175f8232b..fb784ee5f4f 100644
--- a/app/views/projects/labels/index.html.haml
+++ b/app/views/projects/labels/index.html.haml
@@ -14,8 +14,8 @@
= render @labels
= paginate @labels, theme: 'gitlab'
- else
- .light-well
+ .nothing-here-block
- if can? current_user, :admin_label, @project
- .nothing-here-block Create first label or #{link_to 'generate', generate_namespace_project_labels_path(@project.namespace, @project), method: :post} default set of labels
+ Create first label or #{link_to 'generate', generate_namespace_project_labels_path(@project.namespace, @project), method: :post} default set of labels
- else
- .nothing-here-block No labels created
+ No labels created
diff --git a/app/views/projects/merge_requests/_merge_request.html.haml b/app/views/projects/merge_requests/_merge_request.html.haml
index 25e4e8ba80d..300a3715292 100644
--- a/app/views/projects/merge_requests/_merge_request.html.haml
+++ b/app/views/projects/merge_requests/_merge_request.html.haml
@@ -1,3 +1,4 @@
+- ci_commit = merge_request.ci_commit
%li{ class: mr_css_classes(merge_request) }
.merge-request-title
%span.merge-request-title-text
@@ -6,6 +7,8 @@
- merge_request.labels.each do |label|
= link_to_label(label, project: merge_request.project)
.pull-right.light
+ - if ci_commit
+ = render_ci_status(ci_commit)
- if merge_request.merged?
%span
%i.fa.fa-check
diff --git a/app/views/projects/merge_requests/_merge_requests.html.haml b/app/views/projects/merge_requests/_merge_requests.html.haml
index d86707b3d97..0af970e4b92 100644
--- a/app/views/projects/merge_requests/_merge_requests.html.haml
+++ b/app/views/projects/merge_requests/_merge_requests.html.haml
@@ -5,8 +5,10 @@
.nothing-here-block No merge requests to show
- if @merge_requests.present?
- .pull-right
- %span.cgray.pull-right #{@merge_requests.total_count} merge requests for this filter
+ .issuable-filter-count
+ %span.pull-right
+ = @merge_requests.total_count
+ merge requests for this filter
= paginate @merge_requests, theme: "gitlab"
diff --git a/app/views/projects/merge_requests/_show.html.haml b/app/views/projects/merge_requests/_show.html.haml
index e7ac7a0eaa4..eeaa72ed21b 100644
--- a/app/views/projects/merge_requests/_show.html.haml
+++ b/app/views/projects/merge_requests/_show.html.haml
@@ -36,7 +36,8 @@
- if @merge_request.open? && @merge_request.can_be_merged?
.light.append-bottom-20
You can also accept this merge request manually using the
- = link_to "command line", "#modal_merge_info", class: "how_to_merge_link vlink", title: "How To Merge", "data-toggle" => "modal"
+ = succeed '.' do
+ = link_to "command line", "#modal_merge_info", class: "how_to_merge_link vlink", title: "How To Merge", "data-toggle" => "modal"
- if @commits.present?
%ul.merge-request-tabs
diff --git a/app/views/projects/merge_requests/show/_how_to_merge.html.haml b/app/views/projects/merge_requests/show/_how_to_merge.html.haml
index f18cf96c17d..98f0357ce4e 100644
--- a/app/views/projects/merge_requests/show/_how_to_merge.html.haml
+++ b/app/views/projects/merge_requests/show/_how_to_merge.html.haml
@@ -3,11 +3,12 @@
.modal-content
.modal-header
%a.close{href: "#", "data-dismiss" => "modal"} ×
- %h3 Check out, review and merge locally
+ %h3 Check out, review, and merge locally
.modal-body
%p
- %strong Step 1.
+ %strong Step 1.
Fetch and check out the branch for this merge request
+ = clipboard_button
%pre.dark
- if @merge_request.for_fork?
:preserve
@@ -24,6 +25,7 @@
%p
%strong Step 3.
Merge the branch and fix any conflicts that come up
+ = clipboard_button
%pre.dark
- if @merge_request.for_fork?
:preserve
@@ -36,6 +38,7 @@
%p
%strong Step 4.
Push the result of the merge to GitLab
+ = clipboard_button
%pre.dark
:preserve
git push origin #{h @merge_request.target_branch}
diff --git a/app/views/projects/merge_requests/widget/_heading.html.haml b/app/views/projects/merge_requests/widget/_heading.html.haml
index 68dda1424cf..a3551516bfe 100644
--- a/app/views/projects/merge_requests/widget/_heading.html.haml
+++ b/app/views/projects/merge_requests/widget/_heading.html.haml
@@ -1,44 +1,43 @@
-- if @merge_request.has_ci?
- - ci_commit = @merge_request.source_project.ci_commit(@merge_request.source_sha)
- - if ci_commit
- - status = ci_commit.status
- .mr-widget-heading
- .ci_widget{class: "ci-#{status}"}
- = ci_status_icon(ci_commit)
+- ci_commit = @merge_request.ci_commit
+- if ci_commit
+ - status = ci_commit.status
+ .mr-widget-heading
+ .ci_widget{class: "ci-#{status}"}
+ = ci_status_icon(ci_commit)
+ %span CI build #{status}
+ for #{@merge_request.last_commit_short_sha}.
+ %span.ci-coverage
+ = link_to "View build details", ci_status_path(ci_commit)
+
+- 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
+ .mr-widget-heading
+ - [:success, :skipped, :canceled, :failed, :running, :pending].each do |status|
+ .ci_widget{class: "ci-#{status}", style: "display:none"}
+ - if status == :success
+ - status = "passed"
+ = icon("check-circle")
+ - else
+ = icon("circle")
%span CI build #{status}
for #{@merge_request.last_commit_short_sha}.
%span.ci-coverage
- = link_to "View build details", ci_status_path(ci_commit)
-
- - else
- - # 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
- .mr-widget-heading
- - [:success, :skipped, :canceled, :failed, :running, :pending].each do |status|
- .ci_widget{class: "ci-#{status}", style: "display:none"}
- - if status == :success
- - status = "passed"
- = icon("check-circle")
- - else
- = icon("circle")
- %span CI build #{status}
- for #{@merge_request.last_commit_short_sha}.
- %span.ci-coverage
- - if ci_build_details_path(@merge_request)
- = link_to "View build details", ci_build_details_path(@merge_request), :"data-no-turbolink" => "data-no-turbolink"
+ - if ci_build_details_path(@merge_request)
+ = link_to "View build details", ci_build_details_path(@merge_request), :"data-no-turbolink" => "data-no-turbolink"
- .ci_widget
- = icon("spinner spin")
- Checking CI status for #{@merge_request.last_commit_short_sha}&hellip;
+ .ci_widget
+ = icon("spinner spin")
+ Checking CI status for #{@merge_request.last_commit_short_sha}&hellip;
- .ci_widget.ci-not_found{style: "display:none"}
- = icon("times-circle")
- Could not find CI status for #{@merge_request.last_commit_short_sha}.
+ .ci_widget.ci-not_found{style: "display:none"}
+ = icon("times-circle")
+ Could not find CI status for #{@merge_request.last_commit_short_sha}.
- .ci_widget.ci-error{style: "display:none"}
- = icon("times-circle")
- Could not connect to the CI server. Please check your settings and try again.
+ .ci_widget.ci-error{style: "display:none"}
+ = icon("times-circle")
+ Could not connect to the CI server. Please check your settings and try again.
- :coffeescript
- $ ->
- merge_request_widget.getCiStatus()
+ :coffeescript
+ $ ->
+ merge_request_widget.getCiStatus()
diff --git a/app/views/projects/milestones/_issue.html.haml b/app/views/projects/milestones/_issue.html.haml
index 88fccfe4981..133d802aaca 100644
--- a/app/views/projects/milestones/_issue.html.haml
+++ b/app/views/projects/milestones/_issue.html.haml
@@ -1,7 +1,7 @@
%li{ id: dom_id(issue, 'sortable'), class: 'issue-row', 'data-iid' => issue.iid, 'data-url' => issue_path(issue) }
.pull-right.assignee-icon
- if issue.assignee
- = image_tag avatar_icon(issue.assignee.email, 16), class: "avatar s16", alt: ''
+ = image_tag avatar_icon(issue.assignee, 16), class: "avatar s16", alt: ''
%span
= link_to [@project.namespace.becomes(Namespace), @project, issue] do
%span.cgray ##{issue.iid}
diff --git a/app/views/projects/milestones/_merge_request.html.haml b/app/views/projects/milestones/_merge_request.html.haml
index 0d7a118569a..a1033607c5d 100644
--- a/app/views/projects/milestones/_merge_request.html.haml
+++ b/app/views/projects/milestones/_merge_request.html.haml
@@ -5,4 +5,4 @@
= link_to_gfm merge_request.title, [@project.namespace.becomes(Namespace), @project, merge_request], title: merge_request.title
.pull-right.assignee-icon
- if merge_request.assignee
- = image_tag avatar_icon(merge_request.assignee.email, 16), class: "avatar s16", alt: ''
+ = image_tag avatar_icon(merge_request.assignee, 16), class: "avatar s16", alt: ''
diff --git a/app/views/projects/milestones/show.html.haml b/app/views/projects/milestones/show.html.haml
index 4eeb0621e52..3a898dfbcfd 100644
--- a/app/views/projects/milestones/show.html.haml
+++ b/app/views/projects/milestones/show.html.haml
@@ -104,7 +104,7 @@
- @users.each do |user|
%li
= link_to user, title: user.name, class: "darken" do
- = image_tag avatar_icon(user.email, 32), class: "avatar s32"
+ = image_tag avatar_icon(user, 32), class: "avatar s32"
%strong= truncate(user.name, lenght: 40)
%br
%small.cgray= user.username
diff --git a/app/views/projects/notes/_note.html.haml b/app/views/projects/notes/_note.html.haml
index 1638ad6891a..5d184730796 100644
--- a/app/views/projects/notes/_note.html.haml
+++ b/app/views/projects/notes/_note.html.haml
@@ -1,8 +1,8 @@
%li.timeline-entry{ id: dom_id(note), class: [dom_class(note), "note-row-#{note.id}", ('system-note' if note.system)], data: { discussion: note.discussion_id } }
.timeline-entry-inner
.timeline-icon
- = link_to user_path(note.author) do
- = image_tag avatar_icon(note.author_email), class: 'avatar s40', alt: ''
+ %a{href: user_path(note.author)}
+ %img.avatar.s40{src: avatar_icon(note.author), alt: ''}
.timeline-content
.note-header
- if note_editable?(note)
@@ -25,7 +25,7 @@
= '@' + note.author.username
%span.note-last-update
- = link_to "##{dom_id(note)}", name: dom_id(note), title: "Link here" do
+ %a{name: dom_id(note), href: "##{dom_id(note)}", title: 'Link here'}
= time_ago_with_tooltip(note.created_at, placement: 'bottom', html_class: 'note_created_ago')
- if note.updated_at != note.created_at
%span
diff --git a/app/views/projects/project_members/_project_member.html.haml b/app/views/projects/project_members/_project_member.html.haml
index 860a997cff8..76c46d1d806 100644
--- a/app/views/projects/project_members/_project_member.html.haml
+++ b/app/views/projects/project_members/_project_member.html.haml
@@ -4,7 +4,7 @@
%li{class: "#{dom_class(member)} js-toggle-container project_member_row access-#{member.human_access.downcase}", id: dom_id(member)}
%span.list-item-name
- if member.user
- = image_tag avatar_icon(user.email, 16), class: "avatar s16", alt: ''
+ = image_tag avatar_icon(user, 16), class: "avatar s16", alt: ''
%strong
= link_to user.name, user_path(user)
%span.cgray= user.username
diff --git a/app/views/projects/protected_branches/_branches_list.html.haml b/app/views/projects/protected_branches/_branches_list.html.haml
index bb49f4de873..f68449b1863 100644
--- a/app/views/projects/protected_branches/_branches_list.html.haml
+++ b/app/views/projects/protected_branches/_branches_list.html.haml
@@ -1,34 +1,35 @@
- unless @branches.empty?
%br
%h4 Already Protected:
- %table.table.protected-branches-list
- %thead
- %tr.no-border
- %th Branch
- %th Developers can push
- %th Last commit
- %th
+ .table-holder
+ %table.table.protected-branches-list
+ %thead
+ %tr.no-border
+ %th Branch
+ %th Developers can push
+ %th Last commit
+ %th
- %tbody
- - @branches.each do |branch|
- - @url = namespace_project_protected_branch_path(@project.namespace, @project, branch)
- %tr
- %td
- = link_to namespace_project_commits_path(@project.namespace, @project, branch.name) do
- %strong= branch.name
- - if @project.root_ref?(branch.name)
- %span.label.label-info default
+ %tbody
+ - @branches.each do |branch|
+ - @url = namespace_project_protected_branch_path(@project.namespace, @project, branch)
+ %tr
%td
- = check_box_tag "developers_can_push", branch.id, branch.developers_can_push, "data-url" => @url
- %td
- - if commit = branch.commit
- = link_to namespace_project_commit_path(@project.namespace, @project, commit.id), class: 'commit_short_id' do
- = commit.short_id
- &middot;
- #{time_ago_with_tooltip(commit.committed_date)}
- - else
- (branch was removed from repository)
- %td
- .pull-right
- - if can? current_user, :admin_project, @project
- = link_to 'Unprotect', [@project.namespace.becomes(Namespace), @project, branch], data: { confirm: 'Branch will be writable for developers. Are you sure?' }, method: :delete, class: "btn btn-remove btn-sm"
+ = link_to namespace_project_commits_path(@project.namespace, @project, branch.name) do
+ %strong= branch.name
+ - if @project.root_ref?(branch.name)
+ %span.label.label-info default
+ %td
+ = check_box_tag "developers_can_push", branch.id, branch.developers_can_push, "data-url" => @url
+ %td
+ - if commit = branch.commit
+ = link_to namespace_project_commit_path(@project.namespace, @project, commit.id), class: 'commit_short_id' do
+ = commit.short_id
+ &middot;
+ #{time_ago_with_tooltip(commit.committed_date)}
+ - else
+ (branch was removed from repository)
+ %td
+ .pull-right
+ - if can? current_user, :admin_project, @project
+ = link_to 'Unprotect', [@project.namespace.becomes(Namespace), @project, branch], data: { confirm: 'Branch will be writable for developers. Are you sure?' }, method: :delete, class: "btn btn-remove btn-sm"
diff --git a/app/views/projects/remove_fork.js.haml b/app/views/projects/remove_fork.js.haml
new file mode 100644
index 00000000000..17b9fecfeb1
--- /dev/null
+++ b/app/views/projects/remove_fork.js.haml
@@ -0,0 +1,2 @@
+:plain
+ location.href = "#{edit_namespace_project_path(@project.namespace, @project)}";
diff --git a/app/views/projects/runners/show.html.haml b/app/views/projects/runners/show.html.haml
index ffec495f85a..c255cd51bd2 100644
--- a/app/views/projects/runners/show.html.haml
+++ b/app/views/projects/runners/show.html.haml
@@ -9,56 +9,57 @@
%span.runner-state.runner-state-specific
Specific
-%table.table
- %thead
+.table-holder
+ %table.table
+ %thead
+ %tr
+ %th Property Name
+ %th Value
%tr
- %th Property Name
- %th Value
- %tr
- %td
- Tags
- %td
- - @runner.tag_list.each do |tag|
- %span.label.label-primary
- = tag
- %tr
- %td
- Name
- %td
- = @runner.name
- %tr
- %td
- Version
- %td
- = @runner.version
- %tr
- %td
- Revision
- %td
- = @runner.revision
- %tr
- %td
- Platform
- %td
- = @runner.platform
- %tr
- %td
- Architecture
- %td
- = @runner.architecture
- %tr
- %td
- Description
- %td
- = @runner.description
- %tr
- %td
- Last contact
- %td
- - if @runner.contacted_at
- #{time_ago_in_words(@runner.contacted_at)} ago
- - else
- Never
+ %td
+ Tags
+ %td
+ - @runner.tag_list.each do |tag|
+ %span.label.label-primary
+ = tag
+ %tr
+ %td
+ Name
+ %td
+ = @runner.name
+ %tr
+ %td
+ Version
+ %td
+ = @runner.version
+ %tr
+ %td
+ Revision
+ %td
+ = @runner.revision
+ %tr
+ %td
+ Platform
+ %td
+ = @runner.platform
+ %tr
+ %td
+ Architecture
+ %td
+ = @runner.architecture
+ %tr
+ %td
+ Description
+ %td
+ = @runner.description
+ %tr
+ %td
+ Last contact
+ %td
+ - if @runner.contacted_at
+ #{time_ago_in_words(@runner.contacted_at)} ago
+ - else
+ Never
-
+
diff --git a/app/views/projects/services/index.html.haml b/app/views/projects/services/index.html.haml
index 1065def693b..c1356f6db02 100644
--- a/app/views/projects/services/index.html.haml
+++ b/app/views/projects/services/index.html.haml
@@ -2,22 +2,23 @@
%h3.page-title Project services
%p.light Project services allow you to integrate GitLab with other applications
-%table.table
- %thead
- %tr
- %th
- %th Service
- %th Description
- %th Last edit
- - @services.sort_by(&:title).each do |service|
- %tr
- %td
- = boolean_to_icon service.activated?
- %td
- = link_to edit_namespace_project_service_path(@project.namespace, @project, service.to_param) do
- %strong= service.title
- %td
- = service.description
- %td.light
- = time_ago_in_words service.updated_at
- ago
+.table-holder
+ %table.table
+ %thead
+ %tr
+ %th
+ %th Service
+ %th Description
+ %th Last edit
+ - @services.sort_by(&:title).each do |service|
+ %tr
+ %td
+ = boolean_to_icon service.activated?
+ %td
+ = link_to edit_namespace_project_service_path(@project.namespace, @project, service.to_param) do
+ %strong= service.title
+ %td
+ = service.description
+ %td.light
+ = time_ago_in_words service.updated_at
+ ago
diff --git a/app/views/projects/show.html.haml b/app/views/projects/show.html.haml
index e95d987d74c..585caf674c9 100644
--- a/app/views/projects/show.html.haml
+++ b/app/views/projects/show.html.haml
@@ -7,8 +7,7 @@
= render 'shared/no_ssh'
= render 'shared/no_password'
-- if prefer_readme?
- = render 'projects/last_push'
+= render 'projects/last_push'
= render "home_panel"
@@ -28,7 +27,7 @@
= link_to project_files_path(@project) do
= repository_size
- - if !prefer_readme? && @repository.readme
+ - if default_project_view != 'readme' && @repository.readme
%li
= link_to 'Readme', readme_path(@project)
@@ -64,14 +63,12 @@
= icon("exclamation-triangle fw")
Archived project! Repository is read-only
-%section
- - if prefer_readme?
- .project-show-readme
- = render 'projects/readme'
- - else
- .project-show-activity
- = render 'projects/activity'
+- if @repository.commit
+ .content-block.second-block.white
+ = render 'projects/last_commit', commit: @repository.commit, project: @project
+%div{class: "project-show-#{default_project_view}"}
+ = render default_project_view
- if current_user
- access = user_max_access_in_project(current_user, @project)
diff --git a/app/views/projects/snippets/_actions.html.haml b/app/views/projects/snippets/_actions.html.haml
new file mode 100644
index 00000000000..4a515469422
--- /dev/null
+++ b/app/views/projects/snippets/_actions.html.haml
@@ -0,0 +1,11 @@
+= link_to new_namespace_project_snippet_path(@project.namespace, @project), class: 'btn btn-grouped new-snippet-link', title: "New Snippet" do
+ = icon('plus')
+ New Snippet
+- if can?(current_user, :admin_project_snippet, @snippet)
+ = link_to namespace_project_snippet_path(@project.namespace, @project, @snippet), method: :delete, data: { confirm: "Are you sure?" }, class: "btn btn-grouped btn-remove", title: 'Delete Snippet' do
+ = icon('trash-o')
+ Delete
+- if can?(current_user, :update_project_snippet, @snippet)
+ = link_to edit_namespace_project_snippet_path(@project.namespace, @project, @snippet), class: "btn btn-grouped snippable-edit" do
+ = icon('pencil-square-o')
+ Edit
diff --git a/app/views/projects/snippets/index.html.haml b/app/views/projects/snippets/index.html.haml
index 3fed2c9949d..4af963e14da 100644
--- a/app/views/projects/snippets/index.html.haml
+++ b/app/views/projects/snippets/index.html.haml
@@ -1,17 +1,13 @@
- page_title "Snippets"
= render "header_title"
-%h3.page-title
- Snippets
- - if can? current_user, :create_project_snippet, @project
- = link_to new_namespace_project_snippet_path(@project.namespace, @project), class: "btn btn-new pull-right", title: "New Snippet" do
- Add new snippet
+.gray-content-block.top-block
+ .pull-right
+ = link_to new_namespace_project_snippet_path(@project.namespace, @project), class: "btn btn-new", title: "New Snippet" do
+ = icon('plus')
+ New Snippet
-%p.light
- Share code pastes with others out of git repository
+ .oneline
+ Share code pastes with others out of git repository
-%ul.bordered-list
- = render partial: "shared/snippets/snippet", collection: @snippets
- - if @snippets.empty?
- %li
- .nothing-here-block Nothing here.
+= render 'snippets/snippets'
diff --git a/app/views/projects/snippets/show.html.haml b/app/views/projects/snippets/show.html.haml
index be7d4d486fa..5d706942f2d 100644
--- a/app/views/projects/snippets/show.html.haml
+++ b/app/views/projects/snippets/show.html.haml
@@ -1,40 +1,18 @@
- page_title @snippet.title, "Snippets"
= render "header_title"
-%h3.page-title
- = @snippet.title
+.snippet-holder
+ = render 'shared/snippets/header'
- .pull-right
- = link_to new_namespace_project_snippet_path(@project.namespace, @project), class: "btn btn-new", title: "New Snippet" do
- Add new snippet
+ %article.file-holder
+ .file-title
+ = blob_icon 0, @snippet.file_name
+ %strong
+ = @snippet.file_name
+ .file-actions.hidden-xs
+ .btn-group.tree-btn-group
+ = link_to 'Raw', raw_namespace_project_snippet_path(@project.namespace, @project, @snippet), class: "btn btn-sm", target: "_blank"
-%hr
+ = render 'shared/snippets/blob'
-.append-bottom-20
- .pull-right
- = "##{@snippet.id}"
- %span.light
- by
- = link_to user_path(@snippet.author) do
- = image_tag avatar_icon(@snippet.author_email), class: "avatar avatar-inline s16"
- = @snippet.author_name
-
- .back-link
- = link_to namespace_project_snippets_path(@project.namespace, @project) do
- &larr; project snippets
-
-.file-holder
- .file-title
- %i.fa.fa-file
- %strong
- = @snippet.file_name
- .file-actions
- .btn-group
- - if can?(current_user, :update_project_snippet, @snippet)
- = link_to "edit", edit_namespace_project_snippet_path(@project.namespace, @project, @snippet), class: "btn btn-sm", title: 'Edit Snippet'
- = link_to "raw", raw_namespace_project_snippet_path(@project.namespace, @project, @snippet), class: "btn btn-sm", target: "_blank"
- - if can?(current_user, :admin_project_snippet, @snippet)
- = link_to "remove", namespace_project_snippet_path(@project.namespace, @project, @snippet), method: :delete, data: { confirm: "Are you sure?" }, class: "btn btn-sm btn-remove", title: 'Delete Snippet'
- = render 'shared/snippets/blob'
-
-%div#notes= render "projects/notes/notes_with_form"
+ %div#notes= render "projects/notes/notes_with_form"
diff --git a/app/views/projects/tree/_blob_item.html.haml b/app/views/projects/tree/_blob_item.html.haml
index 02ecbade219..2ddc5d504fa 100644
--- a/app/views/projects/tree/_blob_item.html.haml
+++ b/app/views/projects/tree/_blob_item.html.haml
@@ -4,5 +4,5 @@
%span.str-truncated
= link_to blob_item.name, namespace_project_blob_path(@project.namespace, @project, tree_join(@id || @commit.id, blob_item.name))
%td.tree_time_ago.cgray
- = render 'spinner'
+ = render 'projects/tree/spinner'
%td.hidden-xs.tree_commit
diff --git a/app/views/projects/tree/_readme.html.haml b/app/views/projects/tree/_readme.html.haml
index 7e9af19c8ba..3c5edf4b033 100644
--- a/app/views/projects/tree/_readme.html.haml
+++ b/app/views/projects/tree/_readme.html.haml
@@ -1,8 +1,8 @@
-%article.file-holder.readme-holder#README
+%article.file-holder.readme-holder
.file-title
- = link_to '#README' do
+ = blob_icon readme.mode, readme.name
+ = link_to namespace_project_blob_path(@project.namespace, @project, tree_join(@repository.root_ref, readme.name)) do
%strong
- %i.fa.fa-file
= readme.name
.file-content.wiki
= render_readme(readme)
diff --git a/app/views/projects/tree/_tree.html.haml b/app/views/projects/tree/_tree_content.html.haml
index 7ff48e32e60..ee4c9d1693d 100644
--- a/app/views/projects/tree/_tree.html.haml
+++ b/app/views/projects/tree/_tree_content.html.haml
@@ -1,36 +1,5 @@
-.gray-content-block
- %ul.breadcrumb.repo-breadcrumb
- %li
- = link_to namespace_project_tree_path(@project.namespace, @project, @ref) do
- = @project.path
- - tree_breadcrumbs(tree, 6) do |title, path|
- %li
- - if path
- = link_to truncate(title, length: 40), namespace_project_tree_path(@project.namespace, @project, path)
- - else
- = link_to title, '#'
- - if allowed_tree_edit?
- %li
- %span.dropdown
- %a.dropdown-toggle.btn.add-to-tree{href: '#', "data-toggle" => "dropdown"}
- = icon('plus')
- %ul.dropdown-menu
- %li
- = link_to namespace_project_new_blob_path(@project.namespace, @project, @id), title: 'Create file', id: 'new-file-link' do
- = icon('pencil fw')
- Create file
- %li
- = link_to '#modal-upload-blob', { 'data-target' => '#modal-upload-blob', 'data-toggle' => 'modal'} do
- = icon('file fw')
- Upload file
- %li.divider
- %li
- = link_to '#modal-create-new-dir', { 'data-target' => '#modal-create-new-dir', 'data-toggle' => 'modal'} do
- = icon('folder fw')
- New directory
-
-%div#tree-content-holder.tree-content-holder
- .tree-table-holder
+%div.tree-content-holder
+ .table-holder
%table.table#tree-slider{class: "table_#{@hex_path} tree-table table-striped" }
%thead
%tr
@@ -60,8 +29,6 @@
- if tree.readme
= render "projects/tree/readme", readme: tree.readme
-%div.tree_progress
-
- if allowed_tree_edit?
= render 'projects/blob/upload', title: 'Upload', placeholder: 'Upload new file', button_title: 'Upload file', form_path: namespace_project_create_blob_path(@project.namespace, @project, @id), method: :post
= render 'projects/blob/new_dir'
diff --git a/app/views/projects/tree/_tree_header.html.haml b/app/views/projects/tree/_tree_header.html.haml
new file mode 100644
index 00000000000..1115ca6b4ca
--- /dev/null
+++ b/app/views/projects/tree/_tree_header.html.haml
@@ -0,0 +1,32 @@
+.tree-ref-holder
+ = render 'shared/ref_switcher', destination: 'tree', path: @path
+
+%ul.breadcrumb.repo-breadcrumb
+ %li
+ = link_to namespace_project_tree_path(@project.namespace, @project, @ref) do
+ = @project.path
+ - tree_breadcrumbs(tree, 6) do |title, path|
+ %li
+ - if path
+ = link_to truncate(title, length: 40), namespace_project_tree_path(@project.namespace, @project, path)
+ - else
+ = link_to title, '#'
+ - if allowed_tree_edit?
+ %li
+ %span.dropdown
+ %a.dropdown-toggle.btn.add-to-tree{href: '#', "data-toggle" => "dropdown"}
+ = icon('plus')
+ %ul.dropdown-menu
+ %li
+ = link_to namespace_project_new_blob_path(@project.namespace, @project, @id), title: 'Create file', id: 'new-file-link' do
+ = icon('pencil fw')
+ Create file
+ %li
+ = link_to '#modal-upload-blob', { 'data-target' => '#modal-upload-blob', 'data-toggle' => 'modal'} do
+ = icon('file fw')
+ Upload file
+ %li.divider
+ %li
+ = link_to '#modal-create-new-dir', { 'data-target' => '#modal-create-new-dir', 'data-toggle' => 'modal'} do
+ = icon('folder fw')
+ New directory
diff --git a/app/views/projects/tree/_tree_item.html.haml b/app/views/projects/tree/_tree_item.html.haml
index e87138bf980..cf65057e704 100644
--- a/app/views/projects/tree/_tree_item.html.haml
+++ b/app/views/projects/tree/_tree_item.html.haml
@@ -5,5 +5,5 @@
- path = flatten_tree(tree_item)
= link_to path, namespace_project_tree_path(@project.namespace, @project, tree_join(@id || @commit.id, path))
%td.tree_time_ago.cgray
- = render 'spinner'
+ = render 'projects/tree/spinner'
%td.hidden-xs.tree_commit
diff --git a/app/views/projects/tree/show.html.haml b/app/views/projects/tree/show.html.haml
index dec4677f830..ec14bd7f65a 100644
--- a/app/views/projects/tree/show.html.haml
+++ b/app/views/projects/tree/show.html.haml
@@ -6,12 +6,12 @@
= render 'projects/last_push'
-.tree-ref-holder
- = render 'shared/ref_switcher', destination: 'tree', path: @path
-
- if can? current_user, :download_code, @project
.tree-download-holder
= render 'projects/repositories/download_archive', ref: @ref, btn_class: 'btn-group pull-right hidden-xs hidden-sm', split_button: true
#tree-holder.tree-holder.clearfix
- = render "tree", tree: @tree
+ .gray-content-block.top-block
+ = render 'projects/tree/tree_header', tree: @tree
+
+ = render 'projects/tree/tree_content', tree: @tree
diff --git a/app/views/projects/triggers/index.html.haml b/app/views/projects/triggers/index.html.haml
index 17dcb78e256..18a37302c3e 100644
--- a/app/views/projects/triggers/index.html.haml
+++ b/app/views/projects/triggers/index.html.haml
@@ -7,12 +7,13 @@
%hr.clearfix
-if @triggers.any?
- %table.table
- %thead
- %th Token
- %th Last used
- %th
- = render partial: 'trigger', collection: @triggers, as: :trigger
+ .table-holder
+ %table.table
+ %thead
+ %th Token
+ %th Last used
+ %th
+ = render partial: 'trigger', collection: @triggers, as: :trigger
- else
%h4 No triggers
diff --git a/app/views/projects/wikis/history.html.haml b/app/views/projects/wikis/history.html.haml
index bfbef823b35..4322146ce34 100644
--- a/app/views/projects/wikis/history.html.haml
+++ b/app/views/projects/wikis/history.html.haml
@@ -7,28 +7,29 @@
%span.light History for
= link_to @page.title, namespace_project_wiki_path(@project.namespace, @project, @page)
-%table.table
- %thead
- %tr
- %th Page version
- %th Author
- %th Commit Message
- %th Last updated
- %th Format
- %tbody
- - @page.versions.each_with_index do |version, index|
- - commit = version
+.table-holder
+ %table.table
+ %thead
%tr
- %td
- = link_to project_wiki_path_with_version(@project, @page,
- commit.id, index == 0) do
- = truncate_sha(commit.id)
- %td
- = commit.author.name
- %td
- = commit.message
- %td
- #{time_ago_with_tooltip(version.authored_date)}
- %td
- %strong
- = @page.page.wiki.page(@page.page.name, commit.id).try(:format)
+ %th Page version
+ %th Author
+ %th Commit Message
+ %th Last updated
+ %th Format
+ %tbody
+ - @page.versions.each_with_index do |version, index|
+ - commit = version
+ %tr
+ %td
+ = link_to project_wiki_path_with_version(@project, @page,
+ commit.id, index == 0) do
+ = truncate_sha(commit.id)
+ %td
+ = commit.author.name
+ %td
+ = commit.message
+ %td
+ #{time_ago_with_tooltip(version.authored_date)}
+ %td
+ %strong
+ = @page.page.wiki.page(@page.page.name, commit.id).try(:format)
diff --git a/app/views/search/_category.html.haml b/app/views/search/_category.html.haml
index d637abfa76b..481451edb23 100644
--- a/app/views/search/_category.html.haml
+++ b/app/views/search/_category.html.haml
@@ -42,6 +42,13 @@
Wiki
%span.badge
= @search_results.wiki_blobs_count
+ %li{class: ("active" if @scope == 'commits')}
+ = link_to search_filter_path(scope: 'commits') do
+ = icon('history fw')
+ %span
+ Commits
+ %span.badge
+ = @search_results.commits_count
- elsif @show_snippets
%li{class: ("active" if @scope == 'snippet_blobs')}
diff --git a/app/views/search/results/_commit.html.haml b/app/views/search/results/_commit.html.haml
new file mode 100644
index 00000000000..4e6c3965dc6
--- /dev/null
+++ b/app/views/search/results/_commit.html.haml
@@ -0,0 +1,2 @@
+.search-result-row
+ = render 'projects/commits/commit', project: @project, commit: commit
diff --git a/app/views/shared/_clone_panel.html.haml b/app/views/shared/_clone_panel.html.haml
index b23b2f0d5eb..2e4aab36301 100644
--- a/app/views/shared/_clone_panel.html.haml
+++ b/app/views/shared/_clone_panel.html.haml
@@ -6,7 +6,7 @@
type: 'button', |
class: "btn #{ 'active' if default_clone_protocol == 'ssh' }#{ ' has_tooltip' if current_user && current_user.require_ssh_key? }", |
:"data-clone" => project.ssh_url_to_repo, |
- :"data-title" => "Add an SSH key to your profile<br> to pull or push via SSH",
+ :"data-title" => "Add an SSH key to your profile<br> to pull or push via SSH.",
:"data-html" => "true",
:"data-container" => "body"}
SSH
@@ -15,7 +15,7 @@
type: 'button', |
class: "btn #{ 'active' if default_clone_protocol == 'http' }#{ ' has_tooltip' if current_user && current_user.require_password? }", |
:"data-clone" => project.http_url_to_repo, |
- :"data-title" => "Set a password on your account<br> to pull or push via #{gitlab_config.protocol.upcase}",
+ :"data-title" => "Set a password on your account<br> to pull or push via #{gitlab_config.protocol.upcase}.",
:"data-html" => "true",
:"data-container" => "body"}
= gitlab_config.protocol.upcase
diff --git a/app/views/shared/_logo.svg b/app/views/shared/_logo.svg
new file mode 100644
index 00000000000..da49c48acd3
--- /dev/null
+++ b/app/views/shared/_logo.svg
@@ -0,0 +1,21 @@
+<svg width="36px" height="36px" viewBox="0 0 210 210" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" id="tanuki-logo">
+ <g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" sketch:type="MSPage">
+ <g id="logo" sketch:type="MSLayerGroup" transform="translate(0.000000, 10.000000)">
+ <g id="Page-1" sketch:type="MSShapeGroup">
+ <g id="Fill-1-+-Group-24">
+ <g id="Group-24">
+ <g id="Group">
+ <path d="M105.0614,193.655 L105.0614,193.655 L143.7014,74.734 L66.4214,74.734 L105.0614,193.655 L105.0614,193.655 Z" id="Fill-4" fill="#E24329" class="tanuki-shape"></path>
+ <path d="M105.0614,193.6548 L66.4214,74.7338 L12.2684,74.7338 L105.0614,193.6548 L105.0614,193.6548 Z" id="Fill-8" fill="#FC6D26" class="tanuki-shape"></path>
+ <path d="M12.2685,74.7341 L12.2685,74.7341 L0.5265,110.8731 C-0.5445,114.1691 0.6285,117.7801 3.4325,119.8171 L105.0615,193.6551 L12.2685,74.7341 L12.2685,74.7341 Z" id="Fill-12" fill="#FCA326" class="tanuki-shape"></path>
+ <path d="M12.2685,74.7342 L66.4215,74.7342 L43.1485,3.1092 C41.9515,-0.5768 36.7375,-0.5758 35.5405,3.1092 L12.2685,74.7342 L12.2685,74.7342 Z" id="Fill-16" fill="#E24329" class="tanuki-shape"></path>
+ <path d="M105.0614,193.6548 L143.7014,74.7338 L197.8544,74.7338 L105.0614,193.6548 L105.0614,193.6548 Z" id="Fill-18" fill="#FC6D26" class="tanuki-shape"></path>
+ <path d="M197.8544,74.7341 L197.8544,74.7341 L209.5964,110.8731 C210.6674,114.1691 209.4944,117.7801 206.6904,119.8171 L105.0614,193.6551 L197.8544,74.7341 L197.8544,74.7341 Z" id="Fill-20" fill="#FCA326" class="tanuki-shape"></path>
+ <path d="M197.8544,74.7342 L143.7014,74.7342 L166.9744,3.1092 C168.1714,-0.5768 173.3854,-0.5758 174.5824,3.1092 L197.8544,74.7342 L197.8544,74.7342 Z" id="Fill-22" fill="#E24329" class="tanuki-shape"></path>
+ </g>
+ </g>
+ </g>
+ </g>
+ </g>
+ </g>
+</svg>
diff --git a/app/views/shared/issuable/_filter.html.haml b/app/views/shared/issuable/_filter.html.haml
index 8f16773077e..0e4e9c0987a 100644
--- a/app/views/shared/issuable/_filter.html.haml
+++ b/app/views/shared/issuable/_filter.html.haml
@@ -42,11 +42,10 @@
class: 'select2 trigger-submit', include_blank: true,
data: {placeholder: 'Milestone'})
- - if @project
- .filter-item.inline.labels-filter
- = select_tag('label_name', project_labels_options(@project),
- class: 'select2 trigger-submit', include_blank: true,
- data: {placeholder: 'Label'})
+ .filter-item.inline.labels-filter
+ = select_tag('label_name', projects_labels_options,
+ class: 'select2 trigger-submit', include_blank: true,
+ data: {placeholder: 'Label'})
.pull-right
= render 'shared/sort_dropdown'
diff --git a/app/views/shared/projects/_project.html.haml b/app/views/shared/projects/_project.html.haml
index aee839b44e7..c36995b94d7 100644
--- a/app/views/shared/projects/_project.html.haml
+++ b/app/views/shared/projects/_project.html.haml
@@ -21,9 +21,7 @@
.project-controls
- if ci && !project.empty_repo? && project.commit
- if ci_commit = project.ci_commit(project.commit.sha)
- = link_to ci_status_path(ci_commit), class: "c#{ci_status_color(ci_commit)}",
- title: "Build status: #{ci_commit.status}", data: {toggle: 'tooltip', placement: 'left'} do
- = ci_status_icon(ci_commit)
+ = render_ci_status(ci_commit)
&nbsp;
- if stars
%span
diff --git a/app/views/shared/snippets/_header.html.haml b/app/views/shared/snippets/_header.html.haml
new file mode 100644
index 00000000000..0a4a790ec5e
--- /dev/null
+++ b/app/views/shared/snippets/_header.html.haml
@@ -0,0 +1,24 @@
+.snippet-details
+ .page-title
+ .snippet-box{class: visibility_level_color(@snippet.visibility_level)}
+ = visibility_level_icon(@snippet.visibility_level)
+ = visibility_level_label(@snippet.visibility_level)
+ %span.snippet-id Snippet ##{@snippet.id}
+ %span.creator
+ &middot; created by #{link_to_member(@project, @snippet.author, size: 24)}
+ &middot;
+ = time_ago_with_tooltip(@snippet.created_at, placement: 'bottom', html_class: 'snippet_updated_ago')
+ - if @snippet.updated_at != @snippet.created_at
+ %span
+ &middot;
+ = icon('edit', title: 'edited')
+ = time_ago_with_tooltip(@snippet.updated_at, placement: 'bottom', html_class: 'snippet_edited_ago')
+
+ .pull-right
+ - if @snippet.project_id?
+ = render "projects/snippets/actions"
+ - else
+ = render "snippets/actions"
+ .gray-content-block.middle-block
+ %h2.snippet-title
+ = gfm escape_once(@snippet.title)
diff --git a/app/views/shared/snippets/_snippet.html.haml b/app/views/shared/snippets/_snippet.html.haml
index 69a713ad9aa..c6294caddc7 100644
--- a/app/views/shared/snippets/_snippet.html.haml
+++ b/app/views/shared/snippets/_snippet.html.haml
@@ -18,4 +18,3 @@
= image_tag avatar_icon(snippet.author_email), class: "avatar s24", alt: ''
= snippet.author_name
authored #{time_ago_with_tooltip(snippet.created_at)}
-
diff --git a/app/views/snippets/_actions.html.haml b/app/views/snippets/_actions.html.haml
new file mode 100644
index 00000000000..1979ae6d5bc
--- /dev/null
+++ b/app/views/snippets/_actions.html.haml
@@ -0,0 +1,11 @@
+= link_to new_snippet_path, class: 'btn btn-grouped new-snippet-link', title: "New Snippet" do
+ = icon('plus')
+ New Snippet
+- if can?(current_user, :update_personal_snippet, @snippet)
+ = link_to edit_snippet_path(@snippet), class: "btn btn-grouped snippable-edit" do
+ = icon('pencil-square-o')
+ Edit
+- if can?(current_user, :admin_personal_snippet, @snippet)
+ = link_to snippet_path(@snippet), method: :delete, data: { confirm: "Are you sure?" }, class: "btn btn-grouped btn-remove", title: 'Delete Snippet' do
+ = icon('trash-o')
+ Delete
diff --git a/app/views/snippets/show.html.haml b/app/views/snippets/show.html.haml
index 97374e073dc..69d8899d4c1 100644
--- a/app/views/snippets/show.html.haml
+++ b/app/views/snippets/show.html.haml
@@ -1,41 +1,14 @@
- page_title @snippet.title, "Snippets"
-%h4.page-title
- = @snippet.title
- - if @snippet.private?
- %span.label.label-success
- %i.fa.fa-lock
- private
-
- .pull-right
- = link_to new_snippet_path, class: "btn btn-new btn-sm", title: "New Snippet" do
- Add new snippet
-
-.append-bottom-10.prepend-top-10
- .pull-right
- %span.light
- created by
- = link_to user_snippets_path(@snippet.author) do
- = @snippet.author_name
-
- .back-link
- - if @snippet.author == current_user
- = link_to dashboard_snippets_path do
- &larr; your snippets
- - else
- = link_to explore_snippets_path do
- &larr; explore snippets
-
-.file-holder
- .file-title
- %i.fa.fa-file
- %strong
- = @snippet.file_name
- .file-actions
- .btn-group
- - if can?(current_user, :update_personal_snippet, @snippet)
- = link_to "edit", edit_snippet_path(@snippet), class: "btn btn-sm", title: 'Edit Snippet'
- = link_to "raw", raw_snippet_path(@snippet), class: "btn btn-sm", target: "_blank"
- - if can?(current_user, :admin_personal_snippet, @snippet)
- = link_to "remove", snippet_path(@snippet), method: :delete, data: { confirm: "Are you sure?" }, class: "btn btn-sm btn-remove", title: 'Delete Snippet'
- = render 'shared/snippets/blob'
+.snippet-holder
+ = render 'shared/snippets/header'
+
+ %article.file-holder
+ .file-title
+ = blob_icon 0, @snippet.file_name
+ %strong
+ = @snippet.file_name
+ .file-actions.hidden-xs
+ .btn-group.tree-btn-group
+ = link_to 'Raw', raw_snippet_path(@snippet), class: "btn btn-sm", target: "_blank"
+ = render 'shared/snippets/blob'
diff --git a/app/views/users/_projects.html.haml b/app/views/users/_projects.html.haml
deleted file mode 100644
index a126a858ea8..00000000000
--- a/app/views/users/_projects.html.haml
+++ /dev/null
@@ -1,13 +0,0 @@
-- if local_assigns.has_key?(:contributed_projects) && contributed_projects.present?
- .panel.panel-default.contributed-projects
- .panel-heading Projects contributed to
- = render 'shared/projects/list',
- projects: contributed_projects.sort_by(&:star_count).reverse,
- projects_limit: 5, stars: true, avatar: false
-
-- if local_assigns.has_key?(:projects) && projects.present?
- .panel.panel-default
- .panel-heading Personal projects
- = render 'shared/projects/list',
- projects: projects.sort_by(&:star_count).reverse,
- projects_limit: 10, stars: true, avatar: false
diff --git a/app/views/users/calendar.html.haml b/app/views/users/calendar.html.haml
index 922b0c6cebf..7f29918dba3 100644
--- a/app/views/users/calendar.html.haml
+++ b/app/views/users/calendar.html.haml
@@ -1,7 +1,3 @@
-%h4
- Contributions calendar
- .pull-right
- %small Issues, merge requests and push events
#cal-heatmap.calendar
:javascript
new Calendar(
@@ -10,3 +6,5 @@
#{@starting_month},
'#{user_calendar_activities_path}'
);
+
+.calendar-hint Summary of issues, merge requests and push events
diff --git a/app/views/users/show.html.haml b/app/views/users/show.html.haml
index 11beb3e3239..e22d93aae84 100644
--- a/app/views/users/show.html.haml
+++ b/app/views/users/show.html.haml
@@ -6,61 +6,114 @@
= render 'shared/show_aside'
-.row
- %section.col-md-7
- .header-with-avatar
- = link_to avatar_icon(@user.email, 400), target: '_blank' do
- = image_tag avatar_icon(@user.email, 90), class: "avatar avatar-tile s90", alt: ''
- %h3
- = @user.name
- - if @user == current_user
- .pull-right.hidden-xs
- = link_to profile_path, class: 'btn btn-sm' do
- = icon('user')
- Profile settings
- - elsif current_user
- .report_abuse.pull-right
- - if @user.abuse_report
- %span#report_abuse_btn.light.btn.btn-sm.btn-close{title: 'Already reported for abuse', data: {toggle: 'tooltip', placement: 'right', container: 'body'}}
- = icon('exclamation-circle')
- - else
- %a.light.btn.btn-sm{href: new_abuse_report_path(user_id: @user.id), title: 'Report abuse', data: {toggle: 'tooltip', placement: 'right', container: 'body'}}
- = icon('exclamation-circle')
+.cover-block
+ .avatar-holder
+ = link_to avatar_icon(@user, 400), target: '_blank' do
+ = image_tag avatar_icon(@user, 90), class: "avatar s90", alt: ''
+ .cover-title
+ = @user.name
- .username
- @#{@user.username}
- .description
- - if @user.bio.present?
- = @user.bio
+ .cover-desc
+ %span
+ @#{@user.username}.
+ - if @user.bio.present?
+ %span
+ #{@user.bio}.
+ %span
+ Member since #{@user.created_at.stamp("Aug 21, 2011")}
- .clearfix
+ .cover-desc
+ - unless @user.public_email.blank?
+ .profile-link-holder
+ = link_to @user.public_email, "mailto:#{@user.public_email}"
+ - unless @user.skype.blank?
+ .profile-link-holder
+ = link_to "skype:#{@user.skype}", title: "Skype" do
+ = icon('skype')
+ - unless @user.linkedin.blank?
+ .profile-link-holder
+ = link_to "http://www.linkedin.com/in/#{@user.linkedin}", title: "LinkedIn" do
+ = icon('linkedin-square')
+ - unless @user.twitter.blank?
+ .profile-link-holder
+ = link_to "http://www.twitter.com/#{@user.twitter}", title: "Twitter" do
+ = icon('twitter-square')
+ - unless @user.website_url.blank?
+ .profile-link-holder
+ = link_to @user.short_website_url, @user.full_website_url
+ - unless @user.location.blank?
+ .profile-link-holder
+ = icon('map-marker')
+ = @user.location
- - if @groups.any?
- .prepend-top-20
- %h4 Groups
- = render 'groups', groups: @groups
- %hr
- .hidden-xs
- .user-calendar
- %h4.center.light
- %i.fa.fa-spinner.fa-spin
- .user-calendar-activities
- %hr
- %h4
- User Activity
+ .cover-controls
+ - if @user == current_user
+ = link_to profile_path, class: 'btn btn-gray' do
+ = icon('pencil')
+ - elsif current_user
+ %span.report-abuse
+ - if @user.abuse_report
+ %button.btn.btn-danger{ title: 'Already reported for abuse',
+ data: { toggle: 'tooltip', placement: 'left', container: 'body' }}
+ = icon('exclamation-circle')
+ - else
+ = link_to new_abuse_report_path(user_id: @user.id), class: 'btn btn-gray',
+ title: 'Report abuse', data: {toggle: 'tooltip', placement: 'left', container: 'body'} do
+ = icon('exclamation-circle')
+ - if current_user
+ &nbsp;
+ = link_to user_path(@user, :atom, { private_token: current_user.private_token }), class: 'btn btn-gray' do
+ = icon('rss')
- - if current_user
- %span.rss-icon.pull-right
- = link_to user_path(@user, :atom, { private_token: current_user.private_token }) do
- %strong
- %i.fa.fa-rss
+.gray-content-block.second-block
+ .user-calendar
+ %h4.center.light
+ %i.fa.fa-spinner.fa-spin
+ .user-calendar-activities
+
+%ul.nav.center-middle-menu
+ %li.active
+ = link_to "#activity", 'data-toggle' => 'tab' do
+ Activity
+ - if @groups.any?
+ %li
+ = link_to "#groups", 'data-toggle' => 'tab' do
+ Groups
+ - if @contributed_projects.present?
+ %li
+ = link_to "#contributed", 'data-toggle' => 'tab' do
+ Contributed projects
+ - if @projects.present?
+ %li
+ = link_to "#personal", 'data-toggle' => 'tab' do
+ Personal projects
+
+.tab-content
+ .tab-pane.active#activity
.content_list
= spinner
- %aside.col-md-5
- = render 'profile', user: @user
- = render 'projects', projects: @projects, contributed_projects: @contributed_projects
+
+ - if @groups.any?
+ .tab-pane#groups
+ %ul.content-list
+ - @groups.each do |group|
+ = render 'shared/groups/group', group: group
+
+ - if @contributed_projects.present?
+ .tab-pane#contributed
+ .contributed-projects
+ = render 'shared/projects/list',
+ projects: @contributed_projects.sort_by(&:star_count).reverse,
+ projects_limit: 5, stars: true, avatar: false
+
+ - if @projects.present?
+ .tab-pane#personal
+ .personal-projects
+ = render 'shared/projects/list',
+ projects: @projects.sort_by(&:star_count).reverse,
+ projects_limit: 10, stars: true, avatar: false
:coffeescript
$(".user-calendar").load("#{user_calendar_path}")
diff --git a/app/workers/repository_archive_cache_worker.rb b/app/workers/repository_archive_cache_worker.rb
new file mode 100644
index 00000000000..47c5a670ed4
--- /dev/null
+++ b/app/workers/repository_archive_cache_worker.rb
@@ -0,0 +1,9 @@
+class RepositoryArchiveCacheWorker
+ include Sidekiq::Worker
+
+ sidekiq_options queue: :default
+
+ def perform
+ Repository.clean_old_archives
+ end
+end
diff --git a/app/workers/repository_archive_worker.rb b/app/workers/repository_archive_worker.rb
deleted file mode 100644
index 021c1139568..00000000000
--- a/app/workers/repository_archive_worker.rb
+++ /dev/null
@@ -1,43 +0,0 @@
-class RepositoryArchiveWorker
- include Sidekiq::Worker
-
- sidekiq_options queue: :archive_repo
-
- attr_accessor :project, :ref, :format
-
- def perform(project_id, ref, format)
- @project = Project.find(project_id)
- @ref, @format = ref, format.downcase
-
- repository = project.repository
-
- repository.clean_old_archives
-
- return unless file_path
- return if archived? || archiving?
-
- repository.archive_repo(ref, storage_path, format)
- end
-
- private
-
- def storage_path
- Gitlab.config.gitlab.repository_downloads_path
- end
-
- def file_path
- @file_path ||= project.repository.archive_file_path(ref, storage_path, format)
- end
-
- def pid_file_path
- @pid_file_path ||= project.repository.archive_pid_file_path(ref, storage_path, format)
- end
-
- def archived?
- File.exist?(file_path)
- end
-
- def archiving?
- File.exist?(pid_file_path)
- end
-end
diff --git a/app/workers/stuck_ci_builds_worker.rb b/app/workers/stuck_ci_builds_worker.rb
new file mode 100644
index 00000000000..ad02a3b16d9
--- /dev/null
+++ b/app/workers/stuck_ci_builds_worker.rb
@@ -0,0 +1,18 @@
+class StuckCiBuildsWorker
+ include Sidekiq::Worker
+ include Sidetiq::Schedulable
+
+ BUILD_STUCK_TIMEOUT = 1.day
+
+ recurrence { daily }
+
+ def perform
+ Rails.logger.info 'Cleaning stuck builds'
+
+ builds = Ci::Build.running_or_pending.where('updated_at < ?', BUILD_STUCK_TIMEOUT.ago)
+ builds.find_each(batch_size: 50).each do |build|
+ Rails.logger.debug "Dropping stuck #{build.status} build #{build.id} for runner #{build.runner_id}"
+ build.drop
+ end
+ end
+end