summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGELOG.md8
-rw-r--r--Gemfile4
-rw-r--r--Gemfile.lock10
-rw-r--r--app/assets/javascripts/api.js9
-rw-r--r--app/assets/javascripts/repo/components/repo_commit_section.vue4
-rw-r--r--app/assets/javascripts/repo/services/repo_service.js20
-rw-r--r--app/assets/stylesheets/framework/avatar.scss2
-rw-r--r--app/assets/stylesheets/framework/badges.scss2
-rw-r--r--app/assets/stylesheets/framework/blocks.scss4
-rw-r--r--app/assets/stylesheets/framework/buttons.scss2
-rw-r--r--app/assets/stylesheets/framework/calendar.scss6
-rw-r--r--app/assets/stylesheets/framework/common.scss16
-rw-r--r--app/assets/stylesheets/framework/dropdowns.scss12
-rw-r--r--app/assets/stylesheets/framework/filters.scss4
-rw-r--r--app/assets/stylesheets/framework/flash.scss2
-rw-r--r--app/assets/stylesheets/framework/forms.scss6
-rw-r--r--app/assets/stylesheets/framework/header.scss6
-rw-r--r--app/assets/stylesheets/framework/lists.scss4
-rw-r--r--app/assets/stylesheets/framework/mixins.scss2
-rw-r--r--app/assets/stylesheets/framework/modal.scss2
-rw-r--r--app/assets/stylesheets/framework/nav.scss4
-rw-r--r--app/assets/stylesheets/framework/page-header.scss2
-rw-r--r--app/assets/stylesheets/framework/selects.scss10
-rw-r--r--app/assets/stylesheets/framework/snippets.scss2
-rw-r--r--app/assets/stylesheets/framework/tables.scss2
-rw-r--r--app/assets/stylesheets/framework/tw_bootstrap.scss4
-rw-r--r--app/assets/stylesheets/framework/typography.scss12
-rw-r--r--app/assets/stylesheets/framework/variables.scss2
-rw-r--r--app/assets/stylesheets/framework/wells.scss2
-rw-r--r--app/assets/stylesheets/highlight/dark.scss8
-rw-r--r--app/assets/stylesheets/highlight/monokai.scss2
-rw-r--r--app/assets/stylesheets/highlight/solarized_dark.scss2
-rw-r--r--app/assets/stylesheets/highlight/solarized_light.scss2
-rw-r--r--app/assets/stylesheets/highlight/white.scss32
-rw-r--r--app/assets/stylesheets/mailers/highlighted_diff_email.scss32
-rw-r--r--app/assets/stylesheets/new_nav.scss10
-rw-r--r--app/assets/stylesheets/new_sidebar.scss8
-rw-r--r--app/assets/stylesheets/pages/boards.scss2
-rw-r--r--app/assets/stylesheets/pages/builds.scss4
-rw-r--r--app/assets/stylesheets/pages/ci_projects.scss2
-rw-r--r--app/assets/stylesheets/pages/commits.scss9
-rw-r--r--app/assets/stylesheets/pages/convdev_index.scss6
-rw-r--r--app/assets/stylesheets/pages/cycle_analytics.scss10
-rw-r--r--app/assets/stylesheets/pages/diff.scss6
-rw-r--r--app/assets/stylesheets/pages/environments.scss6
-rw-r--r--app/assets/stylesheets/pages/events.scss2
-rw-r--r--app/assets/stylesheets/pages/issuable.scss6
-rw-r--r--app/assets/stylesheets/pages/issues.scss4
-rw-r--r--app/assets/stylesheets/pages/login.scss8
-rw-r--r--app/assets/stylesheets/pages/members.scss4
-rw-r--r--app/assets/stylesheets/pages/merge_requests.scss16
-rw-r--r--app/assets/stylesheets/pages/milestone.scss4
-rw-r--r--app/assets/stylesheets/pages/note_form.scss2
-rw-r--r--app/assets/stylesheets/pages/pipeline_schedules.scss2
-rw-r--r--app/assets/stylesheets/pages/pipelines.scss12
-rw-r--r--app/assets/stylesheets/pages/profile.scss4
-rw-r--r--app/assets/stylesheets/pages/projects.scss16
-rw-r--r--app/assets/stylesheets/pages/repo.scss2
-rw-r--r--app/assets/stylesheets/pages/runners.scss2
-rw-r--r--app/assets/stylesheets/pages/search.scss2
-rw-r--r--app/assets/stylesheets/pages/sherlock.scss2
-rw-r--r--app/assets/stylesheets/pages/todos.scss6
-rw-r--r--app/assets/stylesheets/pages/tree.scss2
-rw-r--r--app/assets/stylesheets/pages/ui_dev_kit.scss2
-rw-r--r--app/assets/stylesheets/pages/wiki.scss4
-rw-r--r--app/assets/stylesheets/pages/xterm.scss2
-rw-r--r--app/assets/stylesheets/print.scss2
-rw-r--r--app/controllers/admin/logs_controller.rb9
-rw-r--r--app/controllers/admin/projects_controller.rb6
-rw-r--r--app/controllers/projects/services_controller.rb9
-rw-r--r--app/finders/admin/projects_finder.rb80
-rw-r--r--app/finders/projects_finder.rb17
-rw-r--r--app/helpers/avatars_helper.rb11
-rw-r--r--app/helpers/commits_helper.rb2
-rw-r--r--app/helpers/events_helper.rb1
-rw-r--r--app/models/ci/build.rb5
-rw-r--r--app/models/ci/pipeline.rb3
-rw-r--r--app/models/event.rb2
-rw-r--r--app/models/issue.rb7
-rw-r--r--app/models/merge_request.rb8
-rw-r--r--app/models/project.rb9
-rw-r--r--app/models/repository.rb13
-rw-r--r--app/services/groups/nested_create_service.rb45
-rw-r--r--app/services/issuable_base_service.rb4
-rw-r--r--app/services/issues/create_service.rb2
-rw-r--r--app/services/merge_requests/create_service.rb2
-rw-r--r--app/services/projects/count_service.rb43
-rw-r--r--app/services/projects/forks_count_service.rb28
-rw-r--r--app/services/projects/open_issues_count_service.rb15
-rw-r--r--app/services/projects/open_merge_requests_count_service.rb13
-rw-r--r--app/views/admin/logs/show.html.haml16
-rw-r--r--app/views/events/_event_push.atom.haml13
-rw-r--r--app/views/events/event/_push.html.haml4
-rw-r--r--app/views/layouts/errors.html.haml4
-rw-r--r--app/views/layouts/nav/_new_project_sidebar.html.haml6
-rw-r--r--app/views/layouts/nav/_project.html.haml6
-rw-r--r--app/views/layouts/oauth_error.html.haml2
-rw-r--r--app/views/projects/_project_templates.html.haml2
-rw-r--r--app/views/projects/commits/_commit.html.haml6
-rw-r--r--app/views/projects/runners/_runner.html.haml2
-rw-r--r--app/views/shared/issuable/_user_dropdown_item.html.haml2
-rw-r--r--app/views/shared/projects/_dropdown.html.haml5
-rw-r--r--app/workers/namespaceless_project_destroy_worker.rb3
-rw-r--r--changelogs/unreleased/13719-git-gc-timeout.yml3
-rw-r--r--changelogs/unreleased/35994-archived-projects-only.yml5
-rw-r--r--changelogs/unreleased/36262_merge_request_reference_in_merge_commit_global.yml5
-rw-r--r--changelogs/unreleased/backstage-gb-after-save-asynchronous-job-hooks.yml5
-rw-r--r--changelogs/unreleased/bvl-improve-bare-project-import.yml6
-rw-r--r--changelogs/unreleased/cache-issue-and-mr-counts.yml5
-rw-r--r--changelogs/unreleased/dm-commit-cache-i18n.yml5
-rw-r--r--changelogs/unreleased/dm-ldap-adapter-attributes.yml6
-rw-r--r--changelogs/unreleased/fix-broadcast-message-caching.yml5
-rw-r--r--changelogs/unreleased/fix-gb-fix-head-pipeline-when-pipeline-has-errors.yml5
-rw-r--r--changelogs/unreleased/fix-old-mr-diffs.yml6
-rw-r--r--changelogs/unreleased/fix-push-events-branch-removals.yml5
-rw-r--r--changelogs/unreleased/font-weight-adjusted.yml5
-rw-r--r--changelogs/unreleased/only-limit-fetch-when-requested.yml5
-rw-r--r--changelogs/unreleased/rd-fix-broken-configuration-for-some-integrations.yml5
-rw-r--r--changelogs/unreleased/tc-remove-nonexisting-namespace-pending-delete-projects.yml5
-rw-r--r--changelogs/unreleased/use_full_path_in_project_avatar_url_webhook.yml5
-rw-r--r--changelogs/unreleased/zj-add-pipeline-source-variable.yml5
-rw-r--r--changelogs/unreleased/zj-fix-fe-blank-button.yml5
-rw-r--r--db/post_migrate/20170816102555_cleanup_nonexisting_namespace_pending_delete_projects.rb54
-rw-r--r--doc/ci/variables/README.md1
-rw-r--r--doc/development/licensing.md2
-rw-r--r--features/steps/project/pages.rb6
-rw-r--r--lib/github/import.rb2
-rw-r--r--lib/gitlab/bare_repository_importer.rb96
-rw-r--r--lib/gitlab/diff/file.rb11
-rw-r--r--lib/gitlab/git/commit.rb8
-rw-r--r--lib/gitlab/git/repository.rb25
-rw-r--r--lib/gitlab/gitaly_client/commit_service.rb14
-rw-r--r--lib/gitlab/gitaly_client/ref_service.rb2
-rw-r--r--lib/gitlab/ldap/adapter.rb6
-rw-r--r--lib/gitlab/ldap/person.rb9
-rw-r--r--lib/gitlab/logger.rb8
-rw-r--r--lib/tasks/gitlab/import.rake65
-rw-r--r--lib/tasks/import.rake18
-rw-r--r--public/404.html6
-rw-r--r--public/422.html6
-rw-r--r--public/500.html6
-rw-r--r--public/502.html6
-rw-r--r--public/503.html6
-rw-r--r--public/deploy.html6
-rw-r--r--spec/controllers/projects/services_controller_spec.rb42
-rw-r--r--spec/features/admin/admin_projects_spec.rb8
-rw-r--r--spec/features/calendar_spec.rb2
-rw-r--r--spec/features/dashboard/activity_spec.rb2
-rw-r--r--spec/features/dashboard/archived_projects_spec.rb7
-rw-r--r--spec/features/merge_requests/merge_commit_message_toggle_spec.rb4
-rw-r--r--spec/features/runners_spec.rb198
-rw-r--r--spec/finders/admin/projects_finder_spec.rb6
-rw-r--r--spec/finders/projects_finder_spec.rb6
-rw-r--r--spec/fixtures/emails/ios_default.eml12
-rw-r--r--spec/fixtures/emails/on_wrote.eml6
-rw-r--r--spec/helpers/avatars_helper_spec.rb42
-rw-r--r--spec/helpers/events_helper_spec.rb4
-rw-r--r--spec/javascripts/repo/components/repo_commit_section_spec.js9
-rw-r--r--spec/javascripts/repo/services/repo_service_spec.js50
-rw-r--r--spec/lib/gitlab/bare_repository_importer_spec.rb68
-rw-r--r--spec/lib/gitlab/diff/file_spec.rb58
-rw-r--r--spec/lib/gitlab/git/repository_spec.rb58
-rw-r--r--spec/lib/gitlab/git/storage/forked_storage_check_spec.rb2
-rw-r--r--spec/lib/gitlab/gitaly_client/commit_service_spec.rb25
-rw-r--r--spec/lib/gitlab/ldap/adapter_spec.rb6
-rw-r--r--spec/migrations/cleanup_nonexisting_namespace_pending_delete_projects_spec.rb32
-rw-r--r--spec/models/ci/build_spec.rb10
-rw-r--r--spec/models/ci/pipeline_spec.rb14
-rw-r--r--spec/models/event_spec.rb44
-rw-r--r--spec/models/issue_spec.rb18
-rw-r--r--spec/models/merge_request_spec.rb11
-rw-r--r--spec/models/user_spec.rb2
-rw-r--r--spec/services/groups/nested_create_service_spec.rb53
-rw-r--r--spec/services/issues/close_service_spec.rb5
-rw-r--r--spec/services/issues/create_service_spec.rb4
-rw-r--r--spec/services/issues/reopen_service_spec.rb7
-rw-r--r--spec/services/merge_requests/close_service_spec.rb7
-rw-r--r--spec/services/merge_requests/create_service_spec.rb32
-rw-r--r--spec/services/merge_requests/reopen_service_spec.rb7
-rw-r--r--spec/services/projects/count_service_spec.rb73
-rw-r--r--spec/services/projects/forks_count_service_spec.rb32
-rw-r--r--spec/services/projects/open_issues_count_service_spec.rb21
-rw-r--r--spec/services/projects/open_merge_requests_count_service_spec.rb15
-rw-r--r--spec/spec_helper.rb12
-rw-r--r--spec/support/cycle_analytics_helpers.rb2
-rw-r--r--spec/support/db_cleaner.rb6
-rw-r--r--spec/workers/build_finished_worker_spec.rb2
-rw-r--r--spec/workers/namespaceless_project_destroy_worker_spec.rb14
-rw-r--r--vendor/assets/stylesheets/katex.scss34
-rw-r--r--vendor/assets/stylesheets/xterm/xterm.css2
190 files changed, 1687 insertions, 663 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 1d969164cfe..d32b6989388 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,6 +2,14 @@
documentation](doc/development/changelog.md) for instructions on adding your own
entry.
+## 9.5.1 (2017-08-23)
+
+- [FIXED] Fix merge request pipeline status when pipeline has errors. !13664
+- [FIXED] Commit rows would occasionally render with the wrong language.
+- [FIXED] Fix caching of future broadcast messages.
+- [FIXED] Only require Sidekiq throttling library when enabled, to reduce cache misses.
+- Raise Housekeeping timeout to 24 hours. !13719
+
## 9.5.0 (2017-08-22)
- [FIXED] Fix timeouts when creating projects in groups with many members. !13508
diff --git a/Gemfile b/Gemfile
index a0a9dddac10..72fc2de426e 100644
--- a/Gemfile
+++ b/Gemfile
@@ -396,12 +396,12 @@ gem 'net-ssh', '~> 4.1.0'
# Required for ED25519 SSH host key support
group :ed25519 do
gem 'rbnacl-libsodium'
- gem 'rbnacl', '~> 3.2'
+ gem 'rbnacl', '~> 4.0'
gem 'bcrypt_pbkdf', '~> 1.0'
end
# Gitaly GRPC client
-gem 'gitaly', '~> 0.29.0'
+gem 'gitaly', '~> 0.30.0'
gem 'toml-rb', '~> 0.3.15', require: false
diff --git a/Gemfile.lock b/Gemfile.lock
index ec8349cd1df..7d3c53ee010 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -203,7 +203,7 @@ GEM
multi_json
fast_gettext (1.4.0)
ffaker (2.4.0)
- ffi (1.9.10)
+ ffi (1.9.18)
flay (2.8.1)
erubis (~> 2.7.0)
path_expander (~> 1.0)
@@ -275,7 +275,7 @@ GEM
po_to_json (>= 1.0.0)
rails (>= 3.2.0)
gherkin-ruby (0.3.2)
- gitaly (0.29.0)
+ gitaly (0.30.0)
google-protobuf (~> 3.1)
grpc (~> 1.0)
github-linguist (4.7.6)
@@ -682,7 +682,7 @@ GEM
rake (12.0.0)
rblineprof (0.3.6)
debugger-ruby_core_source (~> 1.3)
- rbnacl (3.4.0)
+ rbnacl (4.0.2)
ffi
rbnacl-libsodium (1.0.11)
rbnacl (>= 3.0.1)
@@ -1019,7 +1019,7 @@ DEPENDENCIES
gettext (~> 3.2.2)
gettext_i18n_rails (~> 1.8.0)
gettext_i18n_rails_js (~> 1.2.0)
- gitaly (~> 0.29.0)
+ gitaly (~> 0.30.0)
github-linguist (~> 4.7.0)
gitlab-flowdock-git-hook (~> 1.0.1)
gitlab-markup (~> 1.5.1)
@@ -1107,7 +1107,7 @@ DEPENDENCIES
rainbow (~> 2.2)
raindrops (~> 0.18)
rblineprof (~> 0.3.6)
- rbnacl (~> 3.2)
+ rbnacl (~> 4.0)
rbnacl-libsodium
rdoc (~> 4.2)
re2 (~> 1.1.1)
diff --git a/app/assets/javascripts/api.js b/app/assets/javascripts/api.js
index 56f91e95bb9..4319bfcc57f 100644
--- a/app/assets/javascripts/api.js
+++ b/app/assets/javascripts/api.js
@@ -96,18 +96,17 @@ const Api = {
.done(projects => callback(projects));
},
- commitMultiple(id, data, callback) {
+ commitMultiple(id, data) {
+ // see https://docs.gitlab.com/ce/api/commits.html#create-a-commit-with-multiple-files-and-actions
const url = Api.buildUrl(Api.commitPath)
.replace(':id', id);
- return $.ajax({
+ return this.wrapAjaxCall({
url,
type: 'POST',
contentType: 'application/json; charset=utf-8',
data: JSON.stringify(data),
dataType: 'json',
- })
- .done(commitData => callback(commitData))
- .fail(message => callback(message.responseJSON));
+ });
},
// Return text for a specific license
diff --git a/app/assets/javascripts/repo/components/repo_commit_section.vue b/app/assets/javascripts/repo/components/repo_commit_section.vue
index 5ec4a9b6593..1282828b504 100644
--- a/app/assets/javascripts/repo/components/repo_commit_section.vue
+++ b/app/assets/javascripts/repo/components/repo_commit_section.vue
@@ -42,7 +42,9 @@ export default {
actions,
};
Store.submitCommitsLoading = true;
- Service.commitFiles(payload, this.resetCommitState);
+ Service.commitFiles(payload)
+ .then(this.resetCommitState)
+ .catch(() => Flash('An error occured while committing your changes'));
},
resetCommitState() {
diff --git a/app/assets/javascripts/repo/services/repo_service.js b/app/assets/javascripts/repo/services/repo_service.js
index 3cf204e6ec8..af83497fa39 100644
--- a/app/assets/javascripts/repo/services/repo_service.js
+++ b/app/assets/javascripts/repo/services/repo_service.js
@@ -65,15 +65,17 @@ const RepoService = {
return urlArray.join('/');
},
- commitFiles(payload, cb) {
- Api.commitMultiple(Store.projectId, payload, (data) => {
- if (data.short_id && data.stats) {
- Flash(`Your changes have been committed. Commit ${data.short_id} with ${data.stats.additions} additions, ${data.stats.deletions} deletions.`, 'notice');
- } else {
- Flash(data.message);
- }
- cb();
- });
+ commitFiles(payload) {
+ return Api.commitMultiple(Store.projectId, payload)
+ .then(this.commitFlash);
+ },
+
+ commitFlash(data) {
+ if (data.short_id && data.stats) {
+ window.Flash(`Your changes have been committed. Commit ${data.short_id} with ${data.stats.additions} additions, ${data.stats.deletions} deletions.`, 'notice');
+ } else {
+ window.Flash(data.message);
+ }
},
};
diff --git a/app/assets/stylesheets/framework/avatar.scss b/app/assets/stylesheets/framework/avatar.scss
index 486d88efbc5..bdcbd4021b3 100644
--- a/app/assets/stylesheets/framework/avatar.scss
+++ b/app/assets/stylesheets/framework/avatar.scss
@@ -78,7 +78,7 @@
&.s60 { font-size: 32px; line-height: 58px; }
&.s70 { font-size: 34px; line-height: 70px; }
&.s90 { font-size: 36px; line-height: 88px; }
- &.s110 { font-size: 40px; line-height: 108px; font-weight: 300; }
+ &.s110 { font-size: 40px; line-height: 108px; font-weight: $gl-font-weight-normal; }
&.s140 { font-size: 72px; line-height: 138px; }
&.s160 { font-size: 96px; line-height: 158px; }
}
diff --git a/app/assets/stylesheets/framework/badges.scss b/app/assets/stylesheets/framework/badges.scss
index 47a8f44c709..6bbe32df772 100644
--- a/app/assets/stylesheets/framework/badges.scss
+++ b/app/assets/stylesheets/framework/badges.scss
@@ -1,5 +1,5 @@
.badge {
- font-weight: normal;
+ font-weight: $gl-font-weight-normal;
background-color: $badge-bg;
color: $badge-color;
vertical-align: baseline;
diff --git a/app/assets/stylesheets/framework/blocks.scss b/app/assets/stylesheets/framework/blocks.scss
index 95a08c960ea..b575ec9de18 100644
--- a/app/assets/stylesheets/framework/blocks.scss
+++ b/app/assets/stylesheets/framework/blocks.scss
@@ -8,7 +8,7 @@
text-align: center;
padding: 20px;
color: $gl-text-color;
- font-weight: normal;
+ font-weight: $gl-font-weight-normal;
font-size: 14px;
line-height: 36px;
@@ -213,7 +213,7 @@
h1 {
display: inline;
- font-weight: normal;
+ font-weight: $gl-font-weight-normal;
font-size: 24px;
color: $gl-text-color;
}
diff --git a/app/assets/stylesheets/framework/buttons.scss b/app/assets/stylesheets/framework/buttons.scss
index 6eabdc63d9e..b4a6b214e98 100644
--- a/app/assets/stylesheets/framework/buttons.scss
+++ b/app/assets/stylesheets/framework/buttons.scss
@@ -1,7 +1,7 @@
@mixin btn-default {
border-radius: 3px;
font-size: $gl-font-size;
- font-weight: 400;
+ font-weight: $gl-font-weight-normal;
padding: $gl-vert-padding $gl-btn-padding;
&:focus,
diff --git a/app/assets/stylesheets/framework/calendar.scss b/app/assets/stylesheets/framework/calendar.scss
index 0ded4a3b423..4ce767e4cc4 100644
--- a/app/assets/stylesheets/framework/calendar.scss
+++ b/app/assets/stylesheets/framework/calendar.scss
@@ -52,13 +52,13 @@
.pika-label {
color: $gl-text-color-secondary;
font-size: 14px;
- font-weight: normal;
+ font-weight: $gl-font-weight-normal;
}
th {
padding: 2px 0;
color: $note-disabled-comment-color;
- font-weight: normal;
+ font-weight: $gl-font-weight-normal;
text-transform: lowercase;
border-top: 1px solid $calendar-border-color;
}
@@ -88,7 +88,7 @@
.is-today {
.pika-day {
color: inherit;
- font-weight: normal;
+ font-weight: $gl-font-weight-normal;
}
}
diff --git a/app/assets/stylesheets/framework/common.scss b/app/assets/stylesheets/framework/common.scss
index 293aa194528..e16fbbf43b5 100644
--- a/app/assets/stylesheets/framework/common.scss
+++ b/app/assets/stylesheets/framework/common.scss
@@ -36,12 +36,12 @@
color: $common-gray;
font-size: 14px;
margin-bottom: 12px;
- font-weight: normal;
+ font-weight: $gl-font-weight-normal;
line-height: 24px;
}
.bold {
- font-weight: 600;
+ font-weight: $gl-font-weight-bold;
}
.tab-content {
@@ -89,7 +89,7 @@ hr {
}
}
-.item-title { font-weight: 600; }
+.item-title { font-weight: $gl-font-weight-bold; }
/** FLASH message **/
.author_link,
@@ -118,18 +118,18 @@ table a code {
span.update-author {
display: block;
color: $update-author-color;
- font-weight: normal;
+ font-weight: $gl-font-weight-normal;
font-style: italic;
strong {
- font-weight: bold;
+ font-weight: $gl-font-weight-bold;
font-style: normal;
}
}
.user-mention {
color: $user-mention-color;
- font-weight: bold;
+ font-weight: $gl-font-weight-bold;
}
.field_with_errors {
@@ -222,7 +222,7 @@ li.note {
text-align: center;
background: $error-bg;
color: $white-light;
- font-weight: bold;
+ font-weight: $gl-font-weight-bold;
a {
color: $white-light;
@@ -339,7 +339,7 @@ table {
.header-with-avatar {
h3 {
margin: 0;
- font-weight: bold;
+ font-weight: $gl-font-weight-bold;
}
.username {
diff --git a/app/assets/stylesheets/framework/dropdowns.scss b/app/assets/stylesheets/framework/dropdowns.scss
index 5f270e288ae..a45d5a6dca0 100644
--- a/app/assets/stylesheets/framework/dropdowns.scss
+++ b/app/assets/stylesheets/framework/dropdowns.scss
@@ -195,7 +195,7 @@
margin-top: 2px;
margin-bottom: 0;
font-size: 14px;
- font-weight: normal;
+ font-weight: $gl-font-weight-normal;
padding: 8px 0;
background-color: $white-light;
border: 1px solid $dropdown-border-color;
@@ -268,7 +268,7 @@
}
.dropdown-bold-header {
- font-weight: 600;
+ font-weight: $gl-font-weight-bold;
line-height: 22px;
padding: 0 16px;
}
@@ -432,7 +432,7 @@
.dropdown-menu-user-full-name {
display: block;
- font-weight: 500;
+ font-weight: $gl-font-weight-normal;
line-height: 16px;
text-overflow: ellipsis;
overflow: hidden;
@@ -468,7 +468,7 @@
&.is-indeterminate,
&.is-active {
- font-weight: 600;
+ font-weight: $gl-font-weight-bold;
color: $gl-text-color;
&::before {
@@ -502,7 +502,7 @@
position: relative;
padding: 2px 25px 10px;
margin: 0 10px 10px;
- font-weight: 600;
+ font-weight: $gl-font-weight-bold;
line-height: 1;
text-align: center;
text-overflow: ellipsis;
@@ -685,7 +685,7 @@
.dropdown-menu-inner-title {
display: block;
color: $gl-text-color;
- font-weight: 600;
+ font-weight: $gl-font-weight-bold;
}
.dropdown-menu-inner-content {
diff --git a/app/assets/stylesheets/framework/filters.scss b/app/assets/stylesheets/framework/filters.scss
index 8dcaa879b3f..a5d33d410fb 100644
--- a/app/assets/stylesheets/framework/filters.scss
+++ b/app/assets/stylesheets/framework/filters.scss
@@ -371,7 +371,7 @@
}
> .value {
- font-weight: 600;
+ font-weight: $gl-font-weight-bold;
}
}
@@ -452,7 +452,7 @@
.dropdown-light-content {
font-size: 14px;
- font-weight: 400;
+ font-weight: $gl-font-weight-normal;
}
.dropdown-user {
diff --git a/app/assets/stylesheets/framework/flash.scss b/app/assets/stylesheets/framework/flash.scss
index 38d884bc7eb..e1b086ebb2b 100644
--- a/app/assets/stylesheets/framework/flash.scss
+++ b/app/assets/stylesheets/framework/flash.scss
@@ -25,7 +25,7 @@
a.flash-action {
margin-left: 5px;
text-decoration: none;
- font-weight: normal;
+ font-weight: $gl-font-weight-normal;
border-bottom: 1px solid;
&:hover {
diff --git a/app/assets/stylesheets/framework/forms.scss b/app/assets/stylesheets/framework/forms.scss
index 61e3897f369..be96c8ee964 100644
--- a/app/assets/stylesheets/framework/forms.scss
+++ b/app/assets/stylesheets/framework/forms.scss
@@ -32,7 +32,7 @@ label {
}
&.label-light {
- font-weight: 600;
+ font-weight: $gl-font-weight-bold;
}
}
@@ -73,7 +73,7 @@ label {
margin-right: 0;
.control-label {
- font-weight: bold;
+ font-weight: $gl-font-weight-bold;
padding-top: 4px;
}
@@ -157,7 +157,7 @@ label {
.form-group .control-label,
.form-group .control-label-full-width {
- font-weight: normal;
+ font-weight: $gl-font-weight-normal;
}
.form-control::-webkit-input-placeholder {
diff --git a/app/assets/stylesheets/framework/header.scss b/app/assets/stylesheets/framework/header.scss
index b677882eba4..35bd97980e2 100644
--- a/app/assets/stylesheets/framework/header.scss
+++ b/app/assets/stylesheets/framework/header.scss
@@ -160,7 +160,7 @@ header {
li {
&.active a {
- font-weight: bold;
+ font-weight: $gl-font-weight-bold;
}
}
}
@@ -250,7 +250,7 @@ header {
font-size: 18px;
line-height: 22px;
display: inline-block;
- font-weight: normal;
+ font-weight: $gl-font-weight-normal;
color: $gl-text-color;
vertical-align: top;
white-space: nowrap;
@@ -326,7 +326,7 @@ header {
.badge {
position: inherit;
top: -8px;
- font-weight: normal;
+ font-weight: $gl-font-weight-normal;
margin-left: -11px;
font-size: 11px;
color: $white-light;
diff --git a/app/assets/stylesheets/framework/lists.scss b/app/assets/stylesheets/framework/lists.scss
index df2bf561194..0fb19344510 100644
--- a/app/assets/stylesheets/framework/lists.scss
+++ b/app/assets/stylesheets/framework/lists.scss
@@ -113,7 +113,7 @@ ul.content-list {
}
.title {
- font-weight: 600;
+ font-weight: $gl-font-weight-bold;
}
a {
@@ -212,7 +212,7 @@ ul.content-list {
}
.row-title {
- font-weight: 600;
+ font-weight: $gl-font-weight-bold;
}
.row-second-line {
diff --git a/app/assets/stylesheets/framework/mixins.scss b/app/assets/stylesheets/framework/mixins.scss
index 6f91d11b369..d40b65bb2cc 100644
--- a/app/assets/stylesheets/framework/mixins.scss
+++ b/app/assets/stylesheets/framework/mixins.scss
@@ -43,7 +43,7 @@
background: $gray-light;
a {
- font-weight: 600;
+ font-weight: $gl-font-weight-bold;
}
}
diff --git a/app/assets/stylesheets/framework/modal.scss b/app/assets/stylesheets/framework/modal.scss
index a28f54936be..d1f00d3ee2c 100644
--- a/app/assets/stylesheets/framework/modal.scss
+++ b/app/assets/stylesheets/framework/modal.scss
@@ -8,7 +8,7 @@
}
.text-danger {
- font-weight: bold;
+ font-weight: $gl-font-weight-bold;
}
}
diff --git a/app/assets/stylesheets/framework/nav.scss b/app/assets/stylesheets/framework/nav.scss
index 071f20fc457..e20108b171b 100644
--- a/app/assets/stylesheets/framework/nav.scss
+++ b/app/assets/stylesheets/framework/nav.scss
@@ -70,7 +70,7 @@
&.active a {
border-bottom: 2px solid $link-underline-blue;
color: $black;
- font-weight: 600;
+ font-weight: $gl-font-weight-bold;
.badge {
color: $black;
@@ -352,7 +352,7 @@
z-index: 300;
li.active {
- font-weight: bold;
+ font-weight: $gl-font-weight-bold;
}
}
}
diff --git a/app/assets/stylesheets/framework/page-header.scss b/app/assets/stylesheets/framework/page-header.scss
index f1ecd050a0a..0c879f40930 100644
--- a/app/assets/stylesheets/framework/page-header.scss
+++ b/app/assets/stylesheets/framework/page-header.scss
@@ -43,7 +43,7 @@
.commit-committer-link,
.commit-author-link {
color: $gl-text-color;
- font-weight: bold;
+ font-weight: $gl-font-weight-bold;
}
.commit-info {
diff --git a/app/assets/stylesheets/framework/selects.scss b/app/assets/stylesheets/framework/selects.scss
index f7a0b355bf1..d93722e2174 100644
--- a/app/assets/stylesheets/framework/selects.scss
+++ b/app/assets/stylesheets/framework/selects.scss
@@ -76,7 +76,7 @@
}
.select2-results li.select2-result-with-children > .select2-result-label {
- font-weight: 600;
+ font-weight: $gl-font-weight-bold;
color: $gl-text-color;
}
@@ -227,7 +227,7 @@
}
.group-name {
- font-weight: bold;
+ font-weight: $gl-font-weight-bold;
}
.group-path {
@@ -252,12 +252,12 @@
.namespace-result {
.namespace-kind {
color: $namespace-kind-color;
- font-weight: normal;
+ font-weight: $gl-font-weight-normal;
}
.namespace-path {
margin-left: 10px;
- font-weight: bolder;
+ font-weight: $gl-font-weight-bold;
}
}
@@ -283,7 +283,7 @@
padding: 0 1px;
.select2-match {
- font-weight: bold;
+ font-weight: $gl-font-weight-bold;
text-decoration: none;
}
diff --git a/app/assets/stylesheets/framework/snippets.scss b/app/assets/stylesheets/framework/snippets.scss
index 5f7e1b17cc7..30c15c231d5 100644
--- a/app/assets/stylesheets/framework/snippets.scss
+++ b/app/assets/stylesheets/framework/snippets.scss
@@ -30,7 +30,7 @@
.snippet-title {
font-size: 24px;
- font-weight: 600;
+ font-weight: $gl-font-weight-bold;
}
.snippet-edited-ago {
diff --git a/app/assets/stylesheets/framework/tables.scss b/app/assets/stylesheets/framework/tables.scss
index 6d9fa74a030..4dd31bf28cd 100644
--- a/app/assets/stylesheets/framework/tables.scss
+++ b/app/assets/stylesheets/framework/tables.scss
@@ -32,7 +32,7 @@ table {
th {
background-color: $gray-light;
- font-weight: normal;
+ font-weight: $gl-font-weight-normal;
border-bottom: none;
&.wide {
diff --git a/app/assets/stylesheets/framework/tw_bootstrap.scss b/app/assets/stylesheets/framework/tw_bootstrap.scss
index e54cc2866a7..d5c6ddbb4a5 100644
--- a/app/assets/stylesheets/framework/tw_bootstrap.scss
+++ b/app/assets/stylesheets/framework/tw_bootstrap.scss
@@ -103,7 +103,7 @@ summary {
padding: 4px 5px;
font-size: 12px;
font-style: normal;
- font-weight: normal;
+ font-weight: $gl-font-weight-normal;
display: inline-block;
&.label-gray {
@@ -165,7 +165,7 @@ summary {
.panel-heading {
padding: 6px 15px;
font-size: 13px;
- font-weight: normal;
+ font-weight: $gl-font-weight-normal;
a {
color: $panel-heading-link-color;
diff --git a/app/assets/stylesheets/framework/typography.scss b/app/assets/stylesheets/framework/typography.scss
index d13f9996518..71eec0e1a5e 100644
--- a/app/assets/stylesheets/framework/typography.scss
+++ b/app/assets/stylesheets/framework/typography.scss
@@ -74,7 +74,7 @@
h1 {
font-size: 1.75em;
- font-weight: 600;
+ font-weight: $gl-font-weight-bold;
margin: 24px 0 16px;
padding-bottom: 0.3em;
border-bottom: 1px solid $white-dark;
@@ -87,7 +87,7 @@
h2 {
font-size: 1.5em;
- font-weight: 600;
+ font-weight: $gl-font-weight-bold;
margin: 24px 0 16px;
padding-bottom: 0.3em;
border-bottom: 1px solid $white-dark;
@@ -280,7 +280,7 @@ body {
margin-top: $gl-padding;
line-height: 1.3;
font-size: 1.25em;
- font-weight: 600;
+ font-weight: $gl-font-weight-bold;
&:last-child {
margin-bottom: 0;
@@ -291,7 +291,7 @@ body {
margin-top: 0;
line-height: 1.3;
font-size: 1.25em;
- font-weight: 600;
+ font-weight: $gl-font-weight-bold;
margin: 12px 7px;
}
@@ -302,11 +302,11 @@ h4,
h5,
h6 {
color: $gl-text-color;
- font-weight: 600;
+ font-weight: $gl-font-weight-bold;
}
.light-header {
- font-weight: 600;
+ font-weight: $gl-font-weight-bold;
}
/** CODE **/
diff --git a/app/assets/stylesheets/framework/variables.scss b/app/assets/stylesheets/framework/variables.scss
index 225d116e9c7..8a2e64f7bf5 100644
--- a/app/assets/stylesheets/framework/variables.scss
+++ b/app/assets/stylesheets/framework/variables.scss
@@ -111,6 +111,8 @@ $well-light-text-color: #5b6169;
* Text
*/
$gl-font-size: 14px;
+$gl-font-weight-normal: 400;
+$gl-font-weight-bold: 600;
$gl-text-color: #2e2e2e;
$gl-text-color-secondary: #707070;
$gl-text-color-tertiary: #949494;
diff --git a/app/assets/stylesheets/framework/wells.scss b/app/assets/stylesheets/framework/wells.scss
index b1ff2659131..5f9756bf58a 100644
--- a/app/assets/stylesheets/framework/wells.scss
+++ b/app/assets/stylesheets/framework/wells.scss
@@ -69,7 +69,7 @@
.well-centered {
h1 {
- font-weight: normal;
+ font-weight: $gl-font-weight-normal;
text-align: center;
font-size: 48px;
}
diff --git a/app/assets/stylesheets/highlight/dark.scss b/app/assets/stylesheets/highlight/dark.scss
index 6e3829d994f..f0ac9b46f91 100644
--- a/app/assets/stylesheets/highlight/dark.scss
+++ b/app/assets/stylesheets/highlight/dark.scss
@@ -204,11 +204,11 @@ $dark-il: #de935f;
.cs { color: $dark-cs; } /* Comment.Special */
.gd { color: $dark-gd; } /* Generic.Deleted */
.ge { font-style: italic; } /* Generic.Emph */
- .gh { color: $dark-gh; font-weight: bold; } /* Generic.Heading */
+ .gh { color: $dark-gh; font-weight: $gl-font-weight-bold; } /* Generic.Heading */
.gi { color: $dark-gi; } /* Generic.Inserted */
- .gp { color: $dark-gp; font-weight: bold; } /* Generic.Prompt */
- .gs { font-weight: bold; } /* Generic.Strong */
- .gu { color: $dark-gu; font-weight: bold; } /* Generic.Subheading */
+ .gp { color: $dark-gp; font-weight: $gl-font-weight-bold; } /* Generic.Prompt */
+ .gs { font-weight: $gl-font-weight-bold; } /* Generic.Strong */
+ .gu { color: $dark-gu; font-weight: $gl-font-weight-bold; } /* Generic.Subheading */
.kc { color: $dark-kc; } /* Keyword.Constant */
.kd { color: $dark-kd; } /* Keyword.Declaration */
.kn { color: $dark-kn; } /* Keyword.Namespace */
diff --git a/app/assets/stylesheets/highlight/monokai.scss b/app/assets/stylesheets/highlight/monokai.scss
index 68eb0c7720f..eba7919ada9 100644
--- a/app/assets/stylesheets/highlight/monokai.scss
+++ b/app/assets/stylesheets/highlight/monokai.scss
@@ -203,7 +203,7 @@ $monokai-gi: #a6e22e;
.c1 { color: $monokai-c1; } /* Comment.Single */
.cs { color: $monokai-cs; } /* Comment.Special */
.ge { font-style: italic; } /* Generic.Emph */
- .gs { font-weight: bold; } /* Generic.Strong */
+ .gs { font-weight: $gl-font-weight-bold; } /* Generic.Strong */
.kc { color: $monokai-kc; } /* Keyword.Constant */
.kd { color: $monokai-kd; } /* Keyword.Declaration */
.kn { color: $monokai-kn; } /* Keyword.Namespace */
diff --git a/app/assets/stylesheets/highlight/solarized_dark.scss b/app/assets/stylesheets/highlight/solarized_dark.scss
index 2cc968c32f2..ba53ef0352b 100644
--- a/app/assets/stylesheets/highlight/solarized_dark.scss
+++ b/app/assets/stylesheets/highlight/solarized_dark.scss
@@ -231,7 +231,7 @@ $solarized-dark-il: #2aa198;
.gi { color: $solarized-dark-gi; } /* Generic.Inserted */
.go { color: $solarized-dark-go; } /* Generic.Output */
.gp { color: $solarized-dark-gp; } /* Generic.Prompt */
- .gs { color: $solarized-dark-gs; font-weight: bold; } /* Generic.Strong */
+ .gs { color: $solarized-dark-gs; font-weight: $gl-font-weight-bold; } /* Generic.Strong */
.gu { color: $solarized-dark-gu; } /* Generic.Subheading */
.gt { color: $solarized-dark-gt; } /* Generic.Traceback */
.kc { color: $solarized-dark-kc; } /* Keyword.Constant */
diff --git a/app/assets/stylesheets/highlight/solarized_light.scss b/app/assets/stylesheets/highlight/solarized_light.scss
index b61b85a2cd1..e9fccf1b58a 100644
--- a/app/assets/stylesheets/highlight/solarized_light.scss
+++ b/app/assets/stylesheets/highlight/solarized_light.scss
@@ -239,7 +239,7 @@ $solarized-light-il: #2aa198;
.gi { color: $solarized-light-gi; } /* Generic.Inserted */
.go { color: $solarized-light-go; } /* Generic.Output */
.gp { color: $solarized-light-gp; } /* Generic.Prompt */
- .gs { color: $solarized-light-gs; font-weight: bold; } /* Generic.Strong */
+ .gs { color: $solarized-light-gs; font-weight: $gl-font-weight-bold; } /* Generic.Strong */
.gu { color: $solarized-light-gu; } /* Generic.Subheading */
.gt { color: $solarized-light-gt; } /* Generic.Traceback */
.kc { color: $solarized-light-kc; } /* Keyword.Constant */
diff --git a/app/assets/stylesheets/highlight/white.scss b/app/assets/stylesheets/highlight/white.scss
index 578f1902cce..65b140cd7f8 100644
--- a/app/assets/stylesheets/highlight/white.scss
+++ b/app/assets/stylesheets/highlight/white.scss
@@ -211,12 +211,12 @@ $white-gc-bg: #eaf2f5;
.hll { background-color: $white-hll-bg; }
.c { color: $white-c; font-style: italic; }
.err { color: $white-err; background-color: $white-err-bg; }
- .k { font-weight: bold; }
- .o { font-weight: bold; }
+ .k { font-weight: $gl-font-weight-bold; }
+ .o { font-weight: $gl-font-weight-bold; }
.cm { color: $white-cm; font-style: italic; }
- .cp { color: $white-cp; font-weight: bold; }
+ .cp { color: $white-cp; font-weight: $gl-font-weight-bold; }
.c1 { color: $white-c1; font-style: italic; }
- .cs { color: $white-cs; font-weight: bold; font-style: italic; }
+ .cs { color: $white-cs; font-weight: $gl-font-weight-bold; font-style: italic; }
.gd { color: $white-gd; background-color: $white-gd-bg; }
.gd .x { color: $white-gd-x; background-color: $white-gd-x-bg; }
.ge { font-style: italic; }
@@ -226,29 +226,29 @@ $white-gc-bg: #eaf2f5;
.gi .x { color: $white-gi-x; background-color: $white-gi-x-bg; }
.go { color: $white-go; }
.gp { color: $white-gp; }
- .gs { font-weight: bold; }
- .gu { color: $white-gu; font-weight: bold; }
+ .gs { font-weight: $gl-font-weight-bold; }
+ .gu { color: $white-gu; font-weight: $gl-font-weight-bold; }
.gt { color: $white-gt; }
- .kc { font-weight: bold; }
- .kd { font-weight: bold; }
- .kn { font-weight: bold; }
- .kp { font-weight: bold; }
- .kr { font-weight: bold; }
- .kt { color: $white-kt; font-weight: bold; }
+ .kc { font-weight: $gl-font-weight-bold; }
+ .kd { font-weight: $gl-font-weight-bold; }
+ .kn { font-weight: $gl-font-weight-bold; }
+ .kp { font-weight: $gl-font-weight-bold; }
+ .kr { font-weight: $gl-font-weight-bold; }
+ .kt { color: $white-kt; font-weight: $gl-font-weight-bold; }
.m { color: $white-m; }
.s { color: $white-s; }
.n { color: $white-n; }
.na { color: $white-na; }
.nb { color: $white-nb; }
- .nc { color: $white-nc; font-weight: bold; }
+ .nc { color: $white-nc; font-weight: $gl-font-weight-bold; }
.no { color: $white-no; }
.ni { color: $white-ni; }
- .ne { color: $white-ne; font-weight: bold; }
- .nf { color: $white-nf; font-weight: bold; }
+ .ne { color: $white-ne; font-weight: $gl-font-weight-bold; }
+ .nf { color: $white-nf; font-weight: $gl-font-weight-bold; }
.nn { color: $white-nn; }
.nt { color: $white-nt; }
.nv { color: $white-nv; }
- .ow { font-weight: bold; }
+ .ow { font-weight: $gl-font-weight-bold; }
.w { color: $white-w; }
.mf { color: $white-mf; }
.mh { color: $white-mh; }
diff --git a/app/assets/stylesheets/mailers/highlighted_diff_email.scss b/app/assets/stylesheets/mailers/highlighted_diff_email.scss
index ea40f449134..fbe538ad1d7 100644
--- a/app/assets/stylesheets/mailers/highlighted_diff_email.scss
+++ b/app/assets/stylesheets/mailers/highlighted_diff_email.scss
@@ -152,12 +152,12 @@ span.highlight_word {
.hll { background-color: $highlighted-hll-bg; }
.c { color: $highlighted-c; font-style: italic; }
.err { color: $highlighted-err; background-color: $highlighted-err-bg; }
-.k { font-weight: bold; }
-.o { font-weight: bold; }
+.k { font-weight: $gl-font-weight-bold; }
+.o { font-weight: $gl-font-weight-bold; }
.cm { color: $highlighted-cm; font-style: italic; }
-.cp { color: $highlighted-cp; font-weight: bold; }
+.cp { color: $highlighted-cp; font-weight: $gl-font-weight-bold; }
.c1 { color: $highlighted-c1; font-style: italic; }
-.cs { color: $highlighted-cs; font-weight: bold; font-style: italic; }
+.cs { color: $highlighted-cs; font-weight: $gl-font-weight-bold; font-style: italic; }
.gd { color: $highlighted-gd; background-color: $highlighted-gd-bg; }
.gd .x { color: $highlighted-gd; background-color: $highlighted-gd-x-bg; }
.ge { font-style: italic; }
@@ -167,29 +167,29 @@ span.highlight_word {
.gi .x { color: $highlighted-gi; background-color: $highlighted-gi-x-bg; }
.go { color: $highlighted-go; }
.gp { color: $highlighted-gp; }
-.gs { font-weight: bold; }
-.gu { color: $highlighted-gu; font-weight: bold; }
+.gs { font-weight: $gl-font-weight-bold; }
+.gu { color: $highlighted-gu; font-weight: $gl-font-weight-bold; }
.gt { color: $highlighted-gt; }
-.kc { font-weight: bold; }
-.kd { font-weight: bold; }
-.kn { font-weight: bold; }
-.kp { font-weight: bold; }
-.kr { font-weight: bold; }
-.kt { color: $highlighted-kt; font-weight: bold; }
+.kc { font-weight: $gl-font-weight-bold; }
+.kd { font-weight: $gl-font-weight-bold; }
+.kn { font-weight: $gl-font-weight-bold; }
+.kp { font-weight: $gl-font-weight-bold; }
+.kr { font-weight: $gl-font-weight-bold; }
+.kt { color: $highlighted-kt; font-weight: $gl-font-weight-bold; }
.m { color: $highlighted-m; }
.s { color: $highlighted-s; }
.n { color: $highlighted-n; }
.na { color: $highlighted-na; }
.nb { color: $highlighted-nb; }
-.nc { color: $highlighted-nc; font-weight: bold; }
+.nc { color: $highlighted-nc; font-weight: $gl-font-weight-bold; }
.no { color: $highlighted-no; }
.ni { color: $highlighted-ni; }
-.ne { color: $highlighted-ne; font-weight: bold; }
-.nf { color: $highlighted-nf; font-weight: bold; }
+.ne { color: $highlighted-ne; font-weight: $gl-font-weight-bold; }
+.nf { color: $highlighted-nf; font-weight: $gl-font-weight-bold; }
.nn { color: $highlighted-nn; }
.nt { color: $highlighted-nt; }
.nv { color: $highlighted-nv; }
-.ow { font-weight: bold; }
+.ow { font-weight: $gl-font-weight-bold; }
.w { color: $highlighted-w; }
.mf { color: $highlighted-mf; }
.mh { color: $highlighted-mh; }
diff --git a/app/assets/stylesheets/new_nav.scss b/app/assets/stylesheets/new_nav.scss
index 3e2f23e6b2a..54fa4109f8b 100644
--- a/app/assets/stylesheets/new_nav.scss
+++ b/app/assets/stylesheets/new_nav.scss
@@ -134,7 +134,7 @@ header.navbar-gitlab-new {
li {
.badge {
box-shadow: none;
- font-weight: 600;
+ font-weight: $gl-font-weight-bold;
}
}
}
@@ -193,7 +193,7 @@ header.navbar-gitlab-new {
&.active > a {
box-shadow: inset 0 -3px 0 $indigo-500;
color: $white-light;
- font-weight: 700;
+ font-weight: $gl-font-weight-bold;
}
> a {
@@ -371,7 +371,7 @@ header.navbar-gitlab-new {
> a {
&:last-of-type:not(:first-child) {
- font-weight: 600;
+ font-weight: $gl-font-weight-bold;
}
}
}
@@ -411,7 +411,7 @@ header.navbar-gitlab-new {
.breadcrumbs-sub-title {
margin: 2px 0;
font-size: 16px;
- font-weight: normal;
+ font-weight: $gl-font-weight-normal;
line-height: 1;
ul {
@@ -430,7 +430,7 @@ header.navbar-gitlab-new {
}
&:last-child a {
- font-weight: 600;
+ font-weight: $gl-font-weight-bold;
}
}
diff --git a/app/assets/stylesheets/new_sidebar.scss b/app/assets/stylesheets/new_sidebar.scss
index cee5b22adb9..a74d53b4f68 100644
--- a/app/assets/stylesheets/new_sidebar.scss
+++ b/app/assets/stylesheets/new_sidebar.scss
@@ -46,7 +46,7 @@ $new-sidebar-collapsed-width: 50px;
a {
border-bottom: 1px solid $border-color;
- font-weight: 600;
+ font-weight: $gl-font-weight-bold;
display: flex;
align-items: center;
padding: 10px 16px 10px 10px;
@@ -160,7 +160,7 @@ $new-sidebar-collapsed-width: 50px;
> a {
color: $active-color;
- font-weight: 700;
+ font-weight: $gl-font-weight-bold;
}
svg {
@@ -308,7 +308,7 @@ $new-sidebar-collapsed-width: 50px;
.badge {
color: $active-color;
- font-weight: 600;
+ font-weight: $gl-font-weight-bold;
}
.sidebar-sub-level-items {
@@ -474,6 +474,6 @@ $new-sidebar-collapsed-width: 50px;
border-bottom-color: $active-border;
.badge {
- font-weight: 600;
+ font-weight: $gl-font-weight-bold;
}
}
diff --git a/app/assets/stylesheets/pages/boards.scss b/app/assets/stylesheets/pages/boards.scss
index e5b467a2691..0f3074076ce 100644
--- a/app/assets/stylesheets/pages/boards.scss
+++ b/app/assets/stylesheets/pages/boards.scss
@@ -471,7 +471,7 @@
padding-right: 35px;
> strong {
- font-weight: 600;
+ font-weight: $gl-font-weight-bold;
}
}
}
diff --git a/app/assets/stylesheets/pages/builds.scss b/app/assets/stylesheets/pages/builds.scss
index 486424fb729..3d04df8d820 100644
--- a/app/assets/stylesheets/pages/builds.scss
+++ b/app/assets/stylesheets/pages/builds.scss
@@ -277,7 +277,7 @@
}
.trigger-build-variable {
- font-weight: normal;
+ font-weight: $gl-font-weight-normal;
color: $code-color;
}
@@ -378,7 +378,7 @@
}
&.active {
- font-weight: bold;
+ font-weight: $gl-font-weight-bold;
.fa-arrow-right {
display: block;
diff --git a/app/assets/stylesheets/pages/ci_projects.scss b/app/assets/stylesheets/pages/ci_projects.scss
index 7b4eb689f1b..bf6a48889bf 100644
--- a/app/assets/stylesheets/pages/ci_projects.scss
+++ b/app/assets/stylesheets/pages/ci_projects.scss
@@ -22,7 +22,7 @@
vertical-align: middle !important;
a {
- font-weight: normal;
+ font-weight: $gl-font-weight-normal;
text-decoration: none;
}
}
diff --git a/app/assets/stylesheets/pages/commits.scss b/app/assets/stylesheets/pages/commits.scss
index 46fbfe5f91e..c051d37aad6 100644
--- a/app/assets/stylesheets/pages/commits.scss
+++ b/app/assets/stylesheets/pages/commits.scss
@@ -213,7 +213,7 @@
.commit-sha {
font-size: 14px;
- font-weight: 600;
+ font-weight: $gl-font-weight-bold;
}
}
@@ -286,6 +286,9 @@
.gpg-status-box {
+ padding: 2px 10px;
+ margin-right: $gl-padding;
+
&:empty {
display: none;
}
@@ -303,7 +306,7 @@
.gpg-popover-status {
display: flex;
align-items: center;
- font-weight: normal;
+ font-weight: $gl-font-weight-normal;
line-height: 1.5;
}
@@ -314,7 +317,6 @@
&.valid {
svg {
border: 1px solid $brand-success;
-
fill: $brand-success;
}
}
@@ -322,7 +324,6 @@
&.invalid {
svg {
border: 1px solid $common-gray-light;
-
fill: $common-gray-light;
}
}
diff --git a/app/assets/stylesheets/pages/convdev_index.scss b/app/assets/stylesheets/pages/convdev_index.scss
index 0413114c279..16702442f50 100644
--- a/app/assets/stylesheets/pages/convdev_index.scss
+++ b/app/assets/stylesheets/pages/convdev_index.scss
@@ -23,7 +23,7 @@ $space-between-cards: 8px;
line-height: 1;
color: $gl-text-color-secondary;
margin-left: 8px;
- font-weight: 500;
+ font-weight: $gl-font-weight-normal;
a {
font-size: 18px;
@@ -139,7 +139,7 @@ $space-between-cards: 8px;
.card-score-value {
font-size: 16px;
color: $gl-text-color;
- font-weight: 500;
+ font-weight: $gl-font-weight-normal;
}
.card-score-big {
@@ -147,7 +147,7 @@ $space-between-cards: 8px;
border-bottom: 1px solid $border-color;
font-size: 22px;
padding: 10px 0;
- font-weight: 500;
+ font-weight: $gl-font-weight-normal;
}
.card-buttons {
diff --git a/app/assets/stylesheets/pages/cycle_analytics.scss b/app/assets/stylesheets/pages/cycle_analytics.scss
index 6753eb08285..2a92673d9fa 100644
--- a/app/assets/stylesheets/pages/cycle_analytics.scss
+++ b/app/assets/stylesheets/pages/cycle_analytics.scss
@@ -68,7 +68,7 @@
}
.stage-name {
- font-weight: 600;
+ font-weight: $gl-font-weight-bold;
}
}
@@ -93,7 +93,7 @@
.header {
font-size: 30px;
line-height: 38px;
- font-weight: normal;
+ font-weight: $gl-font-weight-normal;
margin: 0;
}
@@ -130,7 +130,7 @@
&.title {
line-height: 19px;
font-size: 14px;
- font-weight: 600;
+ font-weight: $gl-font-weight-bold;
color: $gl-text-color;
}
@@ -211,7 +211,7 @@
box-shadow: inset 2px 0 0 0 $active-item-blue;
.stage-name {
- font-weight: 600;
+ font-weight: $gl-font-weight-bold;
}
}
@@ -404,7 +404,7 @@
color: $gl-link-color;
line-height: 1.3;
vertical-align: top;
- font-weight: normal;
+ font-weight: $gl-font-weight-normal;
}
.fa {
diff --git a/app/assets/stylesheets/pages/diff.scss b/app/assets/stylesheets/pages/diff.scss
index 913a1a95dca..8cbf0ec6180 100644
--- a/app/assets/stylesheets/pages/diff.scss
+++ b/app/assets/stylesheets/pages/diff.scss
@@ -40,7 +40,7 @@
// "Changes suppressed. Click to show." link
.show-suppressed-diff {
font-size: 110%;
- font-weight: bold;
+ font-weight: $gl-font-weight-bold;
}
}
@@ -104,7 +104,7 @@
a {
float: left;
width: 35px;
- font-weight: normal;
+ font-weight: $gl-font-weight-normal;
&[disabled] {
cursor: default;
@@ -395,7 +395,7 @@
background-color: transparent;
border: 0;
color: $gl-link-color;
- font-weight: 600;
+ font-weight: $gl-font-weight-bold;
&:hover,
&:focus {
diff --git a/app/assets/stylesheets/pages/environments.scss b/app/assets/stylesheets/pages/environments.scss
index 00ebf4e26ac..a8d2ae0af28 100644
--- a/app/assets/stylesheets/pages/environments.scss
+++ b/app/assets/stylesheets/pages/environments.scss
@@ -6,7 +6,7 @@
}
.environments-folder-name {
- font-weight: normal;
+ font-weight: $gl-font-weight-normal;
padding-top: 20px;
}
@@ -246,13 +246,13 @@
}
.text-metric-bold {
- font-weight: 600;
+ font-weight: $gl-font-weight-bold;
}
.label-axis-text,
.text-metric-usage {
fill: $black;
- font-weight: 500;
+ font-weight: $gl-font-weight-normal;
font-size: 12px;
}
diff --git a/app/assets/stylesheets/pages/events.scss b/app/assets/stylesheets/pages/events.scss
index 4c3fa1fb8d4..1723d716805 100644
--- a/app/assets/stylesheets/pages/events.scss
+++ b/app/assets/stylesheets/pages/events.scss
@@ -57,7 +57,7 @@
.event-title {
@include str-truncated(calc(100% - 174px));
- font-weight: 600;
+ font-weight: $gl-font-weight-bold;
color: $list-text-color;
}
diff --git a/app/assets/stylesheets/pages/issuable.scss b/app/assets/stylesheets/pages/issuable.scss
index 49839a9b528..ab5a901da71 100644
--- a/app/assets/stylesheets/pages/issuable.scss
+++ b/app/assets/stylesheets/pages/issuable.scss
@@ -271,7 +271,7 @@
}
.light {
- font-weight: normal;
+ font-weight: $gl-font-weight-normal;
}
.no-value {
@@ -306,7 +306,7 @@
display: block;
margin-top: 4px;
font-size: 13px;
- font-weight: normal;
+ font-weight: $gl-font-weight-normal;
}
.hide-expanded {
@@ -689,7 +689,7 @@
.issuable-info,
.task-status,
.issuable-updated-at {
- font-weight: normal;
+ font-weight: $gl-font-weight-normal;
color: $gl-text-color-secondary;
a {
diff --git a/app/assets/stylesheets/pages/issues.scss b/app/assets/stylesheets/pages/issues.scss
index 8cdb3f34ae5..e2177f96aee 100644
--- a/app/assets/stylesheets/pages/issues.scss
+++ b/app/assets/stylesheets/pages/issues.scss
@@ -75,7 +75,7 @@ ul.related-merge-requests > li {
.merge-requests-title,
.related-branches-title {
font-size: 16px;
- font-weight: 600;
+ font-weight: $gl-font-weight-bold;
}
.merge-request-id {
@@ -244,7 +244,7 @@ ul.related-merge-requests > li {
strong {
display: block;
- font-weight: 600;
+ font-weight: $gl-font-weight-bold;
}
}
}
diff --git a/app/assets/stylesheets/pages/login.scss b/app/assets/stylesheets/pages/login.scss
index 3cbe8dededb..d4dc43035eb 100644
--- a/app/assets/stylesheets/pages/login.scss
+++ b/app/assets/stylesheets/pages/login.scss
@@ -22,7 +22,7 @@
}
h1:first-child {
- font-weight: normal;
+ font-weight: $gl-font-weight-normal;
margin-bottom: 0.68em;
margin-top: 0;
font-size: 34px;
@@ -38,7 +38,7 @@
}
a {
- font-weight: bold;
+ font-weight: $gl-font-weight-bold;
}
}
@@ -54,7 +54,7 @@
padding: 15px;
.login-heading h3 {
- font-weight: 300;
+ font-weight: $gl-font-weight-normal;
line-height: 1.5;
margin: 0 0 10px;
}
@@ -186,7 +186,7 @@
}
label {
- font-weight: normal;
+ font-weight: $gl-font-weight-normal;
}
.submit-container {
diff --git a/app/assets/stylesheets/pages/members.scss b/app/assets/stylesheets/pages/members.scss
index e7c07ef67f0..a385eb359e1 100644
--- a/app/assets/stylesheets/pages/members.scss
+++ b/app/assets/stylesheets/pages/members.scss
@@ -46,7 +46,7 @@
}
strong {
- font-weight: 600;
+ font-weight: $gl-font-weight-bold;
}
}
@@ -221,7 +221,7 @@
}
.member {
- font-weight: bold;
+ font-weight: $gl-font-weight-bold;
overflow-wrap: break-word;
word-break: break-all;
}
diff --git a/app/assets/stylesheets/pages/merge_requests.scss b/app/assets/stylesheets/pages/merge_requests.scss
index 6bb013cca85..d1678a17aaf 100644
--- a/app/assets/stylesheets/pages/merge_requests.scss
+++ b/app/assets/stylesheets/pages/merge_requests.scss
@@ -197,7 +197,7 @@
@extend .ref-name;
color: $gl-text-color;
- font-weight: 600;
+ font-weight: $gl-font-weight-bold;
overflow: hidden;
word-break: break-all;
@@ -228,7 +228,7 @@
.mr-widget-body {
h4 {
float: left;
- font-weight: 600;
+ font-weight: $gl-font-weight-bold;
font-size: 14px;
line-height: inherit;
margin-top: 0;
@@ -239,7 +239,7 @@
}
time {
- font-weight: normal;
+ font-weight: $gl-font-weight-normal;
}
}
@@ -249,7 +249,7 @@
}
label {
- font-weight: normal;
+ font-weight: $gl-font-weight-normal;
}
.spacing {
@@ -257,12 +257,12 @@
}
.bold {
- font-weight: 600;
+ font-weight: $gl-font-weight-bold;
color: $gl-gray-light;
}
.state-label {
- font-weight: 600;
+ font-weight: $gl-font-weight-bold;
padding-right: 10px;
}
@@ -336,7 +336,7 @@
.text {
span {
- font-weight: 600;
+ font-weight: $gl-font-weight-bold;
}
p {
@@ -505,7 +505,7 @@
.panel-new-merge-request {
.panel-heading {
padding: 5px 10px;
- font-weight: 600;
+ font-weight: $gl-font-weight-bold;
line-height: 25px;
}
diff --git a/app/assets/stylesheets/pages/milestone.scss b/app/assets/stylesheets/pages/milestone.scss
index 55e0ee1936e..32039936be7 100644
--- a/app/assets/stylesheets/pages/milestone.scss
+++ b/app/assets/stylesheets/pages/milestone.scss
@@ -7,7 +7,7 @@
padding: 10px 16px;
h4 {
- font-weight: bold;
+ font-weight: $gl-font-weight-bold;
}
.progress {
@@ -81,7 +81,7 @@
}
.remaining-days strong {
- font-weight: normal;
+ font-weight: $gl-font-weight-normal;
}
.milestone-stat {
diff --git a/app/assets/stylesheets/pages/note_form.scss b/app/assets/stylesheets/pages/note_form.scss
index b4468d6d0a2..9558924bbcb 100644
--- a/app/assets/stylesheets/pages/note_form.scss
+++ b/app/assets/stylesheets/pages/note_form.scss
@@ -188,7 +188,7 @@
.close {
color: $white-light;
opacity: 0.85;
- font-weight: normal;
+ font-weight: $gl-font-weight-normal;
&:hover {
opacity: 1;
diff --git a/app/assets/stylesheets/pages/pipeline_schedules.scss b/app/assets/stylesheets/pages/pipeline_schedules.scss
index dc1654e006e..7e2297c283f 100644
--- a/app/assets/stylesheets/pages/pipeline_schedules.scss
+++ b/app/assets/stylesheets/pages/pipeline_schedules.scss
@@ -12,7 +12,7 @@
.interval-pattern-form-group {
label {
margin-right: 10px;
- font-weight: normal;
+ font-weight: $gl-font-weight-normal;
&[for='custom'] {
margin-right: 0;
diff --git a/app/assets/stylesheets/pages/pipelines.scss b/app/assets/stylesheets/pages/pipelines.scss
index 85d1905ad40..a408bde37d6 100644
--- a/app/assets/stylesheets/pages/pipelines.scss
+++ b/app/assets/stylesheets/pages/pipelines.scss
@@ -128,7 +128,7 @@
.branch-commit {
.ref-name {
- font-weight: bold;
+ font-weight: $gl-font-weight-bold;
max-width: 120px;
overflow: hidden;
display: inline-block;
@@ -272,7 +272,7 @@
.build-name {
float: right;
- font-weight: 500;
+ font-weight: $gl-font-weight-normal;
}
.ci-status-icon-failed svg {
@@ -281,7 +281,7 @@
.stage {
color: $gl-text-color-secondary;
- font-weight: 500;
+ font-weight: $gl-font-weight-normal;
vertical-align: middle;
}
}
@@ -420,7 +420,7 @@
.stage-name {
margin: 0 0 15px 10px;
- font-weight: bold;
+ font-weight: $gl-font-weight-bold;
width: 176px;
white-space: nowrap;
overflow: hidden;
@@ -580,7 +580,7 @@
vertical-align: bottom;
display: inline-block;
position: relative;
- font-weight: normal;
+ font-weight: $gl-font-weight-normal;
}
@mixin mini-pipeline-graph-color($color-light, $color-main, $color-dark) {
@@ -724,7 +724,7 @@ button.mini-pipeline-graph-dropdown-toggle {
.mini-pipeline-graph-dropdown-item {
padding: 3px 7px 4px;
clear: both;
- font-weight: normal;
+ font-weight: $gl-font-weight-normal;
line-height: 1.428571429;
white-space: nowrap;
margin: 0 5px;
diff --git a/app/assets/stylesheets/pages/profile.scss b/app/assets/stylesheets/pages/profile.scss
index 14ad06b0ac2..c5d6ff66dd6 100644
--- a/app/assets/stylesheets/pages/profile.scss
+++ b/app/assets/stylesheets/pages/profile.scss
@@ -83,7 +83,7 @@
&::after {
content: "\00B7"; // Middle Dot
padding: 0 6px;
- font-weight: bold;
+ font-weight: $gl-font-weight-bold;
}
&:last-child {
@@ -277,7 +277,7 @@ table.u2f-registrations {
.oauth-application-show {
.scope-name {
- font-weight: 600;
+ font-weight: $gl-font-weight-bold;
}
.scopes-list {
diff --git a/app/assets/stylesheets/pages/projects.scss b/app/assets/stylesheets/pages/projects.scss
index d01326637ea..39c4264e496 100644
--- a/app/assets/stylesheets/pages/projects.scss
+++ b/app/assets/stylesheets/pages/projects.scss
@@ -2,7 +2,7 @@
margin: -16px;
.alert-link {
- font-weight: normal;
+ font-weight: $gl-font-weight-normal;
}
}
@@ -114,7 +114,7 @@
margin-top: 10px;
margin-bottom: 10px;
font-size: 24px;
- font-weight: 400;
+ font-weight: $gl-font-weight-normal;
line-height: 1;
word-wrap: break-word;
@@ -259,7 +259,7 @@
border-width: 1px;
border-style: solid;
font-size: 13px;
- font-weight: 600;
+ font-weight: $gl-font-weight-bold;
line-height: 13px;
letter-spacing: .4px;
padding: 6px 14px;
@@ -309,7 +309,7 @@
}
.option-title {
- font-weight: normal;
+ font-weight: $gl-font-weight-normal;
display: inline-block;
color: $gl-text-color;
}
@@ -575,7 +575,7 @@ a.deploy-project-label {
color: $gl-text-color-tertiary;
transform: translateY(-50%);
font-size: 12px;
- font-weight: bold;
+ font-weight: $gl-font-weight-bold;
line-height: 20px;
// Mobile
@@ -826,7 +826,7 @@ pre.light-well {
.new-protected-tag {
label {
margin-top: 6px;
- font-weight: normal;
+ font-weight: $gl-font-weight-normal;
}
}
@@ -853,7 +853,7 @@ pre.light-well {
}
&.is-active {
- font-weight: 600;
+ font-weight: $gl-font-weight-bold;
}
}
@@ -952,7 +952,7 @@ pre.light-well {
&::before {
font-family: FontAwesome;
- font-weight: normal;
+ font-weight: $gl-font-weight-normal;
font-style: normal;
}
}
diff --git a/app/assets/stylesheets/pages/repo.scss b/app/assets/stylesheets/pages/repo.scss
index 1f4d4698199..37971d6bd3a 100644
--- a/app/assets/stylesheets/pages/repo.scss
+++ b/app/assets/stylesheets/pages/repo.scss
@@ -267,7 +267,7 @@
display: inline-block;
font-size: 10px;
text-transform: uppercase;
- font-weight: bold;
+ font-weight: $gl-font-weight-bold;
color: $gray-darkest;
white-space: nowrap;
overflow: hidden;
diff --git a/app/assets/stylesheets/pages/runners.scss b/app/assets/stylesheets/pages/runners.scss
index 57c73295d1e..6cac37a4e28 100644
--- a/app/assets/stylesheets/pages/runners.scss
+++ b/app/assets/stylesheets/pages/runners.scss
@@ -30,7 +30,7 @@
}
h4 {
- font-weight: normal;
+ font-weight: $gl-font-weight-normal;
}
}
diff --git a/app/assets/stylesheets/pages/search.scss b/app/assets/stylesheets/pages/search.scss
index b9818ffcf42..8d73246223d 100644
--- a/app/assets/stylesheets/pages/search.scss
+++ b/app/assets/stylesheets/pages/search.scss
@@ -94,7 +94,7 @@ input[type="checkbox"]:hover {
&::before {
font-family: FontAwesome;
- font-weight: normal;
+ font-weight: $gl-font-weight-normal;
font-style: normal;
}
}
diff --git a/app/assets/stylesheets/pages/sherlock.scss b/app/assets/stylesheets/pages/sherlock.scss
index 23a9c2ada80..bfe065dbbaf 100644
--- a/app/assets/stylesheets/pages/sherlock.scss
+++ b/app/assets/stylesheets/pages/sherlock.scss
@@ -29,5 +29,5 @@ table .sherlock-code {
.sherlock-line-samples-table .slow {
color: $red-500;
- font-weight: bold;
+ font-weight: $gl-font-weight-bold;
}
diff --git a/app/assets/stylesheets/pages/todos.scss b/app/assets/stylesheets/pages/todos.scss
index d7a9dda3770..5b9fafe31bd 100644
--- a/app/assets/stylesheets/pages/todos.scss
+++ b/app/assets/stylesheets/pages/todos.scss
@@ -108,14 +108,14 @@
margin: 0;
float: none;
display: inline-block;
- font-weight: normal;
+ font-weight: $gl-font-weight-normal;
padding: 0 5px;
line-height: inherit;
font-size: 14px;
}
.action-name {
- font-weight: normal;
+ font-weight: $gl-font-weight-normal;
}
.todo-body {
@@ -262,6 +262,6 @@
}
a {
- font-weight: 600;
+ font-weight: $gl-font-weight-bold;
}
}
diff --git a/app/assets/stylesheets/pages/tree.scss b/app/assets/stylesheets/pages/tree.scss
index 0028e207f3e..224eee90a3f 100644
--- a/app/assets/stylesheets/pages/tree.scss
+++ b/app/assets/stylesheets/pages/tree.scss
@@ -231,7 +231,7 @@
}
.upload-link {
- font-weight: normal;
+ font-weight: $gl-font-weight-normal;
color: $md-link-color;
}
diff --git a/app/assets/stylesheets/pages/ui_dev_kit.scss b/app/assets/stylesheets/pages/ui_dev_kit.scss
index 798e060a261..48ac5b21db8 100644
--- a/app/assets/stylesheets/pages/ui_dev_kit.scss
+++ b/app/assets/stylesheets/pages/ui_dev_kit.scss
@@ -1,7 +1,7 @@
.gitlab-ui-dev-kit {
> h2 {
margin: 35px 0 20px;
- font-weight: bold;
+ font-weight: $gl-font-weight-bold;
}
.example {
diff --git a/app/assets/stylesheets/pages/wiki.scss b/app/assets/stylesheets/pages/wiki.scss
index fa6bdd297eb..b7d4e7bf582 100644
--- a/app/assets/stylesheets/pages/wiki.scss
+++ b/app/assets/stylesheets/pages/wiki.scss
@@ -37,7 +37,7 @@
}
.light {
- font-weight: normal;
+ font-weight: $gl-font-weight-normal;
color: $gl-text-color-secondary;
}
@@ -89,7 +89,7 @@
h3 {
font-size: 19px;
- font-weight: normal;
+ font-weight: $gl-font-weight-normal;
margin: $gl-padding 0;
}
}
diff --git a/app/assets/stylesheets/pages/xterm.scss b/app/assets/stylesheets/pages/xterm.scss
index b085c56390d..c7297a34ad8 100644
--- a/app/assets/stylesheets/pages/xterm.scss
+++ b/app/assets/stylesheets/pages/xterm.scss
@@ -281,7 +281,7 @@
$xterm-fg-255: #eee;
.term-bold {
- font-weight: bold;
+ font-weight: $gl-font-weight-bold;
}
.term-italic {
diff --git a/app/assets/stylesheets/print.scss b/app/assets/stylesheets/print.scss
index 113e6e86bb5..b07a5ae22cd 100644
--- a/app/assets/stylesheets/print.scss
+++ b/app/assets/stylesheets/print.scss
@@ -17,7 +17,7 @@
.wiki h3 {
font-size: 18px;
- font-weight: bold;
+ font-weight: 600;
}
header,
diff --git a/app/controllers/admin/logs_controller.rb b/app/controllers/admin/logs_controller.rb
index b999018dde4..bdc4332ae69 100644
--- a/app/controllers/admin/logs_controller.rb
+++ b/app/controllers/admin/logs_controller.rb
@@ -1,2 +1,11 @@
class Admin::LogsController < Admin::ApplicationController
+ def show
+ @loggers = [
+ Gitlab::AppLogger,
+ Gitlab::GitLogger,
+ Gitlab::EnvironmentLogger,
+ Gitlab::SidekiqLogger,
+ Gitlab::RepositoryCheckLogger
+ ]
+ end
end
diff --git a/app/controllers/admin/projects_controller.rb b/app/controllers/admin/projects_controller.rb
index 0b6cd71e651..50cf2643390 100644
--- a/app/controllers/admin/projects_controller.rb
+++ b/app/controllers/admin/projects_controller.rb
@@ -3,9 +3,9 @@ class Admin::ProjectsController < Admin::ApplicationController
before_action :group, only: [:show, :transfer]
def index
- finder = Admin::ProjectsFinder.new(params: params, current_user: current_user)
- @projects = finder.execute
- @sort = finder.sort
+ params[:sort] ||= 'latest_activity_desc'
+ @sort = params[:sort]
+ @projects = Admin::ProjectsFinder.new(params: params, current_user: current_user).execute
respond_to do |format|
format.html
diff --git a/app/controllers/projects/services_controller.rb b/app/controllers/projects/services_controller.rb
index d54a1111f11..daa5c88aae0 100644
--- a/app/controllers/projects/services_controller.rb
+++ b/app/controllers/projects/services_controller.rb
@@ -4,7 +4,6 @@ class Projects::ServicesController < Projects::ApplicationController
# Authorize
before_action :authorize_admin_project!
before_action :service, only: [:edit, :update, :test]
- before_action :update_service, only: [:update, :test]
respond_to :html
@@ -14,6 +13,8 @@ class Projects::ServicesController < Projects::ApplicationController
end
def update
+ @service.attributes = service_params[:service]
+
if @service.save(context: :manual_change)
redirect_to(project_settings_integrations_path(@project), notice: success_message)
else
@@ -24,7 +25,7 @@ class Projects::ServicesController < Projects::ApplicationController
def test
message = {}
- if @service.can_test?
+ if @service.can_test? && @service.update_attributes(service_params[:service])
data = @service.test_data(project, current_user)
outcome = @service.test(data)
@@ -50,10 +51,6 @@ class Projects::ServicesController < Projects::ApplicationController
end
end
- def update_service
- @service.assign_attributes(service_params[:service])
- end
-
def service
@service ||= @project.find_or_initialize_service(params[:id])
end
diff --git a/app/finders/admin/projects_finder.rb b/app/finders/admin/projects_finder.rb
index 7176bfe22d6..d6bcd939522 100644
--- a/app/finders/admin/projects_finder.rb
+++ b/app/finders/admin/projects_finder.rb
@@ -1,33 +1,67 @@
class Admin::ProjectsFinder
- attr_reader :sort, :namespace_id, :visibility_level, :with_push,
- :abandoned, :last_repository_check_failed, :archived,
- :personal, :name, :page, :current_user
+ attr_reader :params, :current_user
def initialize(params:, current_user:)
+ @params = params
@current_user = current_user
- @sort = params.fetch(:sort) { 'latest_activity_desc' }
- @namespace_id = params[:namespace_id]
- @visibility_level = params[:visibility_level]
- @with_push = params[:with_push]
- @abandoned = params[:abandoned]
- @last_repository_check_failed = params[:last_repository_check_failed]
- @archived = params[:archived]
- @personal = params[:personal]
- @name = params[:name]
- @page = params[:page]
end
def execute
items = Project.without_deleted.with_statistics
- items = items.in_namespace(namespace_id) if namespace_id.present?
- items = items.where(visibility_level: visibility_level) if visibility_level.present?
- items = items.with_push if with_push.present?
- items = items.abandoned if abandoned.present?
- items = items.where(last_repository_check_failed: true) if last_repository_check_failed.present?
- items = items.non_archived unless archived.present?
- items = items.personal(current_user) if personal.present?
- items = items.search(name) if name.present?
- items = items.sort(sort)
- items.includes(:namespace).order("namespaces.path, projects.name ASC").page(page)
+ items = by_namespace_id(items)
+ items = by_visibilty_level(items)
+ items = by_with_push(items)
+ items = by_abandoned(items)
+ items = by_last_repository_check_failed(items)
+ items = by_archived(items)
+ items = by_personal(items)
+ items = by_name(items)
+ items = sort(items)
+ items.includes(:namespace).order("namespaces.path, projects.name ASC").page(params[:page])
+ end
+
+ private
+
+ def by_namespace_id(items)
+ params[:namespace_id].present? ? items.in_namespace(params[:namespace_id]) : items
+ end
+
+ def by_visibilty_level(items)
+ params[:visibility_level].present? ? items.where(visibility_level: params[:visibility_level]) : items
+ end
+
+ def by_with_push(items)
+ params[:with_push].present? ? items.with_push : items
+ end
+
+ def by_abandoned(items)
+ params[:abandoned].present? ? items.abandoned : items
+ end
+
+ def by_last_repository_check_failed(items)
+ params[:last_repository_check_failed].present? ? items.where(last_repository_check_failed: true) : items
+ end
+
+ def by_archived(items)
+ if params[:archived] == 'only'
+ items.archived
+ elsif params[:archived].blank?
+ items.non_archived
+ else
+ items
+ end
+ end
+
+ def by_personal(items)
+ params[:personal].present? ? items.personal(current_user) : items
+ end
+
+ def by_name(items)
+ params[:name].present? ? items.search(params[:name]) : items
+ end
+
+ def sort(items)
+ sort = params.fetch(:sort) { 'latest_activity_desc' }
+ items.sort(sort)
end
end
diff --git a/app/finders/projects_finder.rb b/app/finders/projects_finder.rb
index aa80dfc3f37..fa6fea2588a 100644
--- a/app/finders/projects_finder.rb
+++ b/app/finders/projects_finder.rb
@@ -125,9 +125,18 @@ class ProjectsFinder < UnionFinder
end
def by_archived(projects)
- # Back-compatibility with the places where `params[:archived]` can be set explicitly to `false`
- params[:non_archived] = !Gitlab::Utils.to_boolean(params[:archived]) if params.key?(:archived)
-
- params[:non_archived] ? projects.non_archived : projects
+ if params[:non_archived]
+ projects.non_archived
+ elsif params.key?(:archived) # Back-compatibility with the places where `params[:archived]` can be set explicitly to `false`
+ if params[:archived] == 'only'
+ projects.archived
+ elsif Gitlab::Utils.to_boolean(params[:archived])
+ projects
+ else
+ projects.non_archived
+ end
+ else
+ projects
+ end
end
end
diff --git a/app/helpers/avatars_helper.rb b/app/helpers/avatars_helper.rb
index 4b51269533c..a4c226a6aad 100644
--- a/app/helpers/avatars_helper.rb
+++ b/app/helpers/avatars_helper.rb
@@ -12,11 +12,18 @@ module AvatarsHelper
avatar_size = options[:size] || 16
user_name = options[:user].try(:name) || options[:user_name]
avatar_url = options[:url] || avatar_icon(options[:user] || options[:user_email], avatar_size)
- data_attributes = { container: 'body' }
+ has_tooltip = options[:has_tooltip].nil? ? true : options[:has_tooltip]
+ data_attributes = {}
+ css_class = %W[avatar s#{avatar_size}].push(*options[:css_class])
+
+ if has_tooltip
+ css_class.push('has-tooltip')
+ data_attributes = { container: 'body' }
+ end
image_tag(
avatar_url,
- class: %W[avatar has-tooltip s#{avatar_size}].push(*options[:css_class]),
+ class: css_class,
alt: "#{user_name}'s avatar",
title: user_name,
data: data_attributes,
diff --git a/app/helpers/commits_helper.rb b/app/helpers/commits_helper.rb
index 72e26b64e60..9651f9733f9 100644
--- a/app/helpers/commits_helper.rb
+++ b/app/helpers/commits_helper.rb
@@ -114,7 +114,7 @@ module CommitsHelper
end
def commit_signature_badge_classes(additional_classes)
- %w(btn status-box gpg-status-box) + Array(additional_classes)
+ %w(btn gpg-status-box) + Array(additional_classes)
end
protected
diff --git a/app/helpers/events_helper.rb b/app/helpers/events_helper.rb
index c6f98e7e782..b331693c789 100644
--- a/app/helpers/events_helper.rb
+++ b/app/helpers/events_helper.rb
@@ -181,6 +181,7 @@ module EventsHelper
end
def event_commit_title(message)
+ message ||= ''
(message.split("\n").first || "").truncate(70)
rescue
"--broken encoding"
diff --git a/app/models/ci/build.rb b/app/models/ci/build.rb
index 4692fb5644a..095192e9894 100644
--- a/app/models/ci/build.rb
+++ b/app/models/ci/build.rb
@@ -46,7 +46,10 @@ module Ci
before_save :ensure_token
before_destroy { unscoped_project }
- after_create :execute_hooks
+ after_create do |build|
+ run_after_commit { BuildHooksWorker.perform_async(build.id) }
+ end
+
after_commit :update_project_statistics_after_save, on: [:create, :update]
after_commit :update_project_statistics, on: :destroy
diff --git a/app/models/ci/pipeline.rb b/app/models/ci/pipeline.rb
index ea7331cb27f..2d40f8012a3 100644
--- a/app/models/ci/pipeline.rb
+++ b/app/models/ci/pipeline.rb
@@ -393,7 +393,8 @@ module Ci
def predefined_variables
[
{ key: 'CI_PIPELINE_ID', value: id.to_s, public: true },
- { key: 'CI_CONFIG_PATH', value: ci_yaml_file_path, public: true }
+ { key: 'CI_CONFIG_PATH', value: ci_yaml_file_path, public: true },
+ { key: 'CI_PIPELINE_SOURCE', value: source.to_s, public: true }
]
end
diff --git a/app/models/event.rb b/app/models/event.rb
index 15ee170ca75..996768a267b 100644
--- a/app/models/event.rb
+++ b/app/models/event.rb
@@ -406,7 +406,7 @@ class Event < ActiveRecord::Base
def body?
if push?
- push_with_commits? || rm_ref?
+ push_with_commits?
elsif note?
true
else
diff --git a/app/models/issue.rb b/app/models/issue.rb
index 043da9967a1..b9aa937d2f9 100644
--- a/app/models/issue.rb
+++ b/app/models/issue.rb
@@ -50,7 +50,10 @@ class Issue < ActiveRecord::Base
scope :preload_associations, -> { preload(:labels, project: :namespace) }
+ scope :public_only, -> { where(confidential: false) }
+
after_save :expire_etag_cache
+ after_commit :update_project_counter_caches, on: :destroy
attr_spammable :title, spam_title: true
attr_spammable :description, spam_description: true
@@ -266,6 +269,10 @@ class Issue < ActiveRecord::Base
end
end
+ def update_project_counter_caches
+ Projects::OpenIssuesCountService.new(project).refresh_cache
+ end
+
private
# Returns `true` if the given User can read the current Issue.
diff --git a/app/models/merge_request.rb b/app/models/merge_request.rb
index f028d2395c1..dbc73ed3cd4 100644
--- a/app/models/merge_request.rb
+++ b/app/models/merge_request.rb
@@ -31,6 +31,7 @@ class MergeRequest < ActiveRecord::Base
after_create :ensure_merge_request_diff, unless: :importing?
after_update :reload_diff_if_branch_changed
+ after_commit :update_project_counter_caches, on: :destroy
# When this attribute is true some MR validation is ignored
# It allows us to close or modify broken merge requests
@@ -682,9 +683,8 @@ class MergeRequest < ActiveRecord::Base
if !include_description && closes_issues_references.present?
message << "Closes #{closes_issues_references.to_sentence}"
end
-
message << "#{description}" if include_description && description.present?
- message << "See merge request #{to_reference}"
+ message << "See merge request #{to_reference(full: true)}"
message.join("\n\n")
end
@@ -936,6 +936,10 @@ class MergeRequest < ActiveRecord::Base
true
end
+ def update_project_counter_caches
+ Projects::OpenMergeRequestsCountService.new(target_project).refresh_cache
+ end
+
private
def write_ref
diff --git a/app/models/project.rb b/app/models/project.rb
index 37f4dd08355..d5324ceac31 100644
--- a/app/models/project.rb
+++ b/app/models/project.rb
@@ -247,6 +247,7 @@ class Project < ActiveRecord::Base
scope :joined, ->(user) { where('namespace_id != ?', user.namespace_id) }
scope :starred_by, ->(user) { joins(:users_star_projects).where('users_star_projects.user_id': user.id) }
scope :visible_to_user, ->(user) { where(id: user.authorized_projects.select(:id).reorder(nil)) }
+ scope :archived, -> { where(archived: true) }
scope :non_archived, -> { where(archived: false) }
scope :for_milestones, ->(ids) { joins(:milestones).where('milestones.id' => ids).distinct }
scope :with_push, -> { joins(:events).where('events.action = ?', Event::PUSHED) }
@@ -1017,7 +1018,7 @@ class Project < ActiveRecord::Base
name: name,
description: description,
web_url: web_url,
- avatar_url: avatar_url,
+ avatar_url: avatar_url(only_path: false),
git_ssh_url: ssh_url_to_repo,
git_http_url: http_url_to_repo,
namespace: namespace.name,
@@ -1167,7 +1168,11 @@ class Project < ActiveRecord::Base
end
def open_issues_count
- issues.opened.count
+ Projects::OpenIssuesCountService.new(self).count
+ end
+
+ def open_merge_requests_count
+ Projects::OpenMergeRequestsCountService.new(self).count
end
def visibility_level_allowed_as_fork?(level = self.visibility_level)
diff --git a/app/models/repository.rb b/app/models/repository.rb
index 59f913c7fb4..9fb2e2aa306 100644
--- a/app/models/repository.rb
+++ b/app/models/repository.rb
@@ -206,12 +206,18 @@ class Repository
end
def branch_exists?(branch_name)
- branch_names.include?(branch_name)
+ return false unless raw_repository
+
+ @branch_exists_memo ||= Hash.new do |hash, key|
+ hash[key] = raw_repository.branch_exists?(key)
+ end
+
+ @branch_exists_memo[branch_name]
end
def ref_exists?(ref)
- rugged.references.exist?(ref)
- rescue Rugged::ReferenceError
+ !!raw_repository&.ref_exists?(ref)
+ rescue ArgumentError
false
end
@@ -266,6 +272,7 @@ class Repository
def expire_branches_cache
expire_method_caches(%i(branch_names branch_count))
@local_branches = nil
+ @branch_exists_memo = nil
end
def expire_statistics_caches
diff --git a/app/services/groups/nested_create_service.rb b/app/services/groups/nested_create_service.rb
new file mode 100644
index 00000000000..8d793f5c02e
--- /dev/null
+++ b/app/services/groups/nested_create_service.rb
@@ -0,0 +1,45 @@
+module Groups
+ class NestedCreateService < Groups::BaseService
+ attr_reader :group_path
+
+ def initialize(user, params)
+ @current_user, @params = user, params.dup
+
+ @group_path = @params.delete(:group_path)
+ end
+
+ def execute
+ return nil unless group_path
+
+ if group = Group.find_by_full_path(group_path)
+ return group
+ end
+
+ create_group_path
+ end
+
+ private
+
+ def create_group_path
+ group_path_segments = group_path.split('/')
+
+ last_group = nil
+ partial_path_segments = []
+ while subgroup_name = group_path_segments.shift
+ partial_path_segments << subgroup_name
+ partial_path = partial_path_segments.join('/')
+
+ new_params = params.reverse_merge(
+ path: subgroup_name,
+ name: subgroup_name,
+ parent: last_group
+ )
+ new_params[:visibility_level] ||= Gitlab::CurrentSettings.current_application_settings.default_group_visibility
+
+ last_group = Group.find_by_full_path(partial_path) || Groups::CreateService.new(current_user, new_params).execute
+ end
+
+ last_group
+ end
+ end
+end
diff --git a/app/services/issuable_base_service.rb b/app/services/issuable_base_service.rb
index 4a4f2b91182..1486db046b5 100644
--- a/app/services/issuable_base_service.rb
+++ b/app/services/issuable_base_service.rb
@@ -192,6 +192,8 @@ class IssuableBaseService < BaseService
def after_create(issuable)
# To be overridden by subclasses
+
+ issuable.update_project_counter_caches
end
def before_update(issuable)
@@ -200,6 +202,8 @@ class IssuableBaseService < BaseService
def after_update(issuable)
# To be overridden by subclasses
+
+ issuable.update_project_counter_caches
end
def update(issuable)
diff --git a/app/services/issues/create_service.rb b/app/services/issues/create_service.rb
index 234fcbede03..0307634c0b6 100644
--- a/app/services/issues/create_service.rb
+++ b/app/services/issues/create_service.rb
@@ -27,6 +27,8 @@ module Issues
todo_service.new_issue(issuable, current_user)
user_agent_detail_service.create
resolve_discussions_with_issue(issuable)
+
+ super
end
def resolve_discussions_with_issue(issue)
diff --git a/app/services/merge_requests/create_service.rb b/app/services/merge_requests/create_service.rb
index 194413bf321..3d53fe0646b 100644
--- a/app/services/merge_requests/create_service.rb
+++ b/app/services/merge_requests/create_service.rb
@@ -28,6 +28,8 @@ module MergeRequests
todo_service.new_merge_request(issuable, current_user)
issuable.cache_merge_request_closes_issues!(current_user)
update_merge_requests_head_pipeline(issuable)
+
+ super
end
private
diff --git a/app/services/projects/count_service.rb b/app/services/projects/count_service.rb
new file mode 100644
index 00000000000..5e633c37bf8
--- /dev/null
+++ b/app/services/projects/count_service.rb
@@ -0,0 +1,43 @@
+module Projects
+ # Base class for the various service classes that count project data (e.g.
+ # issues or forks).
+ class CountService
+ def initialize(project)
+ @project = project
+ end
+
+ def relation_for_count
+ raise(
+ NotImplementedError,
+ '"relation_for_count" must be implemented and return an ActiveRecord::Relation'
+ )
+ end
+
+ def count
+ Rails.cache.fetch(cache_key) { uncached_count }
+ end
+
+ def refresh_cache
+ Rails.cache.write(cache_key, uncached_count)
+ end
+
+ def uncached_count
+ relation_for_count.count
+ end
+
+ def delete_cache
+ Rails.cache.delete(cache_key)
+ end
+
+ def cache_key_name
+ raise(
+ NotImplementedError,
+ '"cache_key_name" must be implemented and return a String'
+ )
+ end
+
+ def cache_key
+ ['projects', @project.id, cache_key_name]
+ end
+ end
+end
diff --git a/app/services/projects/forks_count_service.rb b/app/services/projects/forks_count_service.rb
index e2e2b1da91d..3a0fa84b868 100644
--- a/app/services/projects/forks_count_service.rb
+++ b/app/services/projects/forks_count_service.rb
@@ -1,30 +1,12 @@
module Projects
# Service class for getting and caching the number of forks of a project.
- class ForksCountService
- def initialize(project)
- @project = project
+ class ForksCountService < CountService
+ def relation_for_count
+ @project.forks
end
- def count
- Rails.cache.fetch(cache_key) { uncached_count }
- end
-
- def refresh_cache
- Rails.cache.write(cache_key, uncached_count)
- end
-
- def delete_cache
- Rails.cache.delete(cache_key)
- end
-
- private
-
- def uncached_count
- @project.forks.count
- end
-
- def cache_key
- ['projects', @project.id, 'forks_count']
+ def cache_key_name
+ 'forks_count'
end
end
end
diff --git a/app/services/projects/open_issues_count_service.rb b/app/services/projects/open_issues_count_service.rb
new file mode 100644
index 00000000000..3c0d186a73c
--- /dev/null
+++ b/app/services/projects/open_issues_count_service.rb
@@ -0,0 +1,15 @@
+module Projects
+ # Service class for counting and caching the number of open issues of a
+ # project.
+ class OpenIssuesCountService < CountService
+ def relation_for_count
+ # We don't include confidential issues in this number since this would
+ # expose the number of confidential issues to non project members.
+ @project.issues.opened.public_only
+ end
+
+ def cache_key_name
+ 'open_issues_count'
+ end
+ end
+end
diff --git a/app/services/projects/open_merge_requests_count_service.rb b/app/services/projects/open_merge_requests_count_service.rb
new file mode 100644
index 00000000000..2a90f78b90d
--- /dev/null
+++ b/app/services/projects/open_merge_requests_count_service.rb
@@ -0,0 +1,13 @@
+module Projects
+ # Service class for counting and caching the number of open merge requests of
+ # a project.
+ class OpenMergeRequestsCountService < CountService
+ def relation_for_count
+ @project.merge_requests.opened
+ end
+
+ def cache_key_name
+ 'open_merge_requests_count'
+ end
+ end
+end
diff --git a/app/views/admin/logs/show.html.haml b/app/views/admin/logs/show.html.haml
index 487f1cf5c4f..ee87f25a225 100644
--- a/app/views/admin/logs/show.html.haml
+++ b/app/views/admin/logs/show.html.haml
@@ -1,25 +1,21 @@
- @no_container = true
- page_title "Logs"
-- loggers = [Gitlab::GitLogger, Gitlab::AppLogger,
- Gitlab::EnvironmentLogger, Gitlab::SidekiqLogger,
- Gitlab::RepositoryCheckLogger]
= render 'admin/monitoring/head'
%div{ class: container_class }
%ul.nav-links.log-tabs
- - loggers.each do |klass|
- %li{ class: active_when(klass == Gitlab::GitLogger) }>
- = link_to klass::file_name, "##{klass::file_name_noext}",
- 'data-toggle' => 'tab'
+ - @loggers.each do |klass|
+ %li{ class: active_when(klass == @loggers.first) }>
+ = link_to klass.file_name, "##{klass.file_name_noext}", data: { toggle: 'tab' }
.row-content-block
To prevent performance issues admin logs output the last 2000 lines
.tab-content
- - loggers.each do |klass|
- .tab-pane{ class: active_when(klass == Gitlab::GitLogger), id: klass::file_name_noext }
+ - @loggers.each do |klass|
+ .tab-pane{ class: active_when(klass == @loggers.first), id: klass.file_name_noext }
.file-holder#README
.js-file-title.file-title
%i.fa.fa-file
- = klass::file_name
+ = klass.file_name
.pull-right
= link_to '#', class: 'log-bottom' do
%i.fa.fa-arrow-down
diff --git a/app/views/events/_event_push.atom.haml b/app/views/events/_event_push.atom.haml
index bf655f9d21a..e3c5fd55f08 100644
--- a/app/views/events/_event_push.atom.haml
+++ b/app/views/events/_event_push.atom.haml
@@ -5,9 +5,10 @@
%i
at
= event.created_at.to_s(:short)
- %blockquote= markdown(escape_once(event.commit_title), pipeline: :atom, project: event.project, author: event.author)
- - if event.commits_count > 1
- %p
- %i
- \... and
- = pluralize(event.commits_count - 1, "more commit")
+ - unless event.rm_ref?
+ %blockquote= markdown(escape_once(event.commit_title), pipeline: :atom, project: event.project, author: event.author)
+ - if event.commits_count > 1
+ %p
+ %i
+ \... and
+ = pluralize(event.commits_count - 1, "more commit")
diff --git a/app/views/events/event/_push.html.haml b/app/views/events/event/_push.html.haml
index 973c652ad88..53ebdd6d2ff 100644
--- a/app/views/events/event/_push.html.haml
+++ b/app/views/events/event/_push.html.haml
@@ -41,7 +41,3 @@
%li.commits-stat
= link_to create_mr_path(project.default_branch, event.ref_name, project) do
Create Merge Request
-- elsif event.rm_ref?
- .event-body
- %ul.well-list.event_commits
- = render "events/commit", project: project, event: event
diff --git a/app/views/layouts/errors.html.haml b/app/views/layouts/errors.html.haml
index 6d9ec043590..9382ee8715e 100644
--- a/app/views/layouts/errors.html.haml
+++ b/app/views/layouts/errors.html.haml
@@ -15,7 +15,7 @@
h1 {
font-size: 56px;
line-height: 100px;
- font-weight: normal;
+ font-weight: 400;
color: #456;
}
@@ -28,7 +28,7 @@
h3 {
color: #456;
font-size: 20px;
- font-weight: normal;
+ font-weight: 400;
line-height: 28px;
}
diff --git a/app/views/layouts/nav/_new_project_sidebar.html.haml b/app/views/layouts/nav/_new_project_sidebar.html.haml
index 0ef81375c3a..81c84756ff8 100644
--- a/app/views/layouts/nav/_new_project_sidebar.html.haml
+++ b/app/views/layouts/nav/_new_project_sidebar.html.haml
@@ -86,7 +86,8 @@
%span.nav-item-name
Issues
- if @project.issues_enabled?
- %span.badge.count.issue_counter= number_with_delimiter(IssuesFinder.new(current_user, project_id: @project.id).execute.opened.count)
+ %span.badge.count.issue_counter
+ = number_with_delimiter(@project.open_issues_count)
%ul.sidebar-sub-level-items
= nav_link(controller: :issues) do
@@ -116,7 +117,8 @@
= custom_icon('mr_bold')
%span.nav-item-name
Merge Requests
- %span.badge.count.merge_counter.js-merge-counter= number_with_delimiter(MergeRequestsFinder.new(current_user, project_id: @project.id).execute.opened.count)
+ %span.badge.count.merge_counter.js-merge-counter
+ = number_with_delimiter(@project.open_merge_requests_count)
- if project_nav_tab? :pipelines
= nav_link(controller: [:pipelines, :builds, :jobs, :pipeline_schedules, :environments, :artifacts]) do
diff --git a/app/views/layouts/nav/_project.html.haml b/app/views/layouts/nav/_project.html.haml
index 924cd2e9681..b88465848e3 100644
--- a/app/views/layouts/nav/_project.html.haml
+++ b/app/views/layouts/nav/_project.html.haml
@@ -28,7 +28,8 @@
%span
Issues
- if @project.issues_enabled?
- %span.badge.count.issue_counter= number_with_delimiter(issuables_count_for_state(:issues, :opened, finder: IssuesFinder.new(current_user, project_id: @project.id)))
+ %span.badge.count.issue_counter
+ = number_with_delimiter(@project.open_issues_count)
- if project_nav_tab? :merge_requests
- controllers = [:merge_requests, 'projects/merge_requests/conflicts']
@@ -37,7 +38,8 @@
= link_to project_merge_requests_path(@project), title: 'Merge Requests', class: 'shortcuts-merge_requests' do
%span
Merge Requests
- %span.badge.count.merge_counter.js-merge-counter= number_with_delimiter(issuables_count_for_state(:merge_requests, :opened, finder: MergeRequestsFinder.new(current_user, project_id: @project.id)))
+ %span.badge.count.merge_counter.js-merge-counter
+ = number_with_delimiter(@project.open_merge_requests_count)
- if project_nav_tab? :pipelines
= nav_link(controller: [:pipelines, :builds, :environments, :artifacts]) do
diff --git a/app/views/layouts/oauth_error.html.haml b/app/views/layouts/oauth_error.html.haml
index 34bcd2a8b3a..03b387f8181 100644
--- a/app/views/layouts/oauth_error.html.haml
+++ b/app/views/layouts/oauth_error.html.haml
@@ -19,7 +19,7 @@
h3 {
color: #456;
font-size: 22px;
- font-weight: bold;
+ font-weight: 600;
margin-bottom: 6px;
}
diff --git a/app/views/projects/_project_templates.html.haml b/app/views/projects/_project_templates.html.haml
index 97cf13df070..5638b7da1b0 100644
--- a/app/views/projects/_project_templates.html.haml
+++ b/app/views/projects/_project_templates.html.haml
@@ -1,6 +1,6 @@
.project-templates-buttons.import-buttons{ data: { toggle: "buttons" } }
.btn.blank-option.active
- %input{ type: "radio", autocomplete: "off", name: "project_templates", id: "blank", checked: "true" }
+ %input{ type: "radio", autocomplete: "off", name: "project[template_name]", id: "blank", checked: "true", value: "" }
= icon('file-o', class: 'btn-template-icon')
Blank
- Gitlab::ProjectTemplate.all.each do |template|
diff --git a/app/views/projects/commits/_commit.html.haml b/app/views/projects/commits/_commit.html.haml
index 7e8a5a38086..1214aabe837 100644
--- a/app/views/projects/commits/_commit.html.haml
+++ b/app/views/projects/commits/_commit.html.haml
@@ -37,14 +37,14 @@
.commit-actions.hidden-xs
- - if commit.status(ref)
- = render_commit_status(commit, ref: ref)
-
- if request.xhr?
= render partial: 'projects/commit/signature', object: commit.signature
- else
= render partial: 'projects/commit/ajax_signature', locals: { commit: commit }
+ - if commit.status(ref)
+ = render_commit_status(commit, ref: ref)
+
= link_to commit.short_id, project_commit_path(project, commit), class: "commit-sha btn btn-transparent"
= clipboard_button(text: commit.id, title: _("Copy commit SHA to clipboard"))
= link_to_browse_code(project, commit)
diff --git a/app/views/projects/runners/_runner.html.haml b/app/views/projects/runners/_runner.html.haml
index abc97bcdff5..25d862ab4de 100644
--- a/app/views/projects/runners/_runner.html.haml
+++ b/app/views/projects/runners/_runner.html.haml
@@ -8,7 +8,7 @@
- if runner.locked?
= icon('lock', class: 'has-tooltip', title: 'Locked to current projects')
- %small
+ %small.edit-runner
= link_to edit_project_runner_path(@project, runner) do
%i.fa.fa-edit.btn
- else
diff --git a/app/views/shared/issuable/_user_dropdown_item.html.haml b/app/views/shared/issuable/_user_dropdown_item.html.haml
index c18e4975bb8..48d04678d47 100644
--- a/app/views/shared/issuable/_user_dropdown_item.html.haml
+++ b/app/views/shared/issuable/_user_dropdown_item.html.haml
@@ -4,7 +4,7 @@
%li.filter-dropdown-item{ class: ('js-current-user' if user == current_user) }
%button.btn.btn-link.dropdown-user{ type: :button }
.avatar-container.s40
- = user_avatar_without_link(user: user, lazy: avatar[:lazy], url: avatar[:url], size: 40).gsub('/images/{{avatar_url}}','{{avatar_url}}').html_safe
+ = user_avatar_without_link(user: user, lazy: avatar[:lazy], url: avatar[:url], size: 40, has_tooltip: false).gsub('/images/{{avatar_url}}','{{avatar_url}}').html_safe
.dropdown-user-details
%span
= user.name
diff --git a/app/views/shared/projects/_dropdown.html.haml b/app/views/shared/projects/_dropdown.html.haml
index 8939aeb6c3a..80432a73e4e 100644
--- a/app/views/shared/projects/_dropdown.html.haml
+++ b/app/views/shared/projects/_dropdown.html.haml
@@ -15,8 +15,11 @@
= link_to filter_projects_path(archived: nil), class: ("is-active" unless params[:archived].present?) do
Hide archived projects
%li
- = link_to filter_projects_path(archived: true), class: ("is-active" if params[:archived].present?) do
+ = link_to filter_projects_path(archived: true), class: ("is-active" if Gitlab::Utils.to_boolean(params[:archived])) do
Show archived projects
+ %li
+ = link_to filter_projects_path(archived: 'only'), class: ("is-active" if params[:archived] == 'only') do
+ Show archived projects only
- if current_user
%li.divider
%li
diff --git a/app/workers/namespaceless_project_destroy_worker.rb b/app/workers/namespaceless_project_destroy_worker.rb
index a9073742ff7..1cfb0be759e 100644
--- a/app/workers/namespaceless_project_destroy_worker.rb
+++ b/app/workers/namespaceless_project_destroy_worker.rb
@@ -18,7 +18,8 @@ class NamespacelessProjectDestroyWorker
rescue ActiveRecord::RecordNotFound
return
end
- return unless project.namespace_id.nil? # Reject doing anything for projects that *do* have a namespace
+
+ return if project.namespace # Reject doing anything for projects that *do* have a namespace
project.team.truncate
diff --git a/changelogs/unreleased/13719-git-gc-timeout.yml b/changelogs/unreleased/13719-git-gc-timeout.yml
deleted file mode 100644
index 13cf97ec764..00000000000
--- a/changelogs/unreleased/13719-git-gc-timeout.yml
+++ /dev/null
@@ -1,3 +0,0 @@
----
-title: "Raise Housekeeping timeout to 24 hours"
-merge_request: 13719
diff --git a/changelogs/unreleased/35994-archived-projects-only.yml b/changelogs/unreleased/35994-archived-projects-only.yml
new file mode 100644
index 00000000000..ce565b177d0
--- /dev/null
+++ b/changelogs/unreleased/35994-archived-projects-only.yml
@@ -0,0 +1,5 @@
+---
+title: Add an option to list only archived projects
+merge_request: 13492
+author: Mehdi Lahmam (@mehlah)
+type: added
diff --git a/changelogs/unreleased/36262_merge_request_reference_in_merge_commit_global.yml b/changelogs/unreleased/36262_merge_request_reference_in_merge_commit_global.yml
new file mode 100644
index 00000000000..356857d6e8a
--- /dev/null
+++ b/changelogs/unreleased/36262_merge_request_reference_in_merge_commit_global.yml
@@ -0,0 +1,5 @@
+---
+title: Merge request reference in merge commit changed to full reference
+merge_request: 13518
+author: haseebeqx
+type: fixed
diff --git a/changelogs/unreleased/backstage-gb-after-save-asynchronous-job-hooks.yml b/changelogs/unreleased/backstage-gb-after-save-asynchronous-job-hooks.yml
new file mode 100644
index 00000000000..fd0b7c4f43c
--- /dev/null
+++ b/changelogs/unreleased/backstage-gb-after-save-asynchronous-job-hooks.yml
@@ -0,0 +1,5 @@
+---
+title: Fire hooks asynchronously when creating a new job to improve performance
+merge_request: 13734
+author:
+type: changed
diff --git a/changelogs/unreleased/bvl-improve-bare-project-import.yml b/changelogs/unreleased/bvl-improve-bare-project-import.yml
new file mode 100644
index 00000000000..74c1da4ea40
--- /dev/null
+++ b/changelogs/unreleased/bvl-improve-bare-project-import.yml
@@ -0,0 +1,6 @@
+---
+title: 'Improve bare project import: Allow subgroups, take default visibility level
+ into account'
+merge_request: 13670
+author:
+type: fixed
diff --git a/changelogs/unreleased/cache-issue-and-mr-counts.yml b/changelogs/unreleased/cache-issue-and-mr-counts.yml
new file mode 100644
index 00000000000..fe3fe3be976
--- /dev/null
+++ b/changelogs/unreleased/cache-issue-and-mr-counts.yml
@@ -0,0 +1,5 @@
+---
+title: Cache the number of open issues and merge requests
+merge_request:
+author:
+type: other
diff --git a/changelogs/unreleased/dm-commit-cache-i18n.yml b/changelogs/unreleased/dm-commit-cache-i18n.yml
deleted file mode 100644
index d47226fd408..00000000000
--- a/changelogs/unreleased/dm-commit-cache-i18n.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Commit rows would occasionally render with the wrong language
-merge_request:
-author:
-type: fixed
diff --git a/changelogs/unreleased/dm-ldap-adapter-attributes.yml b/changelogs/unreleased/dm-ldap-adapter-attributes.yml
new file mode 100644
index 00000000000..edd68ef08e7
--- /dev/null
+++ b/changelogs/unreleased/dm-ldap-adapter-attributes.yml
@@ -0,0 +1,6 @@
+---
+title: Fix signing in using LDAP when attribute mapping uses simple strings instead
+ of arrays
+merge_request:
+author:
+type: fixed
diff --git a/changelogs/unreleased/fix-broadcast-message-caching.yml b/changelogs/unreleased/fix-broadcast-message-caching.yml
deleted file mode 100644
index 58ec1766cfd..00000000000
--- a/changelogs/unreleased/fix-broadcast-message-caching.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Fix caching of future broadcast messages
-merge_request:
-author:
-type: fixed
diff --git a/changelogs/unreleased/fix-gb-fix-head-pipeline-when-pipeline-has-errors.yml b/changelogs/unreleased/fix-gb-fix-head-pipeline-when-pipeline-has-errors.yml
deleted file mode 100644
index ede8031a501..00000000000
--- a/changelogs/unreleased/fix-gb-fix-head-pipeline-when-pipeline-has-errors.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Fix merge request pipeline status when pipeline has errors
-merge_request: 13664
-author:
-type: fixed
diff --git a/changelogs/unreleased/fix-old-mr-diffs.yml b/changelogs/unreleased/fix-old-mr-diffs.yml
new file mode 100644
index 00000000000..b0a011cf354
--- /dev/null
+++ b/changelogs/unreleased/fix-old-mr-diffs.yml
@@ -0,0 +1,6 @@
+---
+title: Show un-highlighted text diffs when we do not have references to the correct
+ blobs
+merge_request:
+author:
+type: fixed
diff --git a/changelogs/unreleased/fix-push-events-branch-removals.yml b/changelogs/unreleased/fix-push-events-branch-removals.yml
new file mode 100644
index 00000000000..71f368db296
--- /dev/null
+++ b/changelogs/unreleased/fix-push-events-branch-removals.yml
@@ -0,0 +1,5 @@
+---
+title: Fix display of push events for removed refs
+merge_request:
+author:
+type: fixed
diff --git a/changelogs/unreleased/font-weight-adjusted.yml b/changelogs/unreleased/font-weight-adjusted.yml
new file mode 100644
index 00000000000..827f3485099
--- /dev/null
+++ b/changelogs/unreleased/font-weight-adjusted.yml
@@ -0,0 +1,5 @@
+---
+title: Changed all font-weight values to 400 and 600 and introduced 2 variables to
+ manage them
+merge_request: !12896
+author:
diff --git a/changelogs/unreleased/only-limit-fetch-when-requested.yml b/changelogs/unreleased/only-limit-fetch-when-requested.yml
deleted file mode 100644
index d9acdf56511..00000000000
--- a/changelogs/unreleased/only-limit-fetch-when-requested.yml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Only require Sidekiq throttling library when enabled, to reduce cache misses
-merge_request:
-author:
-type: fixed
diff --git a/changelogs/unreleased/rd-fix-broken-configuration-for-some-integrations.yml b/changelogs/unreleased/rd-fix-broken-configuration-for-some-integrations.yml
new file mode 100644
index 00000000000..00528397d64
--- /dev/null
+++ b/changelogs/unreleased/rd-fix-broken-configuration-for-some-integrations.yml
@@ -0,0 +1,5 @@
+---
+title: Testing of some integrations were broken due to missing ServiceHook record.
+merge_request:
+author:
+type: fixed
diff --git a/changelogs/unreleased/tc-remove-nonexisting-namespace-pending-delete-projects.yml b/changelogs/unreleased/tc-remove-nonexisting-namespace-pending-delete-projects.yml
new file mode 100644
index 00000000000..218336df5d2
--- /dev/null
+++ b/changelogs/unreleased/tc-remove-nonexisting-namespace-pending-delete-projects.yml
@@ -0,0 +1,5 @@
+---
+title: Migration to remove pending delete projects with non-existing namespace
+merge_request: 13598
+author:
+type: other
diff --git a/changelogs/unreleased/use_full_path_in_project_avatar_url_webhook.yml b/changelogs/unreleased/use_full_path_in_project_avatar_url_webhook.yml
new file mode 100644
index 00000000000..0c3acce1455
--- /dev/null
+++ b/changelogs/unreleased/use_full_path_in_project_avatar_url_webhook.yml
@@ -0,0 +1,5 @@
+---
+title: Use full path of project's avatar in webhooks
+merge_request: 13649
+author: Vitaliy @blackst0ne Klachkov
+type: changed
diff --git a/changelogs/unreleased/zj-add-pipeline-source-variable.yml b/changelogs/unreleased/zj-add-pipeline-source-variable.yml
new file mode 100644
index 00000000000..5d98cd8086a
--- /dev/null
+++ b/changelogs/unreleased/zj-add-pipeline-source-variable.yml
@@ -0,0 +1,5 @@
+---
+title: Add CI_PIPELINE_SOURCE variable on CI Jobs
+merge_request:
+author:
+type: added
diff --git a/changelogs/unreleased/zj-fix-fe-blank-button.yml b/changelogs/unreleased/zj-fix-fe-blank-button.yml
new file mode 100644
index 00000000000..2165d4186c1
--- /dev/null
+++ b/changelogs/unreleased/zj-fix-fe-blank-button.yml
@@ -0,0 +1,5 @@
+---
+title: Fix new project form not resetting the template value
+merge_request:
+author:
+type: fixed
diff --git a/db/post_migrate/20170816102555_cleanup_nonexisting_namespace_pending_delete_projects.rb b/db/post_migrate/20170816102555_cleanup_nonexisting_namespace_pending_delete_projects.rb
new file mode 100644
index 00000000000..3f085c17133
--- /dev/null
+++ b/db/post_migrate/20170816102555_cleanup_nonexisting_namespace_pending_delete_projects.rb
@@ -0,0 +1,54 @@
+# Follow up of CleanupNamespacelessPendingDeleteProjects and it cleans
+# all projects with `pending_delete = true` and for which the
+# namespace no longer exists.
+class CleanupNonexistingNamespacePendingDeleteProjects < ActiveRecord::Migration
+ include Gitlab::Database::MigrationHelpers
+
+ DOWNTIME = false
+
+ disable_ddl_transaction!
+
+ class Project < ActiveRecord::Base
+ self.table_name = 'projects'
+
+ include ::EachBatch
+ end
+
+ class Namespace < ActiveRecord::Base
+ self.table_name = 'namespaces'
+ end
+
+ def up
+ find_projects.each_batch do |batch|
+ args = batch.pluck(:id).map { |id| [id] }
+
+ NamespacelessProjectDestroyWorker.bulk_perform_async(args)
+ end
+ end
+
+ def down
+ # NOOP
+ end
+
+ private
+
+ def find_projects
+ projects = Project.arel_table
+ namespaces = Namespace.arel_table
+
+ namespace_query = namespaces.project(1)
+ .where(namespaces[:id].eq(projects[:namespace_id]))
+ .exists.not
+
+ # SELECT "projects"."id"
+ # FROM "projects"
+ # WHERE "projects"."pending_delete" = 't'
+ # AND (NOT (EXISTS
+ # (SELECT 1
+ # FROM "namespaces"
+ # WHERE "namespaces"."id" = "projects"."namespace_id")))
+ Project.where(projects[:pending_delete].eq(true))
+ .where(namespace_query)
+ .select(:id)
+ end
+end
diff --git a/doc/ci/variables/README.md b/doc/ci/variables/README.md
index 22e7f6879ed..e55a92dbb71 100644
--- a/doc/ci/variables/README.md
+++ b/doc/ci/variables/README.md
@@ -57,6 +57,7 @@ future GitLab releases.**
| **CI_RUNNER_TAGS** | 8.10 | 0.5 | The defined runner tags |
| **CI_PIPELINE_ID** | 8.10 | 0.5 | The unique id of the current pipeline that GitLab CI uses internally |
| **CI_PIPELINE_TRIGGERED** | all | all | The flag to indicate that job was [triggered] |
+| **CI_PIPELINE_SOURCE** | 10.0 | all | The source for this pipeline, one of: push, web, trigger, schedule, api, external. Pipelines created before 9.5 will have unknown as source |
| **CI_PROJECT_DIR** | all | all | The full path where the repository is cloned and where the job is run |
| **CI_PROJECT_ID** | all | all | The unique id of the current project that GitLab CI uses internally |
| **CI_PROJECT_NAME** | 8.10 | 0.5 | The project name that is currently being built (actually it is project folder name) |
diff --git a/doc/development/licensing.md b/doc/development/licensing.md
index 1f115059fb8..2b16dfe0e7c 100644
--- a/doc/development/licensing.md
+++ b/doc/development/licensing.md
@@ -66,7 +66,7 @@ Libraries with the following licenses are unacceptable for use:
## Requesting Approval for Licenses
-Libraries that are not listed in the [Acceptable Licenses][Acceptable-Licenses] or [Unacceptable Licenses][Unacceptable-Licenses] list can be submitted to the legal team for review. Please create an issue in the [Organization Repository][Org-Repo] and cc `@gl-legal`. After a decision has been made, the original requestor is responsible for updating this document.
+Libraries that are not listed in the [Acceptable Licenses][Acceptable-Licenses] or [Unacceptable Licenses][Unacceptable-Licenses] list can be submitted to the legal team for review. Please email `legal@gitlab.com` with the details. After a decision has been made, the original requestor is responsible for updating this document.
## Notes
diff --git a/features/steps/project/pages.rb b/features/steps/project/pages.rb
index 275fb4fc010..bb69c0d6e99 100644
--- a/features/steps/project/pages.rb
+++ b/features/steps/project/pages.rb
@@ -35,7 +35,10 @@ class Spinach::Features::ProjectPages < Spinach::FeatureSteps
end
step 'pages are deployed' do
- pipeline = @project.pipelines.create(ref: 'HEAD', sha: @project.commit('HEAD').sha)
+ pipeline = @project.pipelines.create(ref: 'HEAD',
+ sha: @project.commit('HEAD').sha,
+ source: :push)
+
build = build(:ci_build,
project: @project,
pipeline: pipeline,
@@ -43,6 +46,7 @@ class Spinach::Features::ProjectPages < Spinach::FeatureSteps
artifacts_file: fixture_file_upload(Rails.root + 'spec/fixtures/pages.zip'),
artifacts_metadata: fixture_file_upload(Rails.root + 'spec/fixtures/pages.zip.meta')
)
+
result = ::Projects::UpdatePagesService.new(@project, build).execute
expect(result[:status]).to eq(:success)
end
diff --git a/lib/github/import.rb b/lib/github/import.rb
index 4cc01593ef4..7b848081e85 100644
--- a/lib/github/import.rb
+++ b/lib/github/import.rb
@@ -107,7 +107,7 @@ module Github
# this means that repo has wiki enabled, but have no pages. So,
# we can skip the import.
if e.message !~ /repository not exported/
- errors(:wiki, wiki_url, e.message)
+ error(:wiki, wiki_url, e.message)
end
end
diff --git a/lib/gitlab/bare_repository_importer.rb b/lib/gitlab/bare_repository_importer.rb
new file mode 100644
index 00000000000..9323bfc7fb2
--- /dev/null
+++ b/lib/gitlab/bare_repository_importer.rb
@@ -0,0 +1,96 @@
+module Gitlab
+ class BareRepositoryImporter
+ NoAdminError = Class.new(StandardError)
+
+ def self.execute
+ Gitlab.config.repositories.storages.each do |storage_name, repository_storage|
+ git_base_path = repository_storage['path']
+ repos_to_import = Dir.glob(git_base_path + '/**/*.git')
+
+ repos_to_import.each do |repo_path|
+ if repo_path.end_with?('.wiki.git')
+ log " * Skipping wiki repo"
+ next
+ end
+
+ log "Processing #{repo_path}".color(:yellow)
+
+ repo_relative_path = repo_path[repository_storage['path'].length..-1]
+ .sub(/^\//, '') # Remove leading `/`
+ .sub(/\.git$/, '') # Remove `.git` at the end
+ new(storage_name, repo_relative_path).create_project_if_needed
+ end
+ end
+ end
+
+ attr_reader :storage_name, :full_path, :group_path, :project_path, :user
+ delegate :log, to: :class
+
+ def initialize(storage_name, repo_path)
+ @storage_name = storage_name
+ @full_path = repo_path
+
+ unless @user = User.admins.order_id_asc.first
+ raise NoAdminError.new('No admin user found to import repositories')
+ end
+
+ @group_path, @project_path = File.split(repo_path)
+ @group_path = nil if @group_path == '.'
+ end
+
+ def create_project_if_needed
+ if project = Project.find_by_full_path(full_path)
+ log " * #{project.name} (#{full_path}) exists"
+ return project
+ end
+
+ create_project
+ end
+
+ private
+
+ def create_project
+ group = find_or_create_group
+
+ project_params = {
+ name: project_path,
+ path: project_path,
+ repository_storage: storage_name,
+ namespace_id: group&.id
+ }
+
+ project = Projects::CreateService.new(user, project_params).execute
+
+ if project.persisted?
+ log " * Created #{project.name} (#{full_path})".color(:green)
+ ProjectCacheWorker.perform_async(project.id)
+ else
+ log " * Failed trying to create #{project.name} (#{full_path})".color(:red)
+ log " Errors: #{project.errors.messages}".color(:red)
+ end
+
+ project
+ end
+
+ def find_or_create_group
+ return nil unless group_path
+
+ if namespace = Namespace.find_by_full_path(group_path)
+ log " * Namespace #{group_path} exists.".color(:green)
+ return namespace
+ end
+
+ log " * Creating Group: #{group_path}"
+ Groups::NestedCreateService.new(user, group_path: group_path).execute
+ end
+
+ # This is called from within a rake task only used by Admins, so allow writing
+ # to STDOUT
+ #
+ # rubocop:disable Rails/Output
+ def self.log(message)
+ puts message
+ end
+ # rubocop:enable Rails/Output
+ end
+end
diff --git a/lib/gitlab/diff/file.rb b/lib/gitlab/diff/file.rb
index 6d7de52cb80..1dabd4ebdd0 100644
--- a/lib/gitlab/diff/file.rb
+++ b/lib/gitlab/diff/file.rb
@@ -186,7 +186,10 @@ module Gitlab
end
def content_changed?
- old_blob && new_blob && old_blob.id != new_blob.id
+ return blobs_changed? if diff_refs
+ return false if new_file? || deleted_file? || renamed_file?
+
+ text? && diff_lines.any?
end
def different_type?
@@ -225,6 +228,10 @@ module Gitlab
private
+ def blobs_changed?
+ old_blob && new_blob && old_blob.id != new_blob.id
+ end
+
def simple_viewer_class
return DiffViewer::NotDiffable unless diffable?
@@ -250,6 +257,8 @@ module Gitlab
DiffViewer::Renamed
elsif mode_changed?
DiffViewer::ModeChanged
+ else
+ DiffViewer::NoPreview
end
end
diff --git a/lib/gitlab/git/commit.rb b/lib/gitlab/git/commit.rb
index a499bbc6266..5ee6669050c 100644
--- a/lib/gitlab/git/commit.rb
+++ b/lib/gitlab/git/commit.rb
@@ -271,7 +271,13 @@ module Gitlab
#
# Gitaly migration: https://gitlab.com/gitlab-org/gitaly/issues/324
def to_diff
- rugged_diff_from_parent.patch
+ Gitlab::GitalyClient.migrate(:commit_patch) do |is_enabled|
+ if is_enabled
+ @repository.gitaly_commit_client.patch(id)
+ else
+ rugged_diff_from_parent.patch
+ end
+ end
end
# Returns a diff object for the changes from this commit's first parent.
diff --git a/lib/gitlab/git/repository.rb b/lib/gitlab/git/repository.rb
index 976ea7e4035..b835dec24eb 100644
--- a/lib/gitlab/git/repository.rb
+++ b/lib/gitlab/git/repository.rb
@@ -154,7 +154,7 @@ module Gitlab
if is_enabled
gitaly_ref_client.count_branch_names
else
- rugged.branches.count do |ref|
+ rugged.branches.each(:local).count do |ref|
begin
ref.name && ref.target # ensures the branch is valid
@@ -202,6 +202,19 @@ module Gitlab
end
end
+ # Returns true if the given ref name exists
+ #
+ # Ref names must start with `refs/`.
+ def ref_exists?(ref_name)
+ gitaly_migrate(:ref_exists) do |is_enabled|
+ if is_enabled
+ gitaly_ref_exists?(ref_name)
+ else
+ rugged_ref_exists?(ref_name)
+ end
+ end
+ end
+
# Returns true if the given tag exists
#
# name - The name of the tag as a String.
@@ -993,6 +1006,16 @@ module Gitlab
# Returns true if the given ref name exists
#
# Ref names must start with `refs/`.
+ def rugged_ref_exists?(ref_name)
+ raise ArgumentError, 'invalid refname' unless ref_name.start_with?('refs/')
+ rugged.references.exist?(ref_name)
+ rescue Rugged::ReferenceError
+ false
+ end
+
+ # Returns true if the given ref name exists
+ #
+ # Ref names must start with `refs/`.
def gitaly_ref_exists?(ref_name)
gitaly_ref_client.ref_exists?(ref_name)
end
diff --git a/lib/gitlab/gitaly_client/commit_service.rb b/lib/gitlab/gitaly_client/commit_service.rb
index 2d58fb0186e..57f42bd35ee 100644
--- a/lib/gitlab/gitaly_client/commit_service.rb
+++ b/lib/gitlab/gitaly_client/commit_service.rb
@@ -175,8 +175,8 @@ module Gitlab
def raw_blame(revision, path)
request = Gitaly::RawBlameRequest.new(
repository: @gitaly_repo,
- revision: revision,
- path: path
+ revision: GitalyClient.encode(revision),
+ path: GitalyClient.encode(path)
)
response = GitalyClient.call(@repository.storage, :commit_service, :raw_blame, request)
@@ -194,6 +194,16 @@ module Gitlab
response.commit
end
+ def patch(revision)
+ request = Gitaly::CommitPatchRequest.new(
+ repository: @gitaly_repo,
+ revision: GitalyClient.encode(revision)
+ )
+ response = GitalyClient.call(@repository.storage, :diff_service, :commit_patch, request)
+
+ response.sum(&:data)
+ end
+
private
def commit_diff_request_params(commit, options = {})
diff --git a/lib/gitlab/gitaly_client/ref_service.rb b/lib/gitlab/gitaly_client/ref_service.rb
index cdcfed36740..8c0008c6971 100644
--- a/lib/gitlab/gitaly_client/ref_service.rb
+++ b/lib/gitlab/gitaly_client/ref_service.rb
@@ -71,7 +71,7 @@ module Gitlab
end
def ref_exists?(ref_name)
- request = Gitaly::RefExistsRequest.new(repository: @gitaly_repo, ref: ref_name)
+ request = Gitaly::RefExistsRequest.new(repository: @gitaly_repo, ref: GitalyClient.encode(ref_name))
response = GitalyClient.call(@storage, :ref_service, :ref_exists, request)
response.value
rescue GRPC::InvalidArgument => e
diff --git a/lib/gitlab/ldap/adapter.rb b/lib/gitlab/ldap/adapter.rb
index 8867a91c244..cd7e4ca7b7e 100644
--- a/lib/gitlab/ldap/adapter.rb
+++ b/lib/gitlab/ldap/adapter.rb
@@ -73,7 +73,7 @@ module Gitlab
private
def user_options(field, value, limit)
- options = { attributes: user_attributes }
+ options = { attributes: Gitlab::LDAP::Person.ldap_attributes(config).compact.uniq }
options[:size] = limit if limit
if field.to_sym == :dn
@@ -99,10 +99,6 @@ module Gitlab
filter
end
end
-
- def user_attributes
- %W(#{config.uid} cn dn) + config.attributes['username'] + config.attributes['email']
- end
end
end
end
diff --git a/lib/gitlab/ldap/person.rb b/lib/gitlab/ldap/person.rb
index e138b466a34..4d6f8ac79de 100644
--- a/lib/gitlab/ldap/person.rb
+++ b/lib/gitlab/ldap/person.rb
@@ -21,6 +21,15 @@ module Gitlab
adapter.dn_matches_filter?(dn, AD_USER_DISABLED)
end
+ def self.ldap_attributes(config)
+ [
+ 'dn', # Used in `dn`
+ config.uid, # Used in `uid`
+ *config.attributes['name'], # Used in `name`
+ *config.attributes['email'] # Used in `email`
+ ]
+ end
+
def initialize(entry, provider)
Rails.logger.debug { "Instantiating #{self.class.name} with LDIF:\n#{entry.to_ldif}" }
@entry = entry
diff --git a/lib/gitlab/logger.rb b/lib/gitlab/logger.rb
index 59b21149a9a..6bffd410ed0 100644
--- a/lib/gitlab/logger.rb
+++ b/lib/gitlab/logger.rb
@@ -14,13 +14,9 @@ module Gitlab
def self.read_latest
path = Rails.root.join("log", file_name)
- self.build unless File.exist?(path)
- tail_output, _ = Gitlab::Popen.popen(%W(tail -n 2000 #{path}))
- tail_output.split("\n")
- end
- def self.read_latest_for(filename)
- path = Rails.root.join("log", filename)
+ return [] unless File.readable?(path)
+
tail_output, _ = Gitlab::Popen.popen(%W(tail -n 2000 #{path}))
tail_output.split("\n")
end
diff --git a/lib/tasks/gitlab/import.rake b/lib/tasks/gitlab/import.rake
index 6e10ba374bf..d227a0c8bdb 100644
--- a/lib/tasks/gitlab/import.rake
+++ b/lib/tasks/gitlab/import.rake
@@ -9,6 +9,7 @@ namespace :gitlab do
# * The project owner will set to the first administator of the system
# * Existing projects will be skipped
#
+ #
desc "GitLab | Import bare repositories from repositories -> storages into GitLab project instance"
task repos: :environment do
if Project.current_application_settings.hashed_storage_enabled
@@ -17,69 +18,7 @@ namespace :gitlab do
exit 1
end
- Gitlab.config.repositories.storages.each_value do |repository_storage|
- git_base_path = repository_storage['path']
- repos_to_import = Dir.glob(git_base_path + '/**/*.git')
-
- repos_to_import.each do |repo_path|
- # strip repo base path
- repo_path[0..git_base_path.length] = ''
-
- path = repo_path.sub(/\.git$/, '')
- group_name, name = File.split(path)
- group_name = nil if group_name == '.'
-
- puts "Processing #{repo_path}".color(:yellow)
-
- if path.end_with?('.wiki')
- puts " * Skipping wiki repo"
- next
- end
-
- project = Project.find_by_full_path(path)
-
- if project
- puts " * #{project.name} (#{repo_path}) exists"
- else
- user = User.admins.reorder("id").first
-
- project_params = {
- name: name,
- path: name
- }
-
- # find group namespace
- if group_name
- group = Namespace.find_by(path: group_name)
- # create group namespace
- unless group
- group = Group.new(name: group_name)
- group.path = group_name
- group.owner = user
- if group.save
- puts " * Created Group #{group.name} (#{group.id})".color(:green)
- else
- puts " * Failed trying to create group #{group.name}".color(:red)
- end
- end
- # set project group
- project_params[:namespace_id] = group.id
- end
-
- project = Projects::CreateService.new(user, project_params).execute
-
- if project.persisted?
- puts " * Created #{project.name} (#{repo_path})".color(:green)
- ProjectCacheWorker.perform_async(project.id)
- else
- puts " * Failed trying to create #{project.name} (#{repo_path})".color(:red)
- puts " Errors: #{project.errors.messages}".color(:red)
- end
- end
- end
- end
-
- puts "Done!".color(:green)
+ Gitlab::BareRepositoryImporter.execute
end
end
end
diff --git a/lib/tasks/import.rake b/lib/tasks/import.rake
index 96b8f59242c..1206302cb76 100644
--- a/lib/tasks/import.rake
+++ b/lib/tasks/import.rake
@@ -72,23 +72,7 @@ class GithubImport
return @current_user.namespace if names == @current_user.namespace_path
return @current_user.namespace unless @current_user.can_create_group?
- full_path_namespace = Namespace.find_by_full_path(names)
-
- return full_path_namespace if full_path_namespace
-
- names.split('/').inject(nil) do |parent, name|
- begin
- namespace = Group.create!(name: name,
- path: name,
- owner: @current_user,
- parent: parent)
- namespace.add_owner(@current_user)
-
- namespace
- rescue ActiveRecord::RecordNotUnique, ActiveRecord::RecordInvalid
- Namespace.where(parent: parent).find_by_path_or_name(name)
- end
- end
+ Groups::NestedCreateService.new(@current_user, group_path: names).execute
end
def full_path_namespace(names)
diff --git a/public/404.html b/public/404.html
index 03e98e81862..4db72be6f8c 100644
--- a/public/404.html
+++ b/public/404.html
@@ -15,7 +15,7 @@
h1 {
font-size: 56px;
line-height: 100px;
- font-weight: normal;
+ font-weight: 400;
color: #456;
}
@@ -28,7 +28,7 @@
h3 {
color: #456;
font-size: 20px;
- font-weight: normal;
+ font-weight: 400;
line-height: 28px;
}
@@ -48,7 +48,7 @@
a {
line-height: 100px;
- font-weight: normal;
+ font-weight: 400;
color: #4A8BEE;
font-size: 18px;
text-decoration: none;
diff --git a/public/422.html b/public/422.html
index 49ebbe40f39..a67dcd02200 100644
--- a/public/422.html
+++ b/public/422.html
@@ -15,7 +15,7 @@
h1 {
font-size: 56px;
line-height: 100px;
- font-weight: normal;
+ font-weight: 400;
color: #456;
}
@@ -28,7 +28,7 @@
h3 {
color: #456;
font-size: 20px;
- font-weight: normal;
+ font-weight: 400;
line-height: 28px;
}
@@ -48,7 +48,7 @@
a {
line-height: 100px;
- font-weight: normal;
+ font-weight: 400;
color: #4A8BEE;
font-size: 18px;
text-decoration: none;
diff --git a/public/500.html b/public/500.html
index 516920f7471..7091d14dfc4 100644
--- a/public/500.html
+++ b/public/500.html
@@ -15,7 +15,7 @@
h1 {
font-size: 56px;
line-height: 100px;
- font-weight: normal;
+ font-weight: 400;
color: #456;
}
@@ -28,7 +28,7 @@
h3 {
color: #456;
font-size: 20px;
- font-weight: normal;
+ font-weight: 400;
line-height: 28px;
}
@@ -48,7 +48,7 @@
a {
line-height: 100px;
- font-weight: normal;
+ font-weight: 400;
color: #4A8BEE;
font-size: 18px;
text-decoration: none;
diff --git a/public/502.html b/public/502.html
index 189458c9816..82afd273248 100644
--- a/public/502.html
+++ b/public/502.html
@@ -15,7 +15,7 @@
h1 {
font-size: 56px;
line-height: 100px;
- font-weight: normal;
+ font-weight: 400;
color: #456;
}
@@ -28,7 +28,7 @@
h3 {
color: #456;
font-size: 20px;
- font-weight: normal;
+ font-weight: 400;
line-height: 28px;
}
@@ -48,7 +48,7 @@
a {
line-height: 100px;
- font-weight: normal;
+ font-weight: 400;
color: #4A8BEE;
font-size: 18px;
text-decoration: none;
diff --git a/public/503.html b/public/503.html
index b09b0e2a67e..f1486bc3e84 100644
--- a/public/503.html
+++ b/public/503.html
@@ -15,7 +15,7 @@
h1 {
font-size: 56px;
line-height: 100px;
- font-weight: normal;
+ font-weight: 400;
color: #456;
}
@@ -28,7 +28,7 @@
h3 {
color: #456;
font-size: 20px;
- font-weight: normal;
+ font-weight: 400;
line-height: 28px;
}
@@ -48,7 +48,7 @@
a {
line-height: 100px;
- font-weight: normal;
+ font-weight: 400;
color: #4A8BEE;
font-size: 18px;
text-decoration: none;
diff --git a/public/deploy.html b/public/deploy.html
index 49ec4ac5ce1..e463b62520c 100644
--- a/public/deploy.html
+++ b/public/deploy.html
@@ -20,7 +20,7 @@
h1 {
font-size: 56px;
line-height: 100px;
- font-weight: normal;
+ font-weight: 400;
color: #456;
}
@@ -33,7 +33,7 @@
h3 {
color: #456;
font-size: 20px;
- font-weight: normal;
+ font-weight: 400;
line-height: 28px;
}
@@ -66,4 +66,4 @@
<p>Please contact your GitLab administrator if this problem persists.</p>
</div>
</body>
-</html> \ No newline at end of file
+</html>
diff --git a/spec/controllers/projects/services_controller_spec.rb b/spec/controllers/projects/services_controller_spec.rb
index 4e9b0c09ff2..efba9cc7306 100644
--- a/spec/controllers/projects/services_controller_spec.rb
+++ b/spec/controllers/projects/services_controller_spec.rb
@@ -10,9 +10,6 @@ describe Projects::ServicesController do
before do
sign_in(user)
project.team << [user, :master]
-
- controller.instance_variable_set(:@project, project)
- controller.instance_variable_set(:@service, service)
end
describe '#test' do
@@ -20,7 +17,7 @@ describe Projects::ServicesController do
it 'renders 404' do
allow_any_instance_of(Service).to receive(:can_test?).and_return(false)
- put :test, namespace_id: project.namespace.id, project_id: project.id, id: service.id
+ put :test, namespace_id: project.namespace, project_id: project, id: service.to_param
expect(response).to have_http_status(404)
end
@@ -36,7 +33,7 @@ describe Projects::ServicesController do
it 'returns success' do
allow_any_instance_of(MicrosoftTeams::Notifier).to receive(:ping).and_return(true)
- put :test, namespace_id: project.namespace.id, project_id: project.id, id: service.id
+ put :test, namespace_id: project.namespace, project_id: project, id: service.to_param
expect(response.status).to eq(200)
end
@@ -45,7 +42,7 @@ describe Projects::ServicesController do
it 'returns success' do
expect(HipChat::Client).to receive(:new).with('hipchat_token_p', anything).and_return(hipchat_client)
- put :test, namespace_id: project.namespace.id, project_id: project.id, id: service.id, service: service_params
+ put :test, namespace_id: project.namespace, project_id: project, id: service.to_param, service: service_params
expect(response.status).to eq(200)
end
@@ -54,17 +51,42 @@ describe Projects::ServicesController do
it 'returns success' do
expect(HipChat::Client).to receive(:new).with('hipchat_token_p', anything).and_return(hipchat_client)
- put :test, namespace_id: project.namespace.id, project_id: project.id, id: service.id, service: service_params
+ put :test, namespace_id: project.namespace, project_id: project, id: service.to_param, service: service_params
expect(response.status).to eq(200)
end
+
+ context 'when service is configured for the first time' do
+ before do
+ allow_any_instance_of(ServiceHook).to receive(:execute).and_return(true)
+ end
+
+ it 'persist the object' do
+ do_put
+
+ expect(BuildkiteService.first).to be_present
+ end
+
+ it 'creates the ServiceHook object' do
+ do_put
+
+ expect(BuildkiteService.first.service_hook).to be_present
+ end
+
+ def do_put
+ put :test, namespace_id: project.namespace,
+ project_id: project,
+ id: 'buildkite',
+ service: { 'active' => '1', 'push_events' => '1', token: 'token', 'project_url' => 'http://test.com' }
+ end
+ end
end
context 'failure' do
it 'returns success status code and the error message' do
expect(HipChat::Client).to receive(:new).with('hipchat_token_p', anything).and_raise('Bad test')
- put :test, namespace_id: project.namespace.id, project_id: project.id, id: service.id, service: service_params
+ put :test, namespace_id: project.namespace, project_id: project, id: service.to_param, service: service_params
expect(response.status).to eq(200)
expect(JSON.parse(response.body))
@@ -77,7 +99,7 @@ describe Projects::ServicesController do
context 'when param `active` is set to true' do
it 'activates the service and redirects to integrations paths' do
put :update,
- namespace_id: project.namespace.id, project_id: project.id, id: service.id, service: { active: true }
+ namespace_id: project.namespace, project_id: project, id: service.to_param, service: { active: true }
expect(response).to redirect_to(project_settings_integrations_path(project))
expect(flash[:notice]).to eq 'HipChat activated.'
@@ -87,7 +109,7 @@ describe Projects::ServicesController do
context 'when param `active` is set to false' do
it 'does not activate the service but saves the settings' do
put :update,
- namespace_id: project.namespace.id, project_id: project.id, id: service.id, service: { active: false }
+ namespace_id: project.namespace, project_id: project, id: service.to_param, service: { active: false }
expect(flash[:notice]).to eq 'HipChat settings saved, but not activated.'
end
diff --git a/spec/features/admin/admin_projects_spec.rb b/spec/features/admin/admin_projects_spec.rb
index 77710f80036..f4f2505d436 100644
--- a/spec/features/admin/admin_projects_spec.rb
+++ b/spec/features/admin/admin_projects_spec.rb
@@ -36,6 +36,14 @@ describe "Admin::Projects" do
expect(page).to have_content(archived_project.name)
expect(page).to have_xpath("//span[@class='label label-warning']", text: 'archived')
end
+
+ it 'renders only archived projects', js: true do
+ find(:css, '#sort-projects-dropdown').click
+ click_link 'Show archived projects only'
+
+ expect(page).to have_content(archived_project.name)
+ expect(page).not_to have_content(project.name)
+ end
end
describe "GET /admin/projects/:namespace_id/:id" do
diff --git a/spec/features/calendar_spec.rb b/spec/features/calendar_spec.rb
index 9a597a2d690..4fc6956d111 100644
--- a/spec/features/calendar_spec.rb
+++ b/spec/features/calendar_spec.rb
@@ -2,7 +2,7 @@ require 'spec_helper'
feature 'Contributions Calendar', :js do
let(:user) { create(:user) }
- let(:contributed_project) { create(:project, :public) }
+ let(:contributed_project) { create(:project, :public, :repository) }
let(:issue_note) { create(:note, project: contributed_project) }
# Ex/ Sunday Jan 1, 2016
diff --git a/spec/features/dashboard/activity_spec.rb b/spec/features/dashboard/activity_spec.rb
index 582868bac1e..bd115785646 100644
--- a/spec/features/dashboard/activity_spec.rb
+++ b/spec/features/dashboard/activity_spec.rb
@@ -17,7 +17,7 @@ feature 'Dashboard > Activity' do
end
context 'event filters', :js do
- let(:project) { create(:project) }
+ let(:project) { create(:project, :repository) }
let(:merge_request) do
create(:merge_request, author: user, source_project: project, target_project: project)
diff --git a/spec/features/dashboard/archived_projects_spec.rb b/spec/features/dashboard/archived_projects_spec.rb
index 814ec0e59c7..e8d699ff5e0 100644
--- a/spec/features/dashboard/archived_projects_spec.rb
+++ b/spec/features/dashboard/archived_projects_spec.rb
@@ -26,6 +26,13 @@ RSpec.describe 'Dashboard Archived Project' do
expect(page).to have_link(archived_project.name)
end
+ it 'renders only archived projects' do
+ click_link 'Show archived projects only'
+
+ expect(page).to have_content(archived_project.name)
+ expect(page).not_to have_content(project.name)
+ end
+
it 'searchs archived projects', :js do
click_button 'Last updated'
click_link 'Show archived projects'
diff --git a/spec/features/merge_requests/merge_commit_message_toggle_spec.rb b/spec/features/merge_requests/merge_commit_message_toggle_spec.rb
index 429bc277d73..08a3bb84aac 100644
--- a/spec/features/merge_requests/merge_commit_message_toggle_spec.rb
+++ b/spec/features/merge_requests/merge_commit_message_toggle_spec.rb
@@ -19,7 +19,7 @@ feature 'Clicking toggle commit message link', js: true do
"Merge branch 'feature' into 'master'",
merge_request.title,
"Closes #{issue_1.to_reference} and #{issue_2.to_reference}",
- "See merge request #{merge_request.to_reference}"
+ "See merge request #{merge_request.to_reference(full: true)}"
].join("\n\n")
end
let(:message_with_description) do
@@ -27,7 +27,7 @@ feature 'Clicking toggle commit message link', js: true do
"Merge branch 'feature' into 'master'",
merge_request.title,
merge_request.description,
- "See merge request #{merge_request.to_reference}"
+ "See merge request #{merge_request.to_reference(full: true)}"
].join("\n\n")
end
diff --git a/spec/features/runners_spec.rb b/spec/features/runners_spec.rb
index cac31c34ad1..785cfeb34bd 100644
--- a/spec/features/runners_spec.rb
+++ b/spec/features/runners_spec.rb
@@ -1,149 +1,135 @@
require 'spec_helper'
-describe "Runners" do
- let(:user) { create(:user) }
+feature 'Runners' do
+ given(:user) { create(:user) }
- before do
+ background do
sign_in(user)
end
- describe "specific runners" do
- before do
- @project = FactoryGirl.create :project, shared_runners_enabled: false
- @project.team << [user, :master]
+ context 'when a project has enabled shared_runners' do
+ given(:project) { create(:project) }
- @project2 = FactoryGirl.create :project
- @project2.team << [user, :master]
+ background do
+ project.add_master(user)
+ end
- @project3 = FactoryGirl.create :project
- @project3.team << [user, :developer]
+ context 'when a specific runner is activated on the project' do
+ given(:specific_runner) { create(:ci_runner, :specific) }
- @shared_runner = FactoryGirl.create :ci_runner, :shared
- @specific_runner = FactoryGirl.create :ci_runner
- @specific_runner2 = FactoryGirl.create :ci_runner
- @specific_runner3 = FactoryGirl.create :ci_runner
- @project.runners << @specific_runner
- @project2.runners << @specific_runner2
- @project3.runners << @specific_runner3
+ background do
+ project.runners << specific_runner
+ end
- visit runners_path(@project)
- end
+ scenario 'user sees the specific runner' do
+ visit runners_path(project)
- before do
- expect(page).not_to have_content(@specific_runner3.display_name)
- expect(page).not_to have_content(@specific_runner3.display_name)
- end
+ within '.activated-specific-runners' do
+ expect(page).to have_content(specific_runner.display_name)
+ end
- it "places runners in right places" do
- expect(page.find(".available-specific-runners")).to have_content(@specific_runner2.display_name)
- expect(page.find(".activated-specific-runners")).to have_content(@specific_runner.display_name)
- expect(page.find(".available-shared-runners")).to have_content(@shared_runner.display_name)
- end
+ click_on specific_runner.short_sha
- it "enables specific runner for project" do
- within ".available-specific-runners" do
- click_on "Enable for this project"
+ expect(page).to have_content(specific_runner.platform)
end
- expect(page.find(".activated-specific-runners")).to have_content(@specific_runner2.display_name)
- end
+ scenario 'user removes an activated specific runner if this is last project for that runners' do
+ visit runners_path(project)
- it "disables specific runner for project" do
- @project2.runners << @specific_runner
- visit runners_path(@project)
+ within '.activated-specific-runners' do
+ click_on 'Remove Runner'
+ end
- within ".activated-specific-runners" do
- click_on "Disable for this project"
+ expect(page).not_to have_content(specific_runner.display_name)
end
- expect(page.find(".available-specific-runners")).to have_content(@specific_runner.display_name)
- end
+ context 'when a runner has a tag' do
+ background do
+ specific_runner.update(tag_list: ['tag'])
+ end
- it "removes specific runner for project if this is last project for that runners" do
- within ".activated-specific-runners" do
- click_on "Remove Runner"
- end
+ scenario 'user edits runner not to run untagged jobs' do
+ visit runners_path(project)
- expect(Ci::Runner.exists?(id: @specific_runner)).to be_falsey
- end
- end
+ within '.activated-specific-runners' do
+ first('.edit-runner > a').click
+ end
- describe "shared runners" do
- before do
- @project = FactoryGirl.create :project, shared_runners_enabled: false
- @project.team << [user, :master]
- visit runners_path(@project)
- end
+ expect(page.find_field('runner[run_untagged]')).to be_checked
- it "enables shared runners" do
- click_on "Enable shared Runners"
- expect(@project.reload.shared_runners_enabled).to be_truthy
- end
- end
+ uncheck 'runner_run_untagged'
+ click_button 'Save changes'
- describe "shared runners description" do
- let(:shared_runners_text) { 'custom **shared** runners description' }
- let(:shared_runners_html) { 'custom shared runners description' }
+ expect(page).to have_content 'Can run untagged jobs No'
+ end
+ end
- before do
- stub_application_setting(shared_runners_text: shared_runners_text)
- project = FactoryGirl.create :project, shared_runners_enabled: false
- project.team << [user, :master]
- visit runners_path(project)
- end
+ context 'when a shared runner is activated on the project' do
+ given!(:shared_runner) { create(:ci_runner, :shared) }
- it "sees shared runners description" do
- expect(page.find(".shared-runners-description")).to have_content(shared_runners_html)
- end
- end
+ scenario 'user sees CI/CD setting page' do
+ visit runners_path(project)
- describe "show page" do
- before do
- @project = FactoryGirl.create :project
- @project.team << [user, :master]
- @specific_runner = FactoryGirl.create :ci_runner
- @project.runners << @specific_runner
+ expect(page.find('.available-shared-runners')).to have_content(shared_runner.display_name)
+ end
+ end
end
- it "shows runner information" do
- visit runners_path(@project)
- click_on @specific_runner.short_sha
- expect(page).to have_content(@specific_runner.platform)
- end
- end
+ context 'when a specific runner exists in another project' do
+ given(:another_project) { create(:project) }
+ given(:specific_runner) { create(:ci_runner, :specific) }
- feature 'configuring runners ability to picking untagged jobs' do
- given(:project) { create(:project) }
- given(:runner) { create(:ci_runner) }
+ background do
+ another_project.add_master(user)
+ another_project.runners << specific_runner
+ end
- background do
- project.team << [user, :master]
- project.runners << runner
- end
+ scenario 'user enables and disables a specific runner' do
+ visit runners_path(project)
+
+ within '.available-specific-runners' do
+ click_on 'Enable for this project'
+ end
- scenario 'user checks default configuration' do
- visit project_runner_path(project, runner)
+ expect(page.find('.activated-specific-runners')).to have_content(specific_runner.display_name)
- expect(page).to have_content 'Can run untagged jobs Yes'
+ within '.activated-specific-runners' do
+ click_on 'Disable for this project'
+ end
+
+ expect(page.find('.available-specific-runners')).to have_content(specific_runner.display_name)
+ end
end
- context 'when runner has tags' do
- before do
- runner.update_attribute(:tag_list, ['tag'])
+ context 'when application settings have shared_runners_text' do
+ given(:shared_runners_text) { 'custom **shared** runners description' }
+ given(:shared_runners_html) { 'custom shared runners description' }
+
+ background do
+ stub_application_setting(shared_runners_text: shared_runners_text)
end
- scenario 'user wants to prevent runner from running untagged job' do
+ scenario 'user sees shared runners description' do
visit runners_path(project)
- page.within('.activated-specific-runners') do
- first('small > a').click
- end
- uncheck 'runner_run_untagged'
- click_button 'Save changes'
-
- expect(page).to have_content 'Can run untagged jobs No'
- expect(runner.reload.run_untagged?).to eq false
+ expect(page.find('.shared-runners-description')).to have_content(shared_runners_html)
end
end
end
+
+ context 'when a project has disabled shared_runners' do
+ given(:project) { create(:project, shared_runners_enabled: false) }
+
+ background do
+ project.add_master(user)
+ end
+
+ scenario 'user enables shared runners' do
+ visit runners_path(project)
+
+ click_on 'Enable shared Runners'
+
+ expect(page.find('.shared-runners-description')).to have_content('Disable shared Runners')
+ end
+ end
end
diff --git a/spec/finders/admin/projects_finder_spec.rb b/spec/finders/admin/projects_finder_spec.rb
index 28e36330029..4b67203a0df 100644
--- a/spec/finders/admin/projects_finder_spec.rb
+++ b/spec/finders/admin/projects_finder_spec.rb
@@ -118,6 +118,12 @@ describe Admin::ProjectsFinder do
it { is_expected.to match_array([archived_project, shared_project, public_project, internal_project, private_project]) }
end
+
+ context 'archived=only' do
+ let(:params) { { archived: 'only' } }
+
+ it { is_expected.to eq([archived_project]) }
+ end
end
context 'filter by personal' do
diff --git a/spec/finders/projects_finder_spec.rb b/spec/finders/projects_finder_spec.rb
index a5de586e869..0dfe6ba9c32 100644
--- a/spec/finders/projects_finder_spec.rb
+++ b/spec/finders/projects_finder_spec.rb
@@ -123,6 +123,12 @@ describe ProjectsFinder do
it { is_expected.to match_array([public_project, internal_project, archived_project]) }
end
+ describe 'filter by archived only' do
+ let(:params) { { archived: 'only' } }
+
+ it { is_expected.to eq([archived_project]) }
+ end
+
describe 'filter by archived for backward compatibility' do
let(:params) { { archived: false } }
diff --git a/spec/fixtures/emails/ios_default.eml b/spec/fixtures/emails/ios_default.eml
index 8d4d58feb16..fa19475104a 100644
--- a/spec/fixtures/emails/ios_default.eml
+++ b/spec/fixtures/emails/ios_default.eml
@@ -76,7 +76,7 @@ Content-Transfer-Encoding: 7bit
<img src="https://meta-discourse.global.ssl.fastly.net/user_avatar/meta.discourse.org/techapj/45/3281.png" title="techAPJ" style="max-width:100%;" width="45" height="45">
</td>
<td>
- <a href="https://meta.discourse.org/users/techapj" target="_blank" style="text-decoration: none; font-weight: bold; color: #006699;; font-size:13px;font-family:'lucida grande',tahoma,verdana,arial,sans-serif;color:#3b5998;text-decoration:none;font-weight:bold">techAPJ</a><br>
+ <a href="https://meta.discourse.org/users/techapj" target="_blank" style="text-decoration: none; font-weight: 600; color: #006699;; font-size:13px;font-family:'lucida grande',tahoma,verdana,arial,sans-serif;color:#3b5998;text-decoration:none;font-weight:bold">techAPJ</a><br>
<span style="text-align:right;color:#999999;padding-right:5px;font-family:'lucida grande',tahoma,verdana,arial,sans-serif;font-size:11px">November 28</span>
</td>
</tr>
@@ -94,7 +94,7 @@ Content-Transfer-Encoding: 7bit
<div style="color:#666;">
- <p>To respond, reply to this email or visit <a href="https://meta.discourse.org/t/testing-default-email-replies/22638/3" style="text-decoration: none; font-weight: bold; color: #006699;; color:#666;">https://meta.discourse.org/t/testing-default-email-replies/22638/3</a> in your browser.</p>
+ <p>To respond, reply to this email or visit <a href="https://meta.discourse.org/t/testing-default-email-replies/22638/3" style="text-decoration: none; font-weight: 600; color: #006699;; color:#666;">https://meta.discourse.org/t/testing-default-email-replies/22638/3</a> in your browser.</p>
</div>
<hr style="background-color: #ddd; height: 1px; border: 1px;; background-color: #ddd; height: 1px; border: 1px;">
<h4>Previous Replies</h4>
@@ -106,7 +106,7 @@ Content-Transfer-Encoding: 7bit
<img src="https://meta-discourse.global.ssl.fastly.net/user_avatar/meta.discourse.org/codinghorror/45/5297.png" title="codinghorror" style="max-width:100%;" width="45" height="45">
</td>
<td>
- <a href="https://meta.discourse.org/users/codinghorror" target="_blank" style="text-decoration: none; font-weight: bold; color: #006699;; font-size:13px;font-family:'lucida grande',tahoma,verdana,arial,sans-serif;color:#3b5998;text-decoration:none;font-weight:bold">codinghorror</a><br>
+ <a href="https://meta.discourse.org/users/codinghorror" target="_blank" style="text-decoration: none; font-weight: 600; color: #006699;; font-size:13px;font-family:'lucida grande',tahoma,verdana,arial,sans-serif;color:#3b5998;text-decoration:none;font-weight:bold">codinghorror</a><br>
<span style="text-align:right;color:#999999;padding-right:5px;font-family:'lucida grande',tahoma,verdana,arial,sans-serif;font-size:11px">November 28</span>
</td>
</tr>
@@ -114,7 +114,7 @@ Content-Transfer-Encoding: 7bit
<td style="padding-top:5px;" colspan="2">
<p style="margin-top:0; border: 0;">We're testing the latest GitHub email processing library which we are integrating now.</p>
-<p style="margin-top:0; border: 0;"><a href="https://github.com/github/email_reply_parser" target="_blank" style="text-decoration: none; font-weight: bold; color: #006699;">https://github.com/github/email_reply_parser</a></p>
+<p style="margin-top:0; border: 0;"><a href="https://github.com/github/email_reply_parser" target="_blank" style="text-decoration: none; font-weight: 600; color: #006699;">https://github.com/github/email_reply_parser</a></p>
<p style="margin-top:0; border: 0;">Go ahead and reply to this topic and I'll reply from various email clients for testing.</p>
</td>
@@ -126,10 +126,10 @@ Content-Transfer-Encoding: 7bit
<hr style="background-color: #ddd; height: 1px; border: 1px;; background-color: #ddd; height: 1px; border: 1px;">
<div style="color:#666;">
-<p>To respond, reply to this email or visit <a href="https://meta.discourse.org/t/testing-default-email-replies/22638/3" style="text-decoration: none; font-weight: bold; color: #006699;; color:#666;">https://meta.discourse.org/t/testing-default-email-replies/22638/3</a> in your browser.</p>
+<p>To respond, reply to this email or visit <a href="https://meta.discourse.org/t/testing-default-email-replies/22638/3" style="text-decoration: none; font-weight: 600; color: #006699;; color:#666;">https://meta.discourse.org/t/testing-default-email-replies/22638/3</a> in your browser.</p>
</div>
<div style="color:#666;">
-<p>To unsubscribe from these emails, visit your <a href="https://meta.discourse.org/my/preferences" style="text-decoration: none; font-weight: bold; color: #006699;; color:#666;">user preferences</a>.</p>
+<p>To unsubscribe from these emails, visit your <a href="https://meta.discourse.org/my/preferences" style="text-decoration: none; font-weight: 600; color: #006699;; color:#666;">user preferences</a>.</p>
</div>
</div>
</div></blockquote></body></html>
diff --git a/spec/fixtures/emails/on_wrote.eml b/spec/fixtures/emails/on_wrote.eml
index feb59bd27bb..af6a4e50a49 100644
--- a/spec/fixtures/emails/on_wrote.eml
+++ b/spec/fixtures/emails/on_wrote.eml
@@ -53,7 +53,7 @@ y
> display: inline-block;
> font-family: FontAwesome;
> font-style: normal;
-> font-weight: normal;
+> font-weight: 400;
> line-height: 1;
> -webkit-font-smoothing: antialiased;
> -moz-osx-font-smoothing: grayscale;
@@ -227,7 +227,7 @@ ding:5px">.fa {
display: inline-block;
font-family: FontAwesome;
font-style: normal;
- font-weight: normal;
+ font-weight: 400;
line-height: 1;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
@@ -274,4 +274,4 @@ ight:bold;color:#006699" target=3D"_blank">user preferences</a>.</p>
</div>
</blockquote></div><br></div></div>
---001a11c34c389e728f0502aa26a0-- \ No newline at end of file
+--001a11c34c389e728f0502aa26a0--
diff --git a/spec/helpers/avatars_helper_spec.rb b/spec/helpers/avatars_helper_spec.rb
index d16fcf21e45..4632c679972 100644
--- a/spec/helpers/avatars_helper_spec.rb
+++ b/spec/helpers/avatars_helper_spec.rb
@@ -28,7 +28,7 @@ describe AvatarsHelper do
it 'displays user avatar' do
is_expected.to eq image_tag(
LazyImageTagHelper.placeholder_image,
- class: 'avatar has-tooltip s16 lazy',
+ class: 'avatar s16 has-tooltip lazy',
alt: "#{user.name}'s avatar",
title: user.name,
data: { container: 'body', src: avatar_icon(user, 16) }
@@ -41,7 +41,7 @@ describe AvatarsHelper do
it 'uses provided css_class' do
is_expected.to eq image_tag(
LazyImageTagHelper.placeholder_image,
- class: "avatar has-tooltip s16 #{options[:css_class]} lazy",
+ class: "avatar s16 #{options[:css_class]} has-tooltip lazy",
alt: "#{user.name}'s avatar",
title: user.name,
data: { container: 'body', src: avatar_icon(user, 16) }
@@ -55,7 +55,7 @@ describe AvatarsHelper do
it 'uses provided size' do
is_expected.to eq image_tag(
LazyImageTagHelper.placeholder_image,
- class: "avatar has-tooltip s#{options[:size]} lazy",
+ class: "avatar s#{options[:size]} has-tooltip lazy",
alt: "#{user.name}'s avatar",
title: user.name,
data: { container: 'body', src: avatar_icon(user, options[:size]) }
@@ -69,7 +69,7 @@ describe AvatarsHelper do
it 'uses provided url' do
is_expected.to eq image_tag(
LazyImageTagHelper.placeholder_image,
- class: 'avatar has-tooltip s16 lazy',
+ class: 'avatar s16 has-tooltip lazy',
alt: "#{user.name}'s avatar",
title: user.name,
data: { container: 'body', src: options[:url] }
@@ -77,6 +77,36 @@ describe AvatarsHelper do
end
end
+ context 'with has_tooltip parameter' do
+ context 'with has_tooltip set to true' do
+ let(:options) { { user: user, has_tooltip: true } }
+
+ it 'adds has-tooltip' do
+ is_expected.to eq image_tag(
+ LazyImageTagHelper.placeholder_image,
+ class: 'avatar s16 has-tooltip lazy',
+ alt: "#{user.name}'s avatar",
+ title: user.name,
+ data: { container: 'body', src: avatar_icon(user, 16) }
+ )
+ end
+ end
+
+ context 'with has_tooltip set to false' do
+ let(:options) { { user: user, has_tooltip: false } }
+
+ it 'does not add has-tooltip or data container' do
+ is_expected.to eq image_tag(
+ LazyImageTagHelper.placeholder_image,
+ class: 'avatar s16 lazy',
+ alt: "#{user.name}'s avatar",
+ title: user.name,
+ data: { src: avatar_icon(user, 16) }
+ )
+ end
+ end
+ end
+
context 'with user_name parameter' do
let(:options) { { user_name: 'Tinky Winky', user_email: 'no@f.un' } }
@@ -86,7 +116,7 @@ describe AvatarsHelper do
it 'prefers user parameter' do
is_expected.to eq image_tag(
LazyImageTagHelper.placeholder_image,
- class: 'avatar has-tooltip s16 lazy',
+ class: 'avatar s16 has-tooltip lazy',
alt: "#{user.name}'s avatar",
title: user.name,
data: { container: 'body', src: avatar_icon(user, 16) }
@@ -97,7 +127,7 @@ describe AvatarsHelper do
it 'uses user_name and user_email parameter if user is not present' do
is_expected.to eq image_tag(
LazyImageTagHelper.placeholder_image,
- class: 'avatar has-tooltip s16 lazy',
+ class: 'avatar s16 has-tooltip lazy',
alt: "#{options[:user_name]}'s avatar",
title: options[:user_name],
data: { container: 'body', src: avatar_icon(options[:user_email], 16) }
diff --git a/spec/helpers/events_helper_spec.rb b/spec/helpers/events_helper_spec.rb
index 4b72dbb7964..d5536fcb22b 100644
--- a/spec/helpers/events_helper_spec.rb
+++ b/spec/helpers/events_helper_spec.rb
@@ -106,5 +106,9 @@ describe EventsHelper do
it "handles empty strings" do
expect(helper.event_commit_title("")).to eq("")
end
+
+ it 'handles nil values' do
+ expect(helper.event_commit_title(nil)).to eq('')
+ end
end
end
diff --git a/spec/javascripts/repo/components/repo_commit_section_spec.js b/spec/javascripts/repo/components/repo_commit_section_spec.js
index 249a2f36fcd..e604dcc152d 100644
--- a/spec/javascripts/repo/components/repo_commit_section_spec.js
+++ b/spec/javascripts/repo/components/repo_commit_section_spec.js
@@ -1,7 +1,7 @@
import Vue from 'vue';
import repoCommitSection from '~/repo/components/repo_commit_section.vue';
import RepoStore from '~/repo/stores/repo_store';
-import Api from '~/api';
+import RepoService from '~/repo/services/repo_service';
describe('RepoCommitSection', () => {
const branch = 'master';
@@ -111,7 +111,7 @@ describe('RepoCommitSection', () => {
expect(submitCommit.disabled).toBeFalsy();
spyOn(vm, 'makeCommit').and.callThrough();
- spyOn(Api, 'commitMultiple');
+ spyOn(RepoService, 'commitFiles').and.callFake(() => Promise.resolve());
submitCommit.click();
@@ -119,10 +119,9 @@ describe('RepoCommitSection', () => {
expect(vm.makeCommit).toHaveBeenCalled();
expect(submitCommit.querySelector('.fa-spinner.fa-spin')).toBeTruthy();
- const args = Api.commitMultiple.calls.allArgs()[0];
- const { commit_message, actions, branch: payloadBranch } = args[1];
+ const args = RepoService.commitFiles.calls.allArgs()[0];
+ const { commit_message, actions, branch: payloadBranch } = args[0];
- expect(args[0]).toBe(projectId);
expect(commit_message).toBe(commitMessage);
expect(actions.length).toEqual(2);
expect(payloadBranch).toEqual(branch);
diff --git a/spec/javascripts/repo/services/repo_service_spec.js b/spec/javascripts/repo/services/repo_service_spec.js
index d74e6a67b1e..6f530770525 100644
--- a/spec/javascripts/repo/services/repo_service_spec.js
+++ b/spec/javascripts/repo/services/repo_service_spec.js
@@ -1,5 +1,7 @@
import axios from 'axios';
import RepoService from '~/repo/services/repo_service';
+import RepoStore from '~/repo/stores/repo_store';
+import Api from '~/api';
describe('RepoService', () => {
it('has default json format param', () => {
@@ -118,4 +120,52 @@ describe('RepoService', () => {
}).catch(done.fail);
});
});
+
+ describe('commitFiles', () => {
+ it('calls commitMultiple and .then commitFlash', (done) => {
+ const projectId = 'projectId';
+ const payload = {};
+ RepoStore.projectId = projectId;
+
+ spyOn(Api, 'commitMultiple').and.returnValue(Promise.resolve());
+ spyOn(RepoService, 'commitFlash');
+
+ const apiPromise = RepoService.commitFiles(payload);
+
+ expect(Api.commitMultiple).toHaveBeenCalledWith(projectId, payload);
+
+ apiPromise.then(() => {
+ expect(RepoService.commitFlash).toHaveBeenCalled();
+ done();
+ }).catch(done.fail);
+ });
+ });
+
+ describe('commitFlash', () => {
+ it('calls Flash with data.message', () => {
+ const data = {
+ message: 'message',
+ };
+ spyOn(window, 'Flash');
+
+ RepoService.commitFlash(data);
+
+ expect(window.Flash).toHaveBeenCalledWith(data.message);
+ });
+
+ it('calls Flash with success string if short_id and stats', () => {
+ const data = {
+ short_id: 'short_id',
+ stats: {
+ additions: '4',
+ deletions: '5',
+ },
+ };
+ spyOn(window, 'Flash');
+
+ RepoService.commitFlash(data);
+
+ expect(window.Flash).toHaveBeenCalledWith(`Your changes have been committed. Commit ${data.short_id} with ${data.stats.additions} additions, ${data.stats.deletions} deletions.`, 'notice');
+ });
+ });
});
diff --git a/spec/lib/gitlab/bare_repository_importer_spec.rb b/spec/lib/gitlab/bare_repository_importer_spec.rb
new file mode 100644
index 00000000000..892f2dafc96
--- /dev/null
+++ b/spec/lib/gitlab/bare_repository_importer_spec.rb
@@ -0,0 +1,68 @@
+require 'spec_helper'
+
+describe Gitlab::BareRepositoryImporter, repository: true do
+ subject(:importer) { described_class.new('default', project_path) }
+ let(:project_path) { 'a-group/a-sub-group/a-project' }
+ let!(:admin) { create(:admin) }
+
+ before do
+ allow(described_class).to receive(:log)
+ end
+
+ describe '.execute' do
+ it 'creates a project for a repository in storage' do
+ FileUtils.mkdir_p(File.join(TestEnv.repos_path, "#{project_path}.git"))
+ fake_importer = double
+
+ expect(described_class).to receive(:new).with('default', project_path)
+ .and_return(fake_importer)
+ expect(fake_importer).to receive(:create_project_if_needed)
+
+ described_class.execute
+ end
+
+ it 'skips wiki repos' do
+ FileUtils.mkdir_p(File.join(TestEnv.repos_path, 'the-group', 'the-project.wiki.git'))
+
+ expect(described_class).to receive(:log).with(' * Skipping wiki repo')
+ expect(described_class).not_to receive(:new)
+
+ described_class.execute
+ end
+ end
+
+ describe '#initialize' do
+ context 'without admin users' do
+ let(:admin) { nil }
+
+ it 'raises an error' do
+ expect { importer }.to raise_error(Gitlab::BareRepositoryImporter::NoAdminError)
+ end
+ end
+ end
+
+ describe '#create_project_if_needed' do
+ it 'starts an import for a project that did not exist' do
+ expect(importer).to receive(:create_project)
+
+ importer.create_project_if_needed
+ end
+
+ it 'skips importing when the project already exists' do
+ group = create(:group, path: 'a-group')
+ subgroup = create(:group, path: 'a-sub-group', parent: group)
+ project = create(:project, path: 'a-project', namespace: subgroup)
+
+ expect(importer).not_to receive(:create_project)
+ expect(importer).to receive(:log).with(" * #{project.name} (a-group/a-sub-group/a-project) exists")
+
+ importer.create_project_if_needed
+ end
+
+ it 'creates a project with the correct path in the database' do
+ importer.create_project_if_needed
+
+ expect(Project.find_by_full_path(project_path)).not_to be_nil
+ end
+ end
+end
diff --git a/spec/lib/gitlab/diff/file_spec.rb b/spec/lib/gitlab/diff/file_spec.rb
index d3d841b0668..c91895cedc3 100644
--- a/spec/lib/gitlab/diff/file_spec.rb
+++ b/spec/lib/gitlab/diff/file_spec.rb
@@ -15,6 +15,17 @@ describe Gitlab::Diff::File do
it { expect(diff_lines.first).to be_kind_of(Gitlab::Diff::Line) }
end
+ describe '#highlighted_diff_lines' do
+ it 'highlights the diff and memoises the result' do
+ expect(Gitlab::Diff::Highlight).to receive(:new)
+ .with(diff_file, repository: project.repository)
+ .once
+ .and_call_original
+
+ diff_file.highlighted_diff_lines
+ end
+ end
+
describe '#mode_changed?' do
it { expect(diff_file.mode_changed?).to be_falsey }
end
@@ -122,8 +133,20 @@ describe Gitlab::Diff::File do
let(:commit) { project.commit('2f63565e7aac07bcdadb654e253078b727143ec4') }
let(:diff_file) { commit.diffs.diff_file_with_new_path('files/images/6049019_460s.jpg') }
- it 'returns true' do
- expect(diff_file.content_changed?).to be_truthy
+ context 'when the blobs are different' do
+ it 'returns true' do
+ expect(diff_file.content_changed?).to be_truthy
+ end
+ end
+
+ context 'when there are no diff refs' do
+ before do
+ allow(diff_file).to receive(:diff_refs).and_return(nil)
+ end
+
+ it 'returns false' do
+ expect(diff_file.content_changed?).to be_falsey
+ end
end
end
@@ -131,8 +154,20 @@ describe Gitlab::Diff::File do
let(:commit) { project.commit('570e7b2abdd848b95f2f578043fc23bd6f6fd24d') }
let(:diff_file) { commit.diffs.diff_file_with_new_path('files/ruby/popen.rb') }
- it 'returns true' do
- expect(diff_file.content_changed?).to be_truthy
+ context 'when the blobs are different' do
+ it 'returns true' do
+ expect(diff_file.content_changed?).to be_truthy
+ end
+ end
+
+ context 'when there are no diff refs' do
+ before do
+ allow(diff_file).to receive(:diff_refs).and_return(nil)
+ end
+
+ it 'returns true' do
+ expect(diff_file.content_changed?).to be_truthy
+ end
end
end
end
@@ -270,6 +305,21 @@ describe Gitlab::Diff::File do
expect(diff_file.simple_viewer).to be_a(DiffViewer::ModeChanged)
end
end
+
+ context 'when no other conditions apply' do
+ before do
+ allow(diff_file).to receive(:content_changed?).and_return(false)
+ allow(diff_file).to receive(:new_file?).and_return(false)
+ allow(diff_file).to receive(:deleted_file?).and_return(false)
+ allow(diff_file).to receive(:renamed_file?).and_return(false)
+ allow(diff_file).to receive(:mode_changed?).and_return(false)
+ allow(diff_file).to receive(:raw_text?).and_return(false)
+ end
+
+ it 'returns a No Preview viewer' do
+ expect(diff_file.simple_viewer).to be_a(DiffViewer::NoPreview)
+ end
+ end
end
describe '#rich_viewer' do
diff --git a/spec/lib/gitlab/git/repository_spec.rb b/spec/lib/gitlab/git/repository_spec.rb
index 06fcdd7aa57..b84f54c87fc 100644
--- a/spec/lib/gitlab/git/repository_spec.rb
+++ b/spec/lib/gitlab/git/repository_spec.rb
@@ -977,6 +977,36 @@ describe Gitlab::Git::Repository, seed_helper: true do
it 'returns the number of branches' do
expect(repository.branch_count).to eq(10)
end
+
+ context 'with local and remote branches' do
+ let(:repository) do
+ Gitlab::Git::Repository.new('default', File.join(TEST_MUTABLE_REPO_PATH, '.git'))
+ end
+
+ before do
+ create_remote_branch(repository, 'joe', 'remote_branch', 'master')
+ repository.create_branch('local_branch', 'master')
+ end
+
+ after do
+ FileUtils.rm_rf(TEST_MUTABLE_REPO_PATH)
+ ensure_seeds
+ end
+
+ it 'returns the count of local branches' do
+ expect(repository.branch_count).to eq(repository.local_branches.count)
+ end
+
+ context 'with Gitaly disabled' do
+ before do
+ allow(Gitlab::GitalyClient).to receive(:feature_enabled?).and_return(false)
+ end
+
+ it 'returns the count of local branches' do
+ expect(repository.branch_count).to eq(repository.local_branches.count)
+ end
+ end
+ end
end
describe "#ls_files" do
@@ -1080,6 +1110,34 @@ describe Gitlab::Git::Repository, seed_helper: true do
end
end
+ describe '#ref_exists?' do
+ shared_examples 'checks the existence of refs' do
+ it 'returns true for an existing tag' do
+ expect(repository.ref_exists?('refs/heads/master')).to eq(true)
+ end
+
+ it 'returns false for a non-existing tag' do
+ expect(repository.ref_exists?('refs/tags/THIS_TAG_DOES_NOT_EXIST')).to eq(false)
+ end
+
+ it 'raises an ArgumentError for an empty string' do
+ expect { repository.ref_exists?('') }.to raise_error(ArgumentError)
+ end
+
+ it 'raises an ArgumentError for an invalid ref' do
+ expect { repository.ref_exists?('INVALID') }.to raise_error(ArgumentError)
+ end
+ end
+
+ context 'when Gitaly ref_exists feature is enabled' do
+ it_behaves_like 'checks the existence of refs'
+ end
+
+ context 'when Gitaly ref_exists feature is disabled', skip_gitaly_mock: true do
+ it_behaves_like 'checks the existence of refs'
+ end
+ end
+
describe '#tag_exists?' do
shared_examples 'checks the existence of tags' do
it 'returns true for an existing tag' do
diff --git a/spec/lib/gitlab/git/storage/forked_storage_check_spec.rb b/spec/lib/gitlab/git/storage/forked_storage_check_spec.rb
index 12366151f44..c708b15853a 100644
--- a/spec/lib/gitlab/git/storage/forked_storage_check_spec.rb
+++ b/spec/lib/gitlab/git/storage/forked_storage_check_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Gitlab::Git::Storage::ForkedStorageCheck, skip_database_cleaner: true do
+describe Gitlab::Git::Storage::ForkedStorageCheck, broken_storage: true, skip_database_cleaner: true do
let(:existing_path) do
existing_path = TestEnv.repos_path
FileUtils.mkdir_p(existing_path)
diff --git a/spec/lib/gitlab/gitaly_client/commit_service_spec.rb b/spec/lib/gitlab/gitaly_client/commit_service_spec.rb
index 2eaf4222964..f32fe5d8150 100644
--- a/spec/lib/gitlab/gitaly_client/commit_service_spec.rb
+++ b/spec/lib/gitlab/gitaly_client/commit_service_spec.rb
@@ -140,4 +140,29 @@ describe Gitlab::GitalyClient::CommitService do
described_class.new(repository).find_commit(revision)
end
end
+
+ describe '#patch' do
+ let(:request) do
+ Gitaly::CommitPatchRequest.new(
+ repository: repository_message, revision: revision
+ )
+ end
+ let(:response) { [double(data: "my "), double(data: "diff")] }
+
+ subject { described_class.new(repository).patch(revision) }
+
+ it 'sends an RPC request' do
+ expect_any_instance_of(Gitaly::DiffService::Stub).to receive(:commit_patch)
+ .with(request, kind_of(Hash)).and_return([])
+
+ subject
+ end
+
+ it 'concatenates the responses data' do
+ allow_any_instance_of(Gitaly::DiffService::Stub).to receive(:commit_patch)
+ .with(request, kind_of(Hash)).and_return(response)
+
+ expect(subject).to eq("my diff")
+ end
+ end
end
diff --git a/spec/lib/gitlab/ldap/adapter_spec.rb b/spec/lib/gitlab/ldap/adapter_spec.rb
index d17d440d833..d9ddb4326be 100644
--- a/spec/lib/gitlab/ldap/adapter_spec.rb
+++ b/spec/lib/gitlab/ldap/adapter_spec.rb
@@ -16,7 +16,7 @@ describe Gitlab::LDAP::Adapter do
expect(adapter).to receive(:ldap_search) do |arg|
expect(arg[:filter].to_s).to eq('(uid=johndoe)')
expect(arg[:base]).to eq('dc=example,dc=com')
- expect(arg[:attributes]).to match(%w{uid cn dn uid userid sAMAccountName mail email userPrincipalName})
+ expect(arg[:attributes]).to match(%w{dn uid cn mail email userPrincipalName})
end.and_return({})
adapter.users('uid', 'johndoe')
@@ -26,7 +26,7 @@ describe Gitlab::LDAP::Adapter do
expect(adapter).to receive(:ldap_search).with(
base: 'uid=johndoe,ou=users,dc=example,dc=com',
scope: Net::LDAP::SearchScope_BaseObject,
- attributes: %w{uid cn dn uid userid sAMAccountName mail email userPrincipalName},
+ attributes: %w{dn uid cn mail email userPrincipalName},
filter: nil
).and_return({})
@@ -63,7 +63,7 @@ describe Gitlab::LDAP::Adapter do
it 'uses the right uid attribute when non-default' do
stub_ldap_config(uid: 'sAMAccountName')
expect(adapter).to receive(:ldap_search).with(
- hash_including(attributes: %w{sAMAccountName cn dn uid userid sAMAccountName mail email userPrincipalName})
+ hash_including(attributes: %w{dn sAMAccountName cn mail email userPrincipalName})
).and_return({})
adapter.users('sAMAccountName', 'johndoe')
diff --git a/spec/migrations/cleanup_nonexisting_namespace_pending_delete_projects_spec.rb b/spec/migrations/cleanup_nonexisting_namespace_pending_delete_projects_spec.rb
new file mode 100644
index 00000000000..7879105a334
--- /dev/null
+++ b/spec/migrations/cleanup_nonexisting_namespace_pending_delete_projects_spec.rb
@@ -0,0 +1,32 @@
+require 'spec_helper'
+require Rails.root.join('db', 'post_migrate', '20170816102555_cleanup_nonexisting_namespace_pending_delete_projects.rb')
+
+describe CleanupNonexistingNamespacePendingDeleteProjects do
+ before do
+ # Stub after_save callbacks that will fail when Project has invalid namespace
+ allow_any_instance_of(Project).to receive(:ensure_storage_path_exist).and_return(nil)
+ allow_any_instance_of(Project).to receive(:update_project_statistics).and_return(nil)
+ end
+
+ describe '#up' do
+ set(:some_project) { create(:project) }
+
+ it 'only cleans up when namespace does not exist' do
+ create(:project, pending_delete: true)
+ project = build(:project, pending_delete: true, namespace: nil, namespace_id: Namespace.maximum(:id).to_i.succ)
+ project.save(validate: false)
+
+ expect(NamespacelessProjectDestroyWorker).to receive(:bulk_perform_async).with([[project.id]])
+
+ described_class.new.up
+ end
+
+ it 'does nothing when no pending delete projects without namespace found' do
+ create(:project, pending_delete: true, namespace: create(:namespace))
+
+ expect(NamespacelessProjectDestroyWorker).not_to receive(:bulk_perform_async)
+
+ described_class.new.up
+ end
+ end
+end
diff --git a/spec/models/ci/build_spec.rb b/spec/models/ci/build_spec.rb
index 767f0ad9e65..4f77f0d85cd 100644
--- a/spec/models/ci/build_spec.rb
+++ b/spec/models/ci/build_spec.rb
@@ -21,6 +21,16 @@ describe Ci::Build do
it { is_expected.to respond_to(:has_trace?) }
it { is_expected.to respond_to(:trace) }
+ describe 'callbacks' do
+ context 'when running after_create callback' do
+ it 'triggers asynchronous build hooks worker' do
+ expect(BuildHooksWorker).to receive(:perform_async)
+
+ create(:ci_build)
+ end
+ end
+ end
+
describe '.manual_actions' do
let!(:manual_but_created) { create(:ci_build, :manual, status: :created, pipeline: pipeline) }
let!(:manual_but_succeeded) { create(:ci_build, :manual, status: :success, pipeline: pipeline) }
diff --git a/spec/models/ci/pipeline_spec.rb b/spec/models/ci/pipeline_spec.rb
index ac75c6501ee..b84e3ff18e8 100644
--- a/spec/models/ci/pipeline_spec.rb
+++ b/spec/models/ci/pipeline_spec.rb
@@ -2,7 +2,7 @@ require 'spec_helper'
describe Ci::Pipeline, :mailer do
let(:user) { create(:user) }
- let(:project) { create(:project) }
+ set(:project) { create(:project) }
let(:pipeline) do
create(:ci_empty_pipeline, status: :created, project: project)
@@ -159,6 +159,18 @@ describe Ci::Pipeline, :mailer do
end
end
+ describe '#predefined_variables' do
+ subject { pipeline.predefined_variables }
+
+ it { is_expected.to be_an(Array) }
+
+ it 'includes the defined keys' do
+ keys = subject.map { |v| v[:key] }
+
+ expect(keys).to include('CI_PIPELINE_ID', 'CI_CONFIG_PATH', 'CI_PIPELINE_SOURCE')
+ end
+ end
+
describe '#auto_canceled?' do
subject { pipeline.auto_canceled? }
diff --git a/spec/models/event_spec.rb b/spec/models/event_spec.rb
index ff3224dd298..f55c161c821 100644
--- a/spec/models/event_spec.rb
+++ b/spec/models/event_spec.rb
@@ -304,6 +304,50 @@ describe Event do
end
end
+ describe '#body?' do
+ let(:push_event) do
+ event = build(:push_event)
+
+ allow(event).to receive(:push?).and_return(true)
+
+ event
+ end
+
+ it 'returns true for a push event with commits' do
+ allow(push_event).to receive(:push_with_commits?).and_return(true)
+
+ expect(push_event).to be_body
+ end
+
+ it 'returns false for a push event without a valid commit range' do
+ allow(push_event).to receive(:push_with_commits?).and_return(false)
+
+ expect(push_event).not_to be_body
+ end
+
+ it 'returns true for a Note event' do
+ event = build(:event)
+
+ allow(event).to receive(:note?).and_return(true)
+
+ expect(event).to be_body
+ end
+
+ it 'returns true if the target responds to #title' do
+ event = build(:event)
+
+ allow(event).to receive(:target).and_return(double(:target, title: 'foo'))
+
+ expect(event).to be_body
+ end
+
+ it 'returns false for a regular event without a target' do
+ event = build(:event)
+
+ expect(event).not_to be_body
+ end
+ end
+
def create_push_event(project, user)
event = create(:push_event, project: project, author: user)
diff --git a/spec/models/issue_spec.rb b/spec/models/issue_spec.rb
index 9203f6562f2..de86788d142 100644
--- a/spec/models/issue_spec.rb
+++ b/spec/models/issue_spec.rb
@@ -751,4 +751,22 @@ describe Issue do
end
end
end
+
+ describe 'removing an issue' do
+ it 'refreshes the number of open issues of the project' do
+ project = subject.project
+
+ expect { subject.destroy }
+ .to change { project.open_issues_count }.from(1).to(0)
+ end
+ end
+
+ describe '.public_only' do
+ it 'only returns public issues' do
+ public_issue = create(:issue)
+ create(:issue, confidential: true)
+
+ expect(described_class.public_only).to eq([public_issue])
+ end
+ end
end
diff --git a/spec/models/merge_request_spec.rb b/spec/models/merge_request_spec.rb
index 026bdbd26d1..2d10c6ef1da 100644
--- a/spec/models/merge_request_spec.rb
+++ b/spec/models/merge_request_spec.rb
@@ -604,7 +604,7 @@ describe MergeRequest do
request = build_stubbed(:merge_request)
expect(request.merge_commit_message)
- .to match("See merge request #{request.to_reference}")
+ .to match("See merge request #{request.to_reference(full: true)}")
end
it 'excludes multiple linebreak runs when description is blank' do
@@ -1692,4 +1692,13 @@ describe MergeRequest do
expect(subject.ref_fetched?).to be_falsey
end
end
+
+ describe 'removing a merge request' do
+ it 'refreshes the number of open merge requests of the target project' do
+ project = subject.target_project
+
+ expect { subject.destroy }
+ .to change { project.open_merge_requests_count }.from(1).to(0)
+ end
+ end
end
diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb
index 9a9e255f874..8e04eea56a7 100644
--- a/spec/models/user_spec.rb
+++ b/spec/models/user_spec.rb
@@ -1356,7 +1356,7 @@ describe User do
end
it "excludes push event if branch has been deleted" do
- allow_any_instance_of(Repository).to receive(:branch_names).and_return(['foo'])
+ allow_any_instance_of(Repository).to receive(:branch_exists?).with('master').and_return(false)
expect(subject.recent_push).to eq(nil)
end
diff --git a/spec/services/groups/nested_create_service_spec.rb b/spec/services/groups/nested_create_service_spec.rb
new file mode 100644
index 00000000000..c1526456bac
--- /dev/null
+++ b/spec/services/groups/nested_create_service_spec.rb
@@ -0,0 +1,53 @@
+require 'spec_helper'
+
+describe Groups::NestedCreateService do
+ let(:user) { create(:user) }
+ let(:params) { { group_path: 'a-group/a-sub-group' } }
+
+ subject(:service) { described_class.new(user, params) }
+
+ describe "#execute" do
+ it 'returns the group if it already existed' do
+ parent = create(:group, path: 'a-group', owner: user)
+ child = create(:group, path: 'a-sub-group', parent: parent, owner: user)
+
+ expect(service.execute).to eq(child)
+ end
+
+ it 'reuses a parent if it already existed' do
+ parent = create(:group, path: 'a-group')
+ parent.add_owner(user)
+
+ expect(service.execute.parent).to eq(parent)
+ end
+
+ it 'creates group and subgroup in the database' do
+ service.execute
+
+ parent = Group.find_by_full_path('a-group')
+ child = parent.children.find_by(path: 'a-sub-group')
+
+ expect(parent).not_to be_nil
+ expect(child).not_to be_nil
+ end
+
+ it 'creates the group with correct visibility level' do
+ allow(Gitlab::CurrentSettings.current_application_settings)
+ .to receive(:default_group_visibility) { Gitlab::VisibilityLevel::INTERNAL }
+
+ group = service.execute
+
+ expect(group.visibility_level).to eq(Gitlab::VisibilityLevel::INTERNAL)
+ end
+
+ context 'adding a visibility level ' do
+ let(:params) { { group_path: 'a-group/a-sub-group', visibility_level: Gitlab::VisibilityLevel::PRIVATE } }
+
+ it 'overwrites the visibility level' do
+ group = service.execute
+
+ expect(group.visibility_level).to eq(Gitlab::VisibilityLevel::PRIVATE)
+ end
+ end
+ end
+end
diff --git a/spec/services/issues/close_service_spec.rb b/spec/services/issues/close_service_spec.rb
index a03f68434de..171f70c32a8 100644
--- a/spec/services/issues/close_service_spec.rb
+++ b/spec/services/issues/close_service_spec.rb
@@ -42,6 +42,11 @@ describe Issues::CloseService do
service.execute(issue)
end
+ it 'refreshes the number of open issues' do
+ expect { service.execute(issue) }
+ .to change { project.open_issues_count }.from(1).to(0)
+ end
+
it 'invalidates counter cache for assignees' do
expect_any_instance_of(User).to receive(:invalidate_issue_cache_counts)
diff --git a/spec/services/issues/create_service_spec.rb b/spec/services/issues/create_service_spec.rb
index 9b2d9e79f4f..78b11cd7991 100644
--- a/spec/services/issues/create_service_spec.rb
+++ b/spec/services/issues/create_service_spec.rb
@@ -35,6 +35,10 @@ describe Issues::CreateService do
expect(issue.due_date).to eq Date.tomorrow
end
+ it 'refreshes the number of open issues' do
+ expect { issue }.to change { project.open_issues_count }.from(0).to(1)
+ end
+
context 'when current user cannot admin issues in the project' do
let(:guest) { create(:user) }
diff --git a/spec/services/issues/reopen_service_spec.rb b/spec/services/issues/reopen_service_spec.rb
index 205e9ebd237..48fc98b3b2f 100644
--- a/spec/services/issues/reopen_service_spec.rb
+++ b/spec/services/issues/reopen_service_spec.rb
@@ -34,6 +34,13 @@ describe Issues::ReopenService do
described_class.new(project, user).execute(issue)
end
+ it 'refreshes the number of opened issues' do
+ service = described_class.new(project, user)
+
+ expect { service.execute(issue) }
+ .to change { project.open_issues_count }.from(0).to(1)
+ end
+
context 'when issue is not confidential' do
it 'executes issue hooks' do
expect(project).to receive(:execute_hooks).with(an_instance_of(Hash), :issue_hooks)
diff --git a/spec/services/merge_requests/close_service_spec.rb b/spec/services/merge_requests/close_service_spec.rb
index 04bf267d167..7e65369762c 100644
--- a/spec/services/merge_requests/close_service_spec.rb
+++ b/spec/services/merge_requests/close_service_spec.rb
@@ -52,6 +52,13 @@ describe MergeRequests::CloseService do
end
end
+ it 'refreshes the number of open merge requests for a valid MR' do
+ service = described_class.new(project, user, {})
+
+ expect { service.execute(merge_request) }
+ .to change { project.open_merge_requests_count }.from(1).to(0)
+ end
+
context 'current user is not authorized to close merge request' do
before do
perform_enqueued_jobs do
diff --git a/spec/services/merge_requests/create_service_spec.rb b/spec/services/merge_requests/create_service_spec.rb
index a1f3bec42cc..d6409c0d625 100644
--- a/spec/services/merge_requests/create_service_spec.rb
+++ b/spec/services/merge_requests/create_service_spec.rb
@@ -18,31 +18,35 @@ describe MergeRequests::CreateService do
end
let(:service) { described_class.new(project, user, opts) }
+ let(:merge_request) { service.execute }
before do
project.team << [user, :master]
project.team << [assignee, :developer]
allow(service).to receive(:execute_hooks)
-
- @merge_request = service.execute
end
it 'creates an MR' do
- expect(@merge_request).to be_valid
- expect(@merge_request.title).to eq('Awesome merge_request')
- expect(@merge_request.assignee).to be_nil
- expect(@merge_request.merge_params['force_remove_source_branch']).to eq('1')
+ expect(merge_request).to be_valid
+ expect(merge_request.title).to eq('Awesome merge_request')
+ expect(merge_request.assignee).to be_nil
+ expect(merge_request.merge_params['force_remove_source_branch']).to eq('1')
end
it 'executes hooks with default action' do
- expect(service).to have_received(:execute_hooks).with(@merge_request)
+ expect(service).to have_received(:execute_hooks).with(merge_request)
+ end
+
+ it 'refreshes the number of open merge requests' do
+ expect { service.execute }
+ .to change { project.open_merge_requests_count }.from(0).to(1)
end
it 'does not creates todos' do
attributes = {
project: project,
- target_id: @merge_request.id,
- target_type: @merge_request.class.name
+ target_id: merge_request.id,
+ target_type: merge_request.class.name
}
expect(Todo.where(attributes).count).to be_zero
@@ -51,8 +55,8 @@ describe MergeRequests::CreateService do
it 'creates exactly 1 create MR event' do
attributes = {
action: Event::CREATED,
- target_id: @merge_request.id,
- target_type: @merge_request.class.name
+ target_id: merge_request.id,
+ target_type: merge_request.class.name
}
expect(Event.where(attributes).count).to eq(1)
@@ -69,15 +73,15 @@ describe MergeRequests::CreateService do
}
end
- it { expect(@merge_request.assignee).to eq assignee }
+ it { expect(merge_request.assignee).to eq assignee }
it 'creates a todo for new assignee' do
attributes = {
project: project,
author: user,
user: assignee,
- target_id: @merge_request.id,
- target_type: @merge_request.class.name,
+ target_id: merge_request.id,
+ target_type: merge_request.class.name,
action: Todo::ASSIGNED,
state: :pending
}
diff --git a/spec/services/merge_requests/reopen_service_spec.rb b/spec/services/merge_requests/reopen_service_spec.rb
index f02af0c582e..fa652611c6b 100644
--- a/spec/services/merge_requests/reopen_service_spec.rb
+++ b/spec/services/merge_requests/reopen_service_spec.rb
@@ -47,6 +47,13 @@ describe MergeRequests::ReopenService do
end
end
+ it 'refreshes the number of open merge requests for a valid MR' do
+ service = described_class.new(project, user, {})
+
+ expect { service.execute(merge_request) }
+ .to change { project.open_merge_requests_count }.from(0).to(1)
+ end
+
context 'current user is not authorized to reopen merge request' do
before do
perform_enqueued_jobs do
diff --git a/spec/services/projects/count_service_spec.rb b/spec/services/projects/count_service_spec.rb
new file mode 100644
index 00000000000..79b01e7620e
--- /dev/null
+++ b/spec/services/projects/count_service_spec.rb
@@ -0,0 +1,73 @@
+require 'spec_helper'
+
+describe Projects::CountService do
+ let(:project) { build(:project, id: 1) }
+ let(:service) { described_class.new(project) }
+
+ describe '#relation_for_count' do
+ it 'raises NotImplementedError' do
+ expect { service.relation_for_count }.to raise_error(NotImplementedError)
+ end
+ end
+
+ describe '#count' do
+ before do
+ allow(service).to receive(:cache_key_name).and_return('count_service')
+ end
+
+ it 'returns the number of rows' do
+ allow(service).to receive(:uncached_count).and_return(1)
+
+ expect(service.count).to eq(1)
+ end
+
+ it 'caches the number of rows', :use_clean_rails_memory_store_caching do
+ expect(service).to receive(:uncached_count).once.and_return(1)
+
+ 2.times do
+ expect(service.count).to eq(1)
+ end
+ end
+ end
+
+ describe '#refresh_cache', :use_clean_rails_memory_store_caching do
+ before do
+ allow(service).to receive(:cache_key_name).and_return('count_service')
+ end
+
+ it 'refreshes the cache' do
+ expect(service).to receive(:uncached_count).once.and_return(1)
+
+ service.refresh_cache
+
+ expect(service.count).to eq(1)
+ end
+ end
+
+ describe '#delete_cache', :use_clean_rails_memory_store_caching do
+ before do
+ allow(service).to receive(:cache_key_name).and_return('count_service')
+ end
+
+ it 'removes the cache' do
+ expect(service).to receive(:uncached_count).twice.and_return(1)
+
+ service.count
+ service.delete_cache
+ service.count
+ end
+ end
+
+ describe '#cache_key_name' do
+ it 'raises NotImplementedError' do
+ expect { service.cache_key_name }.to raise_error(NotImplementedError)
+ end
+ end
+
+ describe '#cache_key' do
+ it 'returns the cache key as an Array' do
+ allow(service).to receive(:cache_key_name).and_return('count_service')
+ expect(service.cache_key).to eq(['projects', 1, 'count_service'])
+ end
+ end
+end
diff --git a/spec/services/projects/forks_count_service_spec.rb b/spec/services/projects/forks_count_service_spec.rb
index cf299c5d09b..9f8e7ee18a8 100644
--- a/spec/services/projects/forks_count_service_spec.rb
+++ b/spec/services/projects/forks_count_service_spec.rb
@@ -1,40 +1,14 @@
require 'spec_helper'
describe Projects::ForksCountService do
- let(:project) { build(:project, id: 42) }
- let(:service) { described_class.new(project) }
-
describe '#count' do
it 'returns the number of forks' do
- allow(service).to receive(:uncached_count).and_return(1)
-
- expect(service.count).to eq(1)
- end
-
- it 'caches the forks count', :use_clean_rails_memory_store_caching do
- expect(service).to receive(:uncached_count).once.and_return(1)
+ project = build(:project, id: 42)
+ service = described_class.new(project)
- 2.times { service.count }
- end
- end
-
- describe '#refresh_cache', :use_clean_rails_memory_store_caching do
- it 'refreshes the cache' do
- expect(service).to receive(:uncached_count).once.and_return(1)
-
- service.refresh_cache
+ allow(service).to receive(:uncached_count).and_return(1)
expect(service.count).to eq(1)
end
end
-
- describe '#delete_cache', :use_clean_rails_memory_store_caching do
- it 'removes the cache' do
- expect(service).to receive(:uncached_count).twice.and_return(1)
-
- service.count
- service.delete_cache
- service.count
- end
- end
end
diff --git a/spec/services/projects/open_issues_count_service_spec.rb b/spec/services/projects/open_issues_count_service_spec.rb
new file mode 100644
index 00000000000..f964f9972cd
--- /dev/null
+++ b/spec/services/projects/open_issues_count_service_spec.rb
@@ -0,0 +1,21 @@
+require 'spec_helper'
+
+describe Projects::OpenIssuesCountService do
+ describe '#count' do
+ it 'returns the number of open issues' do
+ project = create(:project)
+ create(:issue, :opened, project: project)
+
+ expect(described_class.new(project).count).to eq(1)
+ end
+
+ it 'does not include confidential issues in the issue count' do
+ project = create(:project)
+
+ create(:issue, :opened, project: project)
+ create(:issue, :opened, confidential: true, project: project)
+
+ expect(described_class.new(project).count).to eq(1)
+ end
+ end
+end
diff --git a/spec/services/projects/open_merge_requests_count_service_spec.rb b/spec/services/projects/open_merge_requests_count_service_spec.rb
new file mode 100644
index 00000000000..9f49b9ec6a2
--- /dev/null
+++ b/spec/services/projects/open_merge_requests_count_service_spec.rb
@@ -0,0 +1,15 @@
+require 'spec_helper'
+
+describe Projects::OpenMergeRequestsCountService do
+ describe '#count' do
+ it 'returns the number of open merge requests' do
+ project = create(:project)
+ create(:merge_request,
+ :opened,
+ source_project: project,
+ target_project: project)
+
+ expect(described_class.new(project).count).to eq(1)
+ end
+ end
+end
diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb
index c10197ff651..ff1754fbe7e 100644
--- a/spec/spec_helper.rb
+++ b/spec/spec_helper.rb
@@ -105,6 +105,18 @@ RSpec.configure do |config|
reset_delivered_emails!
end
+ # Stub the `ForkedStorageCheck.storage_available?` method unless
+ # `:broken_storage` metadata is defined
+ #
+ # This check can be slow and is unnecessary in a test environment where we
+ # know the storage is available, because we create it at runtime
+ config.before(:example) do |example|
+ unless example.metadata[:broken_storage]
+ allow(Gitlab::Git::Storage::ForkedStorageCheck)
+ .to receive(:storage_available?).and_return(true)
+ end
+ end
+
config.around(:each, :use_clean_rails_memory_store_caching) do |example|
caching_store = Rails.cache
Rails.cache = ActiveSupport::Cache::MemoryStore.new
diff --git a/spec/support/cycle_analytics_helpers.rb b/spec/support/cycle_analytics_helpers.rb
index 30911e7fa86..39586d37e93 100644
--- a/spec/support/cycle_analytics_helpers.rb
+++ b/spec/support/cycle_analytics_helpers.rb
@@ -78,6 +78,8 @@ module CycleAnalyticsHelpers
@dummy_pipeline ||=
Ci::Pipeline.new(
sha: project.repository.commit('master').sha,
+ ref: 'master',
+ source: :push,
project: project)
end
diff --git a/spec/support/db_cleaner.rb b/spec/support/db_cleaner.rb
index b0f520d08e8..edaee03ea6c 100644
--- a/spec/support/db_cleaner.rb
+++ b/spec/support/db_cleaner.rb
@@ -4,18 +4,18 @@ RSpec.configure do |config|
end
config.append_after(:context) do
- DatabaseCleaner.clean_with(:truncation)
+ DatabaseCleaner.clean_with(:truncation, cache_tables: false)
end
config.before(:each) do
DatabaseCleaner.strategy = :transaction
end
- config.before(:each, js: true) do
+ config.before(:each, :js) do
DatabaseCleaner.strategy = :truncation
end
- config.before(:each, truncate: true) do
+ config.before(:each, :truncate) do
DatabaseCleaner.strategy = :truncation
end
diff --git a/spec/workers/build_finished_worker_spec.rb b/spec/workers/build_finished_worker_spec.rb
index 2868167c7d4..8cc3f37ebe8 100644
--- a/spec/workers/build_finished_worker_spec.rb
+++ b/spec/workers/build_finished_worker_spec.rb
@@ -3,7 +3,7 @@ require 'spec_helper'
describe BuildFinishedWorker do
describe '#perform' do
context 'when build exists' do
- let(:build) { create(:ci_build) }
+ let!(:build) { create(:ci_build) }
it 'calculates coverage and calls hooks' do
expect(BuildCoverageWorker)
diff --git a/spec/workers/namespaceless_project_destroy_worker_spec.rb b/spec/workers/namespaceless_project_destroy_worker_spec.rb
index 817e103fd9a..20cf580af8a 100644
--- a/spec/workers/namespaceless_project_destroy_worker_spec.rb
+++ b/spec/workers/namespaceless_project_destroy_worker_spec.rb
@@ -75,5 +75,19 @@ describe NamespacelessProjectDestroyWorker do
end
end
end
+
+ context 'project has non-existing namespace' do
+ let!(:project) do
+ project = build(:project, namespace_id: Namespace.maximum(:id).to_i.succ)
+ project.save(validate: false)
+ project
+ end
+
+ it 'deletes the project' do
+ subject.perform(project.id)
+
+ expect(Project.unscoped.all).not_to include(project)
+ end
+ end
end
end
diff --git a/vendor/assets/stylesheets/katex.scss b/vendor/assets/stylesheets/katex.scss
index 9dd8a30bf51..b45836716f2 100644
--- a/vendor/assets/stylesheets/katex.scss
+++ b/vendor/assets/stylesheets/katex.scss
@@ -45,112 +45,112 @@ SOFTWARE.
font-family: 'KaTeX_AMS';
src: url(font-path('KaTeX_AMS-Regular.eot'));
src: url(font-path('KaTeX_AMS-Regular.eot#iefix')) format('embedded-opentype'), url(font-path('KaTeX_AMS-Regular.woff2')) format('woff2'), url(font-path('KaTeX_AMS-Regular.woff')) format('woff'), url(font-path('KaTeX_AMS-Regular.ttf')) format('truetype');
- font-weight: normal;
+ font-weight: 400;
font-style: normal;
}
@font-face {
font-family: 'KaTeX_Caligraphic';
src: url(font-path('KaTeX_Caligraphic-Bold.eot'));
src: url(font-path('KaTeX_Caligraphic-Bold.eot#iefix')) format('embedded-opentype'), url(font-path('KaTeX_Caligraphic-Bold.woff2')) format('woff2'), url(font-path('KaTeX_Caligraphic-Bold.woff')) format('woff'), url(font-path('KaTeX_Caligraphic-Bold.ttf')) format('truetype');
- font-weight: bold;
+ font-weight: 600;
font-style: normal;
}
@font-face {
font-family: 'KaTeX_Caligraphic';
src: url(font-path('KaTeX_Caligraphic-Regular.eot'));
src: url(font-path('KaTeX_Caligraphic-Regular.eot#iefix')) format('embedded-opentype'), url(font-path('KaTeX_Caligraphic-Regular.woff2')) format('woff2'), url(font-path('KaTeX_Caligraphic-Regular.woff')) format('woff'), url(font-path('KaTeX_Caligraphic-Regular.ttf')) format('truetype');
- font-weight: normal;
+ font-weight: 400;
font-style: normal;
}
@font-face {
font-family: 'KaTeX_Fraktur';
src: url(font-path('KaTeX_Fraktur-Bold.eot'));
src: url(font-path('KaTeX_Fraktur-Bold.eot#iefix')) format('embedded-opentype'), url(font-path('KaTeX_Fraktur-Bold.woff2')) format('woff2'), url(font-path('KaTeX_Fraktur-Bold.woff')) format('woff'), url(font-path('KaTeX_Fraktur-Bold.ttf')) format('truetype');
- font-weight: bold;
+ font-weight: 600;
font-style: normal;
}
@font-face {
font-family: 'KaTeX_Fraktur';
src: url(font-path('KaTeX_Fraktur-Regular.eot'));
src: url(font-path('KaTeX_Fraktur-Regular.eot#iefix')) format('embedded-opentype'), url(font-path('KaTeX_Fraktur-Regular.woff2')) format('woff2'), url(font-path('KaTeX_Fraktur-Regular.woff')) format('woff'), url(font-path('KaTeX_Fraktur-Regular.ttf')) format('truetype');
- font-weight: normal;
+ font-weight: 400;
font-style: normal;
}
@font-face {
font-family: 'KaTeX_Main';
src: url(font-path('KaTeX_Main-Bold.eot'));
src: url(font-path('KaTeX_Main-Bold.eot#iefix')) format('embedded-opentype'), url(font-path('KaTeX_Main-Bold.woff2')) format('woff2'), url(font-path('KaTeX_Main-Bold.woff')) format('woff'), url(font-path('KaTeX_Main-Bold.ttf')) format('truetype');
- font-weight: bold;
+ font-weight: 600;
font-style: normal;
}
@font-face {
font-family: 'KaTeX_Main';
src: url(font-path('KaTeX_Main-Italic.eot'));
src: url(font-path('KaTeX_Main-Italic.eot#iefix')) format('embedded-opentype'), url(font-path('KaTeX_Main-Italic.woff2')) format('woff2'), url(font-path('KaTeX_Main-Italic.woff')) format('woff'), url(font-path('KaTeX_Main-Italic.ttf')) format('truetype');
- font-weight: normal;
+ font-weight: 400;
font-style: italic;
}
@font-face {
font-family: 'KaTeX_Main';
src: url(font-path('KaTeX_Main-Regular.eot'));
src: url(font-path('KaTeX_Main-Regular.eot#iefix')) format('embedded-opentype'), url(font-path('KaTeX_Main-Regular.woff2')) format('woff2'), url(font-path('KaTeX_Main-Regular.woff')) format('woff'), url(font-path('KaTeX_Main-Regular.ttf')) format('truetype');
- font-weight: normal;
+ font-weight: 400;
font-style: normal;
}
@font-face {
font-family: 'KaTeX_Math';
src: url(font-path('KaTeX_Math-Italic.eot'));
src: url(font-path('KaTeX_Math-Italic.eot#iefix')) format('embedded-opentype'), url(font-path('KaTeX_Math-Italic.woff2')) format('woff2'), url(font-path('KaTeX_Math-Italic.woff')) format('woff'), url(font-path('KaTeX_Math-Italic.ttf')) format('truetype');
- font-weight: normal;
+ font-weight: 400;
font-style: italic;
}
@font-face {
font-family: 'KaTeX_SansSerif';
src: url(font-path('KaTeX_SansSerif-Regular.eot'));
src: url(font-path('KaTeX_SansSerif-Regular.eot#iefix')) format('embedded-opentype'), url(font-path('KaTeX_SansSerif-Regular.woff2')) format('woff2'), url(font-path('KaTeX_SansSerif-Regular.woff')) format('woff'), url(font-path('KaTeX_SansSerif-Regular.ttf')) format('truetype');
- font-weight: normal;
+ font-weight: 400;
font-style: normal;
}
@font-face {
font-family: 'KaTeX_Script';
src: url(font-path('KaTeX_Script-Regular.eot'));
src: url(font-path('KaTeX_Script-Regular.eot#iefix')) format('embedded-opentype'), url(font-path('KaTeX_Script-Regular.woff2')) format('woff2'), url(font-path('KaTeX_Script-Regular.woff')) format('woff'), url(font-path('KaTeX_Script-Regular.ttf')) format('truetype');
- font-weight: normal;
+ font-weight: 400;
font-style: normal;
}
@font-face {
font-family: 'KaTeX_Size1';
src: url(font-path('KaTeX_Size1-Regular.eot'));
src: url(font-path('KaTeX_Size1-Regular.eot#iefix')) format('embedded-opentype'), url(font-path('KaTeX_Size1-Regular.woff2')) format('woff2'), url(font-path('KaTeX_Size1-Regular.woff')) format('woff'), url(font-path('KaTeX_Size1-Regular.ttf')) format('truetype');
- font-weight: normal;
+ font-weight: 400;
font-style: normal;
}
@font-face {
font-family: 'KaTeX_Size2';
src: url(font-path('KaTeX_Size2-Regular.eot'));
src: url(font-path('KaTeX_Size2-Regular.eot#iefix')) format('embedded-opentype'), url(font-path('KaTeX_Size2-Regular.woff2')) format('woff2'), url(font-path('KaTeX_Size2-Regular.woff')) format('woff'), url(font-path('KaTeX_Size2-Regular.ttf')) format('truetype');
- font-weight: normal;
+ font-weight: 400;
font-style: normal;
}
@font-face {
font-family: 'KaTeX_Size3';
src: url(font-path('KaTeX_Size3-Regular.eot'));
src: url(font-path('KaTeX_Size3-Regular.eot#iefix')) format('embedded-opentype'), url(font-path('KaTeX_Size3-Regular.woff2')) format('woff2'), url(font-path('KaTeX_Size3-Regular.woff')) format('woff'), url(font-path('KaTeX_Size3-Regular.ttf')) format('truetype');
- font-weight: normal;
+ font-weight: 400;
font-style: normal;
}
@font-face {
font-family: 'KaTeX_Size4';
src: url(font-path('KaTeX_Size4-Regular.eot'));
src: url(font-path('KaTeX_Size4-Regular.eot#iefix')) format('embedded-opentype'), url(font-path('KaTeX_Size4-Regular.woff2')) format('woff2'), url(font-path('KaTeX_Size4-Regular.woff')) format('woff'), url(font-path('KaTeX_Size4-Regular.ttf')) format('truetype');
- font-weight: normal;
+ font-weight: 400;
font-style: normal;
}
@font-face {
font-family: 'KaTeX_Typewriter';
src: url(font-path('KaTeX_Typewriter-Regular.eot'));
src: url(font-path('KaTeX_Typewriter-Regular.eot#iefix')) format('embedded-opentype'), url(font-path('KaTeX_Typewriter-Regular.woff2')) format('woff2'), url(font-path('KaTeX_Typewriter-Regular.woff')) format('woff'), url(font-path('KaTeX_Typewriter-Regular.ttf')) format('truetype');
- font-weight: normal;
+ font-weight: 400;
font-style: normal;
}
.katex-display {
@@ -192,7 +192,7 @@ SOFTWARE.
}
.katex .mathbf {
font-family: KaTeX_Main;
- font-weight: bold;
+ font-weight: 600;
}
.katex .amsrm {
font-family: KaTeX_AMS;
diff --git a/vendor/assets/stylesheets/xterm/xterm.css b/vendor/assets/stylesheets/xterm/xterm.css
index b30d7b493f1..fabc51b0e3d 100644
--- a/vendor/assets/stylesheets/xterm/xterm.css
+++ b/vendor/assets/stylesheets/xterm/xterm.css
@@ -142,7 +142,7 @@
* Determine default colors for xterm.js
*/
.terminal .xterm-bold {
- font-weight: bold;
+ font-weight: 600;
}
.terminal .xterm-underline {