summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2019-10-16 12:06:32 +0000
committerGitLab Bot <gitlab-bot@gitlab.com>2019-10-16 12:06:32 +0000
commitd2ffc30fd583e86d4122bb5061098f4f3ca7b3f1 (patch)
treecb29c77a3ea49eb8ec732b0e644ed6cfad4770d9
parent914ea32e0efca21436220df2c10e1bfbe4ed3da9 (diff)
downloadgitlab-ce-d2ffc30fd583e86d4122bb5061098f4f3ca7b3f1.tar.gz
Add latest changes from gitlab-org/gitlab@master
-rw-r--r--app/assets/javascripts/ide/stores/mutations.js7
-rw-r--r--app/assets/javascripts/registry/components/app.vue53
-rw-r--r--app/assets/javascripts/registry/index.js14
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/mr_collapsible_extension.vue51
-rw-r--r--app/assets/stylesheets/framework/common.scss3
-rw-r--r--app/assets/stylesheets/framework/variables.scss1
-rw-r--r--app/assets/stylesheets/pages/merge_requests.scss2
-rw-r--r--app/helpers/application_helper.rb5
-rw-r--r--app/models/container_repository.rb2
-rw-r--r--app/services/projects/container_repository/delete_tags_service.rb6
-rw-r--r--app/views/projects/registry/repositories/index.html.haml3
-rw-r--r--app/views/shared/_allow_request_access.html.haml4
-rw-r--r--changelogs/unreleased/18217-request-access-to-project-should-be-on-by-default.yml5
-rw-r--r--changelogs/unreleased/29881-fix-ide-delete-and-readd.yml5
-rw-r--r--changelogs/unreleased/feature-add-copyable-login-with-copy-to-empty-container-registry-view.yml5
-rw-r--r--changelogs/unreleased/issue_11240.yml5
-rw-r--r--config/initializers/7_prometheus_metrics.rb6
-rw-r--r--db/migrate/20190925055714_default_request_access_groups.rb15
-rw-r--r--db/migrate/20190925055902_default_request_access_projects.rb15
-rw-r--r--db/schema.rb4
-rw-r--r--doc/api/epics.md3
-rw-r--r--lib/container_registry/client.rb8
-rw-r--r--lib/gitlab/health_checks/gitaly_check.rb2
-rw-r--r--lib/gitlab/health_checks/probes/readiness.rb6
-rw-r--r--lib/gitlab/health_checks/puma_check.rb36
-rw-r--r--lib/gitlab/health_checks/simple_abstract_check.rb4
-rw-r--r--lib/gitlab/health_checks/unicorn_check.rb41
-rw-r--r--lib/gitlab/metrics/exporter/base_exporter.rb20
-rw-r--r--lib/gitlab/metrics/exporter/web_exporter.rb10
-rw-r--r--locale/gitlab.pot11
-rw-r--r--scripts/review_apps/base-config.yaml3
-rw-r--r--spec/controllers/groups/group_members_controller_spec.rb2
-rw-r--r--spec/controllers/projects/project_members_controller_spec.rb2
-rw-r--r--spec/factories/groups.rb4
-rw-r--r--spec/factories/projects.rb4
-rw-r--r--spec/features/groups/members/master_manages_access_requests_spec.rb2
-rw-r--r--spec/features/groups/members/request_access_spec.rb2
-rw-r--r--spec/features/projects/members/group_members_spec.rb4
-rw-r--r--spec/features/projects/members/group_requester_cannot_request_access_to_project_spec.rb4
-rw-r--r--spec/features/projects/members/master_manages_access_requests_spec.rb2
-rw-r--r--spec/features/projects/members/user_requests_access_spec.rb2
-rw-r--r--spec/finders/access_requests_finder_spec.rb4
-rw-r--r--spec/finders/group_members_finder_spec.rb2
-rw-r--r--spec/finders/members_finder_spec.rb4
-rw-r--r--spec/frontend/ide/stores/integration_spec.js100
-rw-r--r--spec/frontend/registry/components/app_spec.js13
-rw-r--r--spec/frontend/vue_mr_widget/components/artifacts_list_app_spec.js8
-rw-r--r--spec/frontend/vue_mr_widget/components/mr_collapsible_extension_spec.js20
-rw-r--r--spec/helpers/members_helper_spec.rb8
-rw-r--r--spec/lib/gitlab/health_checks/puma_check_spec.rb65
-rw-r--r--spec/lib/gitlab/health_checks/unicorn_check_spec.rb63
-rw-r--r--spec/lib/gitlab/metrics/exporter/base_exporter_spec.rb12
-rw-r--r--spec/mailers/notify_spec.rb8
-rw-r--r--spec/models/ci/build_metadata_spec.rb2
-rw-r--r--spec/models/ci/build_spec.rb2
-rw-r--r--spec/models/concerns/access_requestable_spec.rb8
-rw-r--r--spec/models/group_spec.rb4
-rw-r--r--spec/models/member_spec.rb6
-rw-r--r--spec/models/project_spec.rb2
-rw-r--r--spec/models/project_team_spec.rb8
-rw-r--r--spec/models/user_spec.rb6
-rw-r--r--spec/requests/api/access_requests_spec.rb4
-rw-r--r--spec/requests/api/badges_spec.rb4
-rw-r--r--spec/requests/api/members_spec.rb4
-rw-r--r--spec/services/members/approve_access_request_service_spec.rb4
-rw-r--r--spec/services/members/request_access_service_spec.rb4
-rw-r--r--spec/services/notification_service_spec.rb18
-rw-r--r--spec/services/projects/container_repository/cleanup_tags_service_spec.rb2
-rw-r--r--spec/services/projects/container_repository/delete_tags_service_spec.rb15
69 files changed, 638 insertions, 145 deletions
diff --git a/app/assets/javascripts/ide/stores/mutations.js b/app/assets/javascripts/ide/stores/mutations.js
index 2587b57a817..e84e2782e46 100644
--- a/app/assets/javascripts/ide/stores/mutations.js
+++ b/app/assets/javascripts/ide/stores/mutations.js
@@ -73,16 +73,15 @@ export default {
const entry = data.entries[key];
const foundEntry = state.entries[key];
+ // NOTE: We can't clone `entry` in any of the below assignments because
+ // we need `state.entries` and the `entry.tree` to reference the same object.
if (!foundEntry) {
Object.assign(state.entries, {
[key]: entry,
});
} else if (foundEntry.deleted) {
Object.assign(state.entries, {
- [key]: {
- ...entry,
- replaces: true,
- },
+ [key]: Object.assign(entry, { replaces: true }),
});
} else {
const tree = entry.tree.filter(
diff --git a/app/assets/javascripts/registry/components/app.vue b/app/assets/javascripts/registry/components/app.vue
index 7ae06af02cf..a20bae9e37e 100644
--- a/app/assets/javascripts/registry/components/app.vue
+++ b/app/assets/javascripts/registry/components/app.vue
@@ -15,15 +15,19 @@ export default {
GlLoadingIcon,
},
props: {
- endpoint: {
- type: String,
- required: true,
- },
characterError: {
type: Boolean,
required: false,
default: false,
},
+ containersErrorImage: {
+ type: String,
+ required: true,
+ },
+ endpoint: {
+ type: String,
+ required: true,
+ },
helpPagePath: {
type: String,
required: true,
@@ -32,7 +36,11 @@ export default {
type: String,
required: true,
},
- containersErrorImage: {
+ personalAccessTokensHelpLink: {
+ type: String,
+ required: true,
+ },
+ registryHostUrlWithPort: {
type: String,
required: true,
},
@@ -40,6 +48,10 @@ export default {
type: String,
required: true,
},
+ twoFactorAuthHelpLink: {
+ type: String,
+ required: true,
+ },
},
store,
computed: {
@@ -79,6 +91,26 @@ export default {
false,
);
},
+ notLoggedInToRegistryText() {
+ return sprintf(
+ s__(`ContainerRegistry|If you are not already logged in, you need to authenticate to
+ the Container Registry by using your GitLab username and password. If you have
+ %{twofaDocLinkStart}Two-Factor Authentication%{twofaDocLinkEnd} enabled, use a
+ %{personalAccessTokensDocLinkStart}Personal Access Token
+ %{personalAccessTokensDocLinkEnd}instead of a password.`),
+ {
+ twofaDocLinkStart: `<a href="${this.twoFactorAuthHelpLink}" target="_blank">`,
+ twofaDocLinkEnd: '</a>',
+ personalAccessTokensDocLinkStart: `<a href="${this.personalAccessTokensHelpLink}" target="_blank">`,
+ personalAccessTokensDocLinkEnd: '</a>',
+ },
+ false,
+ );
+ },
+ dockerLoginCommand() {
+ // eslint-disable-next-line @gitlab/i18n/no-non-i18n-strings
+ return `docker login ${this.registryHostUrlWithPort}`;
+ },
dockerBuildCommand() {
// eslint-disable-next-line @gitlab/i18n/no-non-i18n-strings
return `docker build -t ${this.repositoryUrl} .`;
@@ -130,6 +162,17 @@ export default {
<template #description>
<p class="js-no-container-images-text" v-html="noContainerImagesText"></p>
<h5>{{ s__('ContainerRegistry|Quick Start') }}</h5>
+ <p class="js-not-logged-in-to-registry-text" v-html="notLoggedInToRegistryText"></p>
+ <div class="input-group append-bottom-10">
+ <input :value="dockerLoginCommand" type="text" class="form-control monospace" readonly />
+ <span class="input-group-append">
+ <clipboard-button
+ :text="dockerLoginCommand"
+ :title="s__('ContainerRegistry|Copy login command')"
+ class="input-group-text"
+ />
+ </span>
+ </div>
<p>
{{
s__(
diff --git a/app/assets/javascripts/registry/index.js b/app/assets/javascripts/registry/index.js
index d8daec29fda..38c3d67042c 100644
--- a/app/assets/javascripts/registry/index.js
+++ b/app/assets/javascripts/registry/index.js
@@ -13,23 +13,29 @@ export default () =>
data() {
const { dataset } = document.querySelector(this.$options.el);
return {
- endpoint: dataset.endpoint,
characterError: Boolean(dataset.characterError),
+ containersErrorImage: dataset.containersErrorImage,
+ endpoint: dataset.endpoint,
helpPagePath: dataset.helpPagePath,
noContainersImage: dataset.noContainersImage,
- containersErrorImage: dataset.containersErrorImage,
+ personalAccessTokensHelpLink: dataset.personalAccessTokensHelpLink,
+ registryHostUrlWithPort: dataset.registryHostUrlWithPort,
repositoryUrl: dataset.repositoryUrl,
+ twoFactorAuthHelpLink: dataset.twoFactorAuthHelpLink,
};
},
render(createElement) {
return createElement('registry-app', {
props: {
- endpoint: this.endpoint,
characterError: this.characterError,
+ containersErrorImage: this.containersErrorImage,
+ endpoint: this.endpoint,
helpPagePath: this.helpPagePath,
noContainersImage: this.noContainersImage,
- containersErrorImage: this.containersErrorImage,
+ personalAccessTokensHelpLink: this.personalAccessTokensHelpLink,
+ registryHostUrlWithPort: this.registryHostUrlWithPort,
repositoryUrl: this.repositoryUrl,
+ twoFactorAuthHelpLink: this.twoFactorAuthHelpLink,
},
});
},
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/mr_collapsible_extension.vue b/app/assets/javascripts/vue_merge_request_widget/components/mr_collapsible_extension.vue
index ae1d9368008..36f291e995c 100644
--- a/app/assets/javascripts/vue_merge_request_widget/components/mr_collapsible_extension.vue
+++ b/app/assets/javascripts/vue_merge_request_widget/components/mr_collapsible_extension.vue
@@ -39,9 +39,6 @@ export default {
ariaLabel() {
return this.isCollapsed ? __('Expand') : __('Collapse');
},
- isButtonDisabled() {
- return this.isLoading || this.hasError;
- },
},
methods: {
toggleCollapsed() {
@@ -53,25 +50,35 @@ export default {
<template>
<div>
<div class="mr-widget-extension d-flex align-items-center pl-3">
- <gl-button
- class="btn-blank btn s32 square append-right-default"
- :aria-label="ariaLabel"
- :disabled="isButtonDisabled"
- @click="toggleCollapsed"
- >
- <gl-loading-icon v-if="isLoading" />
- <icon v-else :name="arrowIconName" class="js-icon" />
- </gl-button>
- <gl-button
- variant="link"
- class="js-title"
- :disabled="isButtonDisabled"
- :class="{ 'border-0': isButtonDisabled }"
- @click="toggleCollapsed"
- >
- <template v-if="isCollapsed">{{ title }}</template>
- <template v-else>{{ __('Collapse') }}</template>
- </gl-button>
+ <div v-if="hasError" class="ci-widget media">
+ <div class="media-body">
+ <span class="gl-font-size-small mr-widget-margin-left gl-line-height-24 js-error-state">{{
+ title
+ }}</span>
+ </div>
+ </div>
+
+ <template v-else>
+ <gl-button
+ class="btn-blank btn s32 square append-right-default"
+ :aria-label="ariaLabel"
+ :disabled="isLoading"
+ @click="toggleCollapsed"
+ >
+ <gl-loading-icon v-if="isLoading" />
+ <icon v-else :name="arrowIconName" class="js-icon" />
+ </gl-button>
+ <gl-button
+ variant="link"
+ class="js-title"
+ :disabled="isLoading"
+ :class="{ 'border-0': isLoading }"
+ @click="toggleCollapsed"
+ >
+ <template v-if="isCollapsed">{{ title }}</template>
+ <template v-else>{{ __('Collapse') }}</template>
+ </gl-button>
+ </template>
</div>
<div v-if="!isCollapsed" class="border-top js-slot-container">
diff --git a/app/assets/stylesheets/framework/common.scss b/app/assets/stylesheets/framework/common.scss
index 370fc84e492..4b89a2f2b04 100644
--- a/app/assets/stylesheets/framework/common.scss
+++ b/app/assets/stylesheets/framework/common.scss
@@ -560,3 +560,6 @@ img.emoji {
}
}
}
+
+.gl-font-size-small { font-size: $gl-font-size-small; }
+.gl-line-height-24 { line-height: $gl-line-height-24; }
diff --git a/app/assets/stylesheets/framework/variables.scss b/app/assets/stylesheets/framework/variables.scss
index f352ee33535..dfc39d8e03b 100644
--- a/app/assets/stylesheets/framework/variables.scss
+++ b/app/assets/stylesheets/framework/variables.scss
@@ -833,6 +833,7 @@ Merge Requests
*/
$mr-tabs-height: 48px;
$mr-version-controls-height: 56px;
+$mr-widget-margin-left: 40px;
/*
Compare Branches
diff --git a/app/assets/stylesheets/pages/merge_requests.scss b/app/assets/stylesheets/pages/merge_requests.scss
index e6feded1d4f..971f3b2c308 100644
--- a/app/assets/stylesheets/pages/merge_requests.scss
+++ b/app/assets/stylesheets/pages/merge_requests.scss
@@ -19,6 +19,8 @@
border-top: 1px solid $border-color;
}
+.mr-widget-margin-left { margin-left: $mr-widget-margin-left; }
+
.media-section {
@include media-breakpoint-down(md) {
align-items: flex-start;
diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb
index 5c2420e80f2..ecaeb7060c8 100644
--- a/app/helpers/application_helper.rb
+++ b/app/helpers/application_helper.rb
@@ -108,6 +108,11 @@ module ApplicationHelper
Gitlab.config.extra
end
+ # shortcut for gitlab registry config
+ def registry_config
+ Gitlab.config.registry
+ end
+
# Render a `time` element with Javascript-based relative date and tooltip
#
# time - Time object
diff --git a/app/models/container_repository.rb b/app/models/container_repository.rb
index 583e23d1274..253f74e9811 100644
--- a/app/models/container_repository.rb
+++ b/app/models/container_repository.rb
@@ -67,7 +67,7 @@ class ContainerRepository < ApplicationRecord
def delete_tags!
return unless has_tags?
- digests = tags.map { |tag| tag.digest }.to_set
+ digests = tags.map { |tag| tag.digest }.compact.to_set
digests.all? do |digest|
delete_tag_by_digest(digest)
diff --git a/app/services/projects/container_repository/delete_tags_service.rb b/app/services/projects/container_repository/delete_tags_service.rb
index 22656b29c58..5129e2269a8 100644
--- a/app/services/projects/container_repository/delete_tags_service.rb
+++ b/app/services/projects/container_repository/delete_tags_service.rb
@@ -48,10 +48,10 @@ module Projects
# rubocop: disable CodeReuse/ActiveRecord
Gitlab::Sentry.track_exception(ArgumentError.new('multiple tag digests')) if tag_digests.many?
- # deletes the dummy image
- # all created tag digests are the same since they all have the same dummy image.
+ # Deletes the dummy image
+ # All created tag digests are the same since they all have the same dummy image.
# a single delete is sufficient to remove all tags with it
- if container_repository.client.delete_repository_tag(container_repository.path, tag_digests.first)
+ if container_repository.delete_tag_by_digest(tag_digests.first)
success(deleted: tag_names)
else
error('could not delete tags')
diff --git a/app/views/projects/registry/repositories/index.html.haml b/app/views/projects/registry/repositories/index.html.haml
index ddb19cb6b65..b2e160e37bc 100644
--- a/app/views/projects/registry/repositories/index.html.haml
+++ b/app/views/projects/registry/repositories/index.html.haml
@@ -5,7 +5,10 @@
.col-12
#js-vue-registry-images{ data: { endpoint: project_container_registry_index_path(@project, format: :json),
"help_page_path" => help_page_path('user/packages/container_registry/index'),
+ "two_factor_auth_help_link" => help_page_path('user/profile/account/two_factor_authentication'),
+ "personal_access_tokens_help_link" => help_page_path('user/profile/personal_access_tokens'),
"no_containers_image" => image_path('illustrations/docker-empty-state.svg'),
"containers_error_image" => image_path('illustrations/docker-error-state.svg'),
"repository_url" => escape_once(@project.container_registry_url),
+ "registry_host_url_with_port" => escape_once(registry_config.host_port),
character_error: @character_error.to_s } }
diff --git a/app/views/shared/_allow_request_access.html.haml b/app/views/shared/_allow_request_access.html.haml
index 2b24bde9e59..ca82f2f3377 100644
--- a/app/views/shared/_allow_request_access.html.haml
+++ b/app/views/shared/_allow_request_access.html.haml
@@ -3,6 +3,4 @@
.form-check
= form.check_box :request_access_enabled, class: 'form-check-input', data: { qa_selector: 'request_access_checkbox' }
= form.label :request_access_enabled, class: 'form-check-label' do
- %span{ class: label_class }= _('Allow users to request access')
- %br
- %span.text-muted= _('Allow users to request access if visibility is public or internal.')
+ %span{ class: label_class }= _('Allow users to request access (if visibility is public or internal)')
diff --git a/changelogs/unreleased/18217-request-access-to-project-should-be-on-by-default.yml b/changelogs/unreleased/18217-request-access-to-project-should-be-on-by-default.yml
new file mode 100644
index 00000000000..3fb1b874e77
--- /dev/null
+++ b/changelogs/unreleased/18217-request-access-to-project-should-be-on-by-default.yml
@@ -0,0 +1,5 @@
+---
+title: Enable Request Access functionality by default for new projects and groups
+merge_request: 17662
+author:
+type: changed
diff --git a/changelogs/unreleased/29881-fix-ide-delete-and-readd.yml b/changelogs/unreleased/29881-fix-ide-delete-and-readd.yml
new file mode 100644
index 00000000000..91445ca791b
--- /dev/null
+++ b/changelogs/unreleased/29881-fix-ide-delete-and-readd.yml
@@ -0,0 +1,5 @@
+---
+title: Fix Web IDE tree not updating modified status
+merge_request: 18647
+author:
+type: fixed
diff --git a/changelogs/unreleased/feature-add-copyable-login-with-copy-to-empty-container-registry-view.yml b/changelogs/unreleased/feature-add-copyable-login-with-copy-to-empty-container-registry-view.yml
new file mode 100644
index 00000000000..6d7a773120b
--- /dev/null
+++ b/changelogs/unreleased/feature-add-copyable-login-with-copy-to-empty-container-registry-view.yml
@@ -0,0 +1,5 @@
+---
+title: Adds login input with copy box and supporting copy to empty container registry view
+merge_request: 18244
+author: nate geslin
+type: added
diff --git a/changelogs/unreleased/issue_11240.yml b/changelogs/unreleased/issue_11240.yml
new file mode 100644
index 00000000000..751440d1e8c
--- /dev/null
+++ b/changelogs/unreleased/issue_11240.yml
@@ -0,0 +1,5 @@
+---
+title: Expose subscribed attribute for epic on API
+merge_request: 18475
+author:
+type: added
diff --git a/config/initializers/7_prometheus_metrics.rb b/config/initializers/7_prometheus_metrics.rb
index c5cd055f4ff..d58fb54f71c 100644
--- a/config/initializers/7_prometheus_metrics.rb
+++ b/config/initializers/7_prometheus_metrics.rb
@@ -34,6 +34,12 @@ Sidekiq.configure_server do |config|
config.on(:startup) do
# webserver metrics are cleaned up in config.ru: `warmup` block
Prometheus::CleanupMultiprocDirService.new.execute
+ # In production, sidekiq is run in a multi-process setup where processes might interfere
+ # with each other cleaning up and reinitializing prometheus database files, which is why
+ # we're re-doing the work every time here.
+ # A cleaner solution would be to run the cleanup pre-fork, and the initialization once
+ # after all workers have forked, but I don't know how at this point.
+ ::Prometheus::Client.reinitialize_on_pid_change(force: true)
Gitlab::Metrics::Exporter::SidekiqExporter.instance.start
end
diff --git a/db/migrate/20190925055714_default_request_access_groups.rb b/db/migrate/20190925055714_default_request_access_groups.rb
new file mode 100644
index 00000000000..ba3efbe56f4
--- /dev/null
+++ b/db/migrate/20190925055714_default_request_access_groups.rb
@@ -0,0 +1,15 @@
+# frozen_string_literal: true
+
+class DefaultRequestAccessGroups < ActiveRecord::Migration[5.2]
+ include Gitlab::Database::MigrationHelpers
+
+ DOWNTIME = false
+
+ def up
+ change_column_default :namespaces, :request_access_enabled, true
+ end
+
+ def down
+ change_column_default :namespaces, :request_access_enabled, false
+ end
+end
diff --git a/db/migrate/20190925055902_default_request_access_projects.rb b/db/migrate/20190925055902_default_request_access_projects.rb
new file mode 100644
index 00000000000..3ad88d0963d
--- /dev/null
+++ b/db/migrate/20190925055902_default_request_access_projects.rb
@@ -0,0 +1,15 @@
+# frozen_string_literal: true
+
+class DefaultRequestAccessProjects < ActiveRecord::Migration[5.2]
+ include Gitlab::Database::MigrationHelpers
+
+ DOWNTIME = false
+
+ def up
+ change_column_default :projects, :request_access_enabled, true
+ end
+
+ def down
+ change_column_default :projects, :request_access_enabled, false
+ end
+end
diff --git a/db/schema.rb b/db/schema.rb
index b9952cfc12d..c860fed7bbc 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -2333,7 +2333,7 @@ ActiveRecord::Schema.define(version: 2019_10_04_133612) do
t.boolean "membership_lock", default: false
t.boolean "share_with_group_lock", default: false
t.integer "visibility_level", default: 20, null: false
- t.boolean "request_access_enabled", default: false, null: false
+ t.boolean "request_access_enabled", default: true, null: false
t.string "ldap_sync_status", default: "ready", null: false
t.string "ldap_sync_error"
t.datetime "ldap_sync_last_update_at"
@@ -2922,7 +2922,7 @@ ActiveRecord::Schema.define(version: 2019_10_04_133612) do
t.boolean "has_external_issue_tracker"
t.string "repository_storage", default: "default", null: false
t.boolean "repository_read_only"
- t.boolean "request_access_enabled", default: false, null: false
+ t.boolean "request_access_enabled", default: true, null: false
t.boolean "has_external_wiki"
t.string "ci_config_path"
t.boolean "lfs_enabled"
diff --git a/doc/api/epics.md b/doc/api/epics.md
index c24df6a236f..a5ec42a2a41 100644
--- a/doc/api/epics.md
+++ b/doc/api/epics.md
@@ -147,7 +147,8 @@ Example response:
"closed_at": "2018-08-18T12:22:05.239Z",
"labels": [],
"upvotes": 4,
- "downvotes": 0
+ "downvotes": 0,
+ "subscribed": true
}
```
diff --git a/lib/container_registry/client.rb b/lib/container_registry/client.rb
index 2bd8eb65306..92861c567a8 100644
--- a/lib/container_registry/client.rb
+++ b/lib/container_registry/client.rb
@@ -36,7 +36,9 @@ module ContainerRegistry
end
def delete_repository_tag(name, reference)
- faraday.delete("/v2/#{name}/manifests/#{reference}").success?
+ result = faraday.delete("/v2/#{name}/manifests/#{reference}")
+
+ result.success? || result.status == 404
end
def upload_raw_blob(path, blob)
@@ -84,7 +86,9 @@ module ContainerRegistry
end
def delete_blob(name, digest)
- faraday.delete("/v2/#{name}/blobs/#{digest}").success?
+ result = faraday.delete("/v2/#{name}/blobs/#{digest}")
+
+ result.success? || result.status == 404
end
def put_tag(name, reference, manifest)
diff --git a/lib/gitlab/health_checks/gitaly_check.rb b/lib/gitlab/health_checks/gitaly_check.rb
index f5f142c251f..e780bf8a986 100644
--- a/lib/gitlab/health_checks/gitaly_check.rb
+++ b/lib/gitlab/health_checks/gitaly_check.rb
@@ -5,7 +5,7 @@ module Gitlab
class GitalyCheck
extend BaseAbstractCheck
- METRIC_PREFIX = 'gitaly_health_check'
+ METRIC_PREFIX = 'gitaly_health_check'.freeze
class << self
def readiness
diff --git a/lib/gitlab/health_checks/probes/readiness.rb b/lib/gitlab/health_checks/probes/readiness.rb
index b789cbe1ae6..28abf490ffc 100644
--- a/lib/gitlab/health_checks/probes/readiness.rb
+++ b/lib/gitlab/health_checks/probes/readiness.rb
@@ -6,10 +6,10 @@ module Gitlab
class Readiness
attr_reader :checks
- # This accepts an array of Proc
+ # This accepts an array of objects implementing `:readiness`
# that returns `::Gitlab::HealthChecks::Result`
def initialize(*additional_checks)
- @checks = ::Gitlab::HealthChecks::CHECKS.map { |check| check.method(:readiness) }
+ @checks = ::Gitlab::HealthChecks::CHECKS
@checks += additional_checks
end
@@ -43,7 +43,7 @@ module Gitlab
def probe_readiness
checks
- .flat_map(&:call)
+ .flat_map(&:readiness)
.compact
.group_by(&:name)
end
diff --git a/lib/gitlab/health_checks/puma_check.rb b/lib/gitlab/health_checks/puma_check.rb
new file mode 100644
index 00000000000..7aafe29fbae
--- /dev/null
+++ b/lib/gitlab/health_checks/puma_check.rb
@@ -0,0 +1,36 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module HealthChecks
+ # This check can only be run on Puma `master` process
+ class PumaCheck
+ extend SimpleAbstractCheck
+
+ class << self
+ private
+
+ def metric_prefix
+ 'puma_check'
+ end
+
+ def successful?(result)
+ result > 0
+ end
+
+ def check
+ return unless defined?(::Puma)
+
+ stats = Puma.stats
+ stats = JSON.parse(stats)
+
+ # If `workers` is missing this means that
+ # Puma server is running in single mode
+ stats.fetch('workers', 1)
+ rescue NoMethodError
+ # server is not ready
+ 0
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/health_checks/simple_abstract_check.rb b/lib/gitlab/health_checks/simple_abstract_check.rb
index 959f28791c3..4e0b9296819 100644
--- a/lib/gitlab/health_checks/simple_abstract_check.rb
+++ b/lib/gitlab/health_checks/simple_abstract_check.rb
@@ -7,6 +7,8 @@ module Gitlab
def readiness
check_result = check
+ return if check_result.nil?
+
if successful?(check_result)
HealthChecks::Result.new(name, true)
elsif check_result.is_a?(Timeout::Error)
@@ -20,6 +22,8 @@ module Gitlab
def metrics
result, elapsed = with_timing(&method(:check))
+ return if result.nil?
+
Rails.logger.error("#{human_name} check returned unexpected result #{result}") unless successful?(result) # rubocop:disable Gitlab/RailsLogger
[
metric("#{metric_prefix}_timeout", result.is_a?(Timeout::Error) ? 1 : 0),
diff --git a/lib/gitlab/health_checks/unicorn_check.rb b/lib/gitlab/health_checks/unicorn_check.rb
new file mode 100644
index 00000000000..a30ae015257
--- /dev/null
+++ b/lib/gitlab/health_checks/unicorn_check.rb
@@ -0,0 +1,41 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module HealthChecks
+ # This check can only be run on Unicorn `master` process
+ class UnicornCheck
+ extend SimpleAbstractCheck
+
+ class << self
+ include Gitlab::Utils::StrongMemoize
+
+ private
+
+ def metric_prefix
+ 'unicorn_check'
+ end
+
+ def successful?(result)
+ result > 0
+ end
+
+ def check
+ return unless http_servers
+
+ http_servers.sum(&:worker_processes) # rubocop: disable CodeReuse/ActiveRecord
+ end
+
+ # Traversal of ObjectSpace is expensive, on fully loaded application
+ # it takes around 80ms. The instances of HttpServers are not a subject
+ # to change so we can cache the list of servers.
+ def http_servers
+ strong_memoize(:http_servers) do
+ next unless defined?(::Unicorn::HttpServer)
+
+ ObjectSpace.each_object(::Unicorn::HttpServer).to_a
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/metrics/exporter/base_exporter.rb b/lib/gitlab/metrics/exporter/base_exporter.rb
index 3aac18f59c6..13483e437d8 100644
--- a/lib/gitlab/metrics/exporter/base_exporter.rb
+++ b/lib/gitlab/metrics/exporter/base_exporter.rb
@@ -6,6 +6,8 @@ module Gitlab
class BaseExporter < Daemon
attr_reader :server
+ attr_accessor :additional_checks
+
def enabled?
settings.enabled
end
@@ -32,12 +34,10 @@ module Gitlab
Port: settings.port, BindAddress: settings.address,
Logger: logger, AccessLog: access_log)
server.mount_proc '/readiness' do |req, res|
- render_probe(
- ::Gitlab::HealthChecks::Probes::Readiness.new, req, res)
+ render_probe(readiness_probe, req, res)
end
server.mount_proc '/liveness' do |req, res|
- render_probe(
- ::Gitlab::HealthChecks::Probes::Liveness.new, req, res)
+ render_probe(liveness_probe, req, res)
end
server.mount '/', Rack::Handler::WEBrick, rack_app
@@ -52,8 +52,10 @@ module Gitlab
def stop_working
if server
+ # we close sockets if thread is not longer running
+ # this happens, when the process forks
+ server.listeners.each(&:close) unless thread.alive?
server.shutdown
- server.listeners.each(&:close)
end
@server = nil
@@ -67,6 +69,14 @@ module Gitlab
end
end
+ def readiness_probe
+ ::Gitlab::HealthChecks::Probes::Readiness.new(*additional_checks)
+ end
+
+ def liveness_probe
+ ::Gitlab::HealthChecks::Probes::Liveness.new
+ end
+
def render_probe(probe, req, res)
result = probe.execute
diff --git a/lib/gitlab/metrics/exporter/web_exporter.rb b/lib/gitlab/metrics/exporter/web_exporter.rb
index fac7043352a..f4b42759fb9 100644
--- a/lib/gitlab/metrics/exporter/web_exporter.rb
+++ b/lib/gitlab/metrics/exporter/web_exporter.rb
@@ -7,6 +7,16 @@ module Gitlab
module Metrics
module Exporter
class WebExporter < BaseExporter
+ # This exporter is always run on master process
+ def initialize
+ super
+
+ self.additional_checks = [
+ Gitlab::HealthChecks::PumaCheck,
+ Gitlab::HealthChecks::UnicornCheck
+ ]
+ end
+
def settings
Settings.monitoring.web_exporter
end
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index 0741e0445a6..d8c5a934542 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -1413,10 +1413,7 @@ msgstr ""
msgid "Allow users to register any application to use GitLab as an OAuth provider"
msgstr ""
-msgid "Allow users to request access"
-msgstr ""
-
-msgid "Allow users to request access if visibility is public or internal."
+msgid "Allow users to request access (if visibility is public or internal)"
msgstr ""
msgid "Allowed email domain restriction only permitted for top-level groups"
@@ -4352,12 +4349,18 @@ msgstr ""
msgid "ContainerRegistry|Copy build command"
msgstr ""
+msgid "ContainerRegistry|Copy login command"
+msgstr ""
+
msgid "ContainerRegistry|Copy push command"
msgstr ""
msgid "ContainerRegistry|Docker connection error"
msgstr ""
+msgid "ContainerRegistry|If you are not already logged in, you need to authenticate to the Container Registry by using your GitLab username and password. If you have %{twofaDocLinkStart}Two-Factor Authentication%{twofaDocLinkEnd} enabled, use a %{personalAccessTokensDocLinkStart}Personal Access Token %{personalAccessTokensDocLinkEnd}instead of a password."
+msgstr ""
+
msgid "ContainerRegistry|Last Updated"
msgstr ""
diff --git a/scripts/review_apps/base-config.yaml b/scripts/review_apps/base-config.yaml
index de5e14af4d4..1dc79e6d45e 100644
--- a/scripts/review_apps/base-config.yaml
+++ b/scripts/review_apps/base-config.yaml
@@ -153,7 +153,8 @@ redis:
redis-ha:
enabled: false
registry:
- minReplicas: 1
+ hpa:
+ minReplicas: 1
resources:
requests:
cpu: 50m
diff --git a/spec/controllers/groups/group_members_controller_spec.rb b/spec/controllers/groups/group_members_controller_spec.rb
index 0c3dd971582..22f970133e3 100644
--- a/spec/controllers/groups/group_members_controller_spec.rb
+++ b/spec/controllers/groups/group_members_controller_spec.rb
@@ -6,7 +6,7 @@ describe Groups::GroupMembersController do
include ExternalAuthorizationServiceHelpers
let(:user) { create(:user) }
- let(:group) { create(:group, :public, :access_requestable) }
+ let(:group) { create(:group, :public) }
let(:membership) { create(:group_member, group: group) }
describe 'GET index' do
diff --git a/spec/controllers/projects/project_members_controller_spec.rb b/spec/controllers/projects/project_members_controller_spec.rb
index 5130e26c928..2f473d395ad 100644
--- a/spec/controllers/projects/project_members_controller_spec.rb
+++ b/spec/controllers/projects/project_members_controller_spec.rb
@@ -4,7 +4,7 @@ require('spec_helper')
describe Projects::ProjectMembersController do
let(:user) { create(:user) }
- let(:project) { create(:project, :public, :access_requestable) }
+ let(:project) { create(:project, :public) }
describe 'GET index' do
it 'has the project_members address with a 200 status code' do
diff --git a/spec/factories/groups.rb b/spec/factories/groups.rb
index ba1a4883f85..93c01f8034d 100644
--- a/spec/factories/groups.rb
+++ b/spec/factories/groups.rb
@@ -32,8 +32,8 @@ FactoryBot.define do
avatar { fixture_file_upload('spec/fixtures/dk.png') }
end
- trait :access_requestable do
- request_access_enabled { true }
+ trait :request_access_disabled do
+ request_access_enabled { false }
end
trait :nested do
diff --git a/spec/factories/projects.rb b/spec/factories/projects.rb
index ae1feb73e4d..9477eeb18d4 100644
--- a/spec/factories/projects.rb
+++ b/spec/factories/projects.rb
@@ -117,8 +117,8 @@ FactoryBot.define do
storage_version { nil }
end
- trait :access_requestable do
- request_access_enabled { true }
+ trait :request_access_disabled do
+ request_access_enabled { false }
end
trait :with_avatar do
diff --git a/spec/features/groups/members/master_manages_access_requests_spec.rb b/spec/features/groups/members/master_manages_access_requests_spec.rb
index 454da126c81..1c13bd3d59e 100644
--- a/spec/features/groups/members/master_manages_access_requests_spec.rb
+++ b/spec/features/groups/members/master_manages_access_requests_spec.rb
@@ -4,7 +4,7 @@ require 'spec_helper'
describe 'Groups > Members > Maintainer manages access requests' do
it_behaves_like 'Maintainer manages access requests' do
- let(:entity) { create(:group, :public, :access_requestable) }
+ let(:entity) { create(:group, :public) }
let(:members_page_path) { group_group_members_path(entity) }
end
end
diff --git a/spec/features/groups/members/request_access_spec.rb b/spec/features/groups/members/request_access_spec.rb
index 0d5321709ae..5f22af3529c 100644
--- a/spec/features/groups/members/request_access_spec.rb
+++ b/spec/features/groups/members/request_access_spec.rb
@@ -5,7 +5,7 @@ require 'spec_helper'
describe 'Groups > Members > Request access' do
let(:user) { create(:user) }
let(:owner) { create(:user) }
- let(:group) { create(:group, :public, :access_requestable) }
+ let(:group) { create(:group, :public) }
let!(:project) { create(:project, :private, namespace: group) }
before do
diff --git a/spec/features/projects/members/group_members_spec.rb b/spec/features/projects/members/group_members_spec.rb
index dd5fc82e058..4ecc3db78b3 100644
--- a/spec/features/projects/members/group_members_spec.rb
+++ b/spec/features/projects/members/group_members_spec.rb
@@ -5,8 +5,8 @@ require 'spec_helper'
describe 'Projects members' do
let(:user) { create(:user) }
let(:developer) { create(:user) }
- let(:group) { create(:group, :public, :access_requestable) }
- let(:project) { create(:project, :public, :access_requestable, creator: user, group: group) }
+ let(:group) { create(:group, :public) }
+ let(:project) { create(:project, :public, creator: user, group: group) }
let(:project_invitee) { create(:project_member, project: project, invite_token: '123', invite_email: 'test1@abc.com', user: nil) }
let(:group_invitee) { create(:group_member, group: group, invite_token: '123', invite_email: 'test2@abc.com', user: nil) }
let(:project_requester) { create(:user) }
diff --git a/spec/features/projects/members/group_requester_cannot_request_access_to_project_spec.rb b/spec/features/projects/members/group_requester_cannot_request_access_to_project_spec.rb
index fb4238f0a1f..ecd55f71c84 100644
--- a/spec/features/projects/members/group_requester_cannot_request_access_to_project_spec.rb
+++ b/spec/features/projects/members/group_requester_cannot_request_access_to_project_spec.rb
@@ -5,8 +5,8 @@ require 'spec_helper'
describe 'Projects > Members > Group requester cannot request access to project', :js do
let(:user) { create(:user) }
let(:owner) { create(:user) }
- let(:group) { create(:group, :public, :access_requestable) }
- let(:project) { create(:project, :public, :access_requestable, namespace: group) }
+ let(:group) { create(:group, :public) }
+ let(:project) { create(:project, :public, namespace: group) }
before do
group.add_owner(owner)
diff --git a/spec/features/projects/members/master_manages_access_requests_spec.rb b/spec/features/projects/members/master_manages_access_requests_spec.rb
index 17d6efbcaa5..f113fb643f8 100644
--- a/spec/features/projects/members/master_manages_access_requests_spec.rb
+++ b/spec/features/projects/members/master_manages_access_requests_spec.rb
@@ -4,7 +4,7 @@ require 'spec_helper'
describe 'Projects > Members > Maintainer manages access requests' do
it_behaves_like 'Maintainer manages access requests' do
- let(:entity) { create(:project, :public, :access_requestable) }
+ let(:entity) { create(:project, :public) }
let(:members_page_path) { project_project_members_path(entity) }
end
end
diff --git a/spec/features/projects/members/user_requests_access_spec.rb b/spec/features/projects/members/user_requests_access_spec.rb
index 9f7327cd6e4..a77f0bdcbe9 100644
--- a/spec/features/projects/members/user_requests_access_spec.rb
+++ b/spec/features/projects/members/user_requests_access_spec.rb
@@ -4,7 +4,7 @@ require 'spec_helper'
describe 'Projects > Members > User requests access', :js do
let(:user) { create(:user) }
- let(:project) { create(:project, :public, :access_requestable, :repository) }
+ let(:project) { create(:project, :public, :repository) }
let(:maintainer) { project.owner }
before do
diff --git a/spec/finders/access_requests_finder_spec.rb b/spec/finders/access_requests_finder_spec.rb
index 4c67087b50f..fbfc8035bcc 100644
--- a/spec/finders/access_requests_finder_spec.rb
+++ b/spec/finders/access_requests_finder_spec.rb
@@ -7,13 +7,13 @@ describe AccessRequestsFinder do
let(:access_requester) { create(:user) }
let(:project) do
- create(:project, :public, :access_requestable) do |project|
+ create(:project, :public) do |project|
project.request_access(access_requester)
end
end
let(:group) do
- create(:group, :public, :access_requestable) do |group|
+ create(:group, :public) do |group|
group.request_access(access_requester)
end
end
diff --git a/spec/finders/group_members_finder_spec.rb b/spec/finders/group_members_finder_spec.rb
index 12f92f6b5b0..08f3b4024b3 100644
--- a/spec/finders/group_members_finder_spec.rb
+++ b/spec/finders/group_members_finder_spec.rb
@@ -4,7 +4,7 @@ require 'spec_helper'
describe GroupMembersFinder, '#execute' do
let(:group) { create(:group) }
- let(:nested_group) { create(:group, :access_requestable, parent: group) }
+ let(:nested_group) { create(:group, parent: group) }
let(:user1) { create(:user) }
let(:user2) { create(:user) }
let(:user3) { create(:user) }
diff --git a/spec/finders/members_finder_spec.rb b/spec/finders/members_finder_spec.rb
index 9849808c255..f9b8fee6f2d 100644
--- a/spec/finders/members_finder_spec.rb
+++ b/spec/finders/members_finder_spec.rb
@@ -4,7 +4,7 @@ require 'spec_helper'
describe MembersFinder, '#execute' do
set(:group) { create(:group) }
- set(:nested_group) { create(:group, :access_requestable, parent: group) }
+ set(:nested_group) { create(:group, parent: group) }
set(:project) { create(:project, namespace: nested_group) }
set(:user1) { create(:user) }
set(:user2) { create(:user) }
@@ -57,7 +57,7 @@ describe MembersFinder, '#execute' do
context 'when include_invited_groups_members == true' do
subject { described_class.new(project, user2).execute(include_invited_groups_members: true) }
- set(:linked_group) { create(:group, :public, :access_requestable) }
+ set(:linked_group) { create(:group, :public) }
set(:nested_linked_group) { create(:group, parent: linked_group) }
set(:linked_group_member) { linked_group.add_guest(user1) }
set(:nested_linked_group_member) { nested_linked_group.add_guest(user2) }
diff --git a/spec/frontend/ide/stores/integration_spec.js b/spec/frontend/ide/stores/integration_spec.js
new file mode 100644
index 00000000000..443de18f288
--- /dev/null
+++ b/spec/frontend/ide/stores/integration_spec.js
@@ -0,0 +1,100 @@
+import { decorateFiles } from '~/ide/lib/files';
+import { createStore } from '~/ide/stores';
+
+const TEST_BRANCH = 'test_branch';
+const TEST_NAMESPACE = 'test_namespace';
+const TEST_PROJECT_ID = `${TEST_NAMESPACE}/test_project`;
+const TEST_PATH_DIR = 'src';
+const TEST_PATH = `${TEST_PATH_DIR}/foo.js`;
+const TEST_CONTENT = `Lorem ipsum dolar sit
+Lorem ipsum dolar
+Lorem ipsum
+Lorem
+`;
+
+jest.mock('~/ide/ide_router');
+
+describe('IDE store integration', () => {
+ let store;
+
+ beforeEach(() => {
+ store = createStore();
+ store.replaceState({
+ ...store.state,
+ projects: {
+ [TEST_PROJECT_ID]: {
+ web_url: 'test_web_url',
+ branches: [],
+ },
+ },
+ currentProjectId: TEST_PROJECT_ID,
+ currentBranchId: TEST_BRANCH,
+ });
+ });
+
+ describe('with project and files', () => {
+ beforeEach(() => {
+ const { entries, treeList } = decorateFiles({
+ data: [`${TEST_PATH_DIR}/`, TEST_PATH, 'README.md'],
+ projectId: TEST_PROJECT_ID,
+ branchId: TEST_BRANCH,
+ });
+
+ Object.assign(entries[TEST_PATH], {
+ raw: TEST_CONTENT,
+ });
+
+ store.replaceState({
+ ...store.state,
+ trees: {
+ [`${TEST_PROJECT_ID}/${TEST_BRANCH}`]: {
+ tree: treeList,
+ },
+ },
+ entries,
+ });
+ });
+
+ describe('when a file is deleted and readded', () => {
+ beforeEach(() => {
+ store.dispatch('deleteEntry', TEST_PATH);
+ store.dispatch('createTempEntry', { name: TEST_PATH, type: 'blob' });
+ });
+
+ it('has changed and staged', () => {
+ expect(store.state.changedFiles).toEqual([
+ expect.objectContaining({
+ path: TEST_PATH,
+ tempFile: true,
+ deleted: false,
+ }),
+ ]);
+
+ expect(store.state.stagedFiles).toEqual([
+ expect.objectContaining({
+ path: TEST_PATH,
+ deleted: true,
+ }),
+ ]);
+ });
+
+ it('cleans up after commit', () => {
+ const expected = expect.objectContaining({
+ path: TEST_PATH,
+ staged: false,
+ changed: false,
+ tempFile: false,
+ deleted: false,
+ });
+ store.dispatch('stageChange', TEST_PATH);
+
+ store.dispatch('commit/updateFilesAfterCommit', { data: {} });
+
+ expect(store.state.entries[TEST_PATH]).toEqual(expected);
+ expect(store.state.entries[TEST_PATH_DIR].tree.find(x => x.path === TEST_PATH)).toEqual(
+ expected,
+ );
+ });
+ });
+ });
+});
diff --git a/spec/frontend/registry/components/app_spec.js b/spec/frontend/registry/components/app_spec.js
index 190af5c11cd..5dcb61e03b5 100644
--- a/spec/frontend/registry/components/app_spec.js
+++ b/spec/frontend/registry/components/app_spec.js
@@ -1,5 +1,5 @@
-import registry from '~/registry/components/app.vue';
import { mount } from '@vue/test-utils';
+import registry from '~/registry/components/app.vue';
import { TEST_HOST } from '../../helpers/test_constants';
import { reposServerResponse, parsedReposServerResponse } from '../mock_data';
@@ -8,6 +8,7 @@ describe('Registry List', () => {
const findCollapsibleContainer = w => w.findAll({ name: 'CollapsibeContainerRegisty' });
const findNoContainerImagesText = w => w.find('.js-no-container-images-text');
+ const findNotLoggedInToRegistryText = w => w.find('.js-not-logged-in-to-registry-text');
const findSpinner = w => w.find('.gl-spinner');
const findCharacterErrorText = w => w.find('.js-character-error-text');
@@ -17,6 +18,9 @@ describe('Registry List', () => {
noContainersImage: 'foo',
containersErrorImage: 'foo',
repositoryUrl: 'foo',
+ registryHostUrlWithPort: 'foo',
+ personalAccessTokensHelpLink: 'foo',
+ twoFactorAuthHelpLink: 'foo',
};
const setMainEndpoint = jest.fn();
@@ -67,6 +71,13 @@ describe('Registry List', () => {
'With the Container Registry, every project can have its own space to store its Docker images. More Information',
);
});
+
+ it('should render login help text', () => {
+ const notLoggedInToRegistryText = findNotLoggedInToRegistryText(localWrapper);
+ expect(notLoggedInToRegistryText.text()).toEqual(
+ 'If you are not already logged in, you need to authenticate to the Container Registry by using your GitLab username and password. If you have Two-Factor Authentication enabled, use a Personal Access Token instead of a password.',
+ );
+ });
});
describe('while loading data', () => {
diff --git a/spec/frontend/vue_mr_widget/components/artifacts_list_app_spec.js b/spec/frontend/vue_mr_widget/components/artifacts_list_app_spec.js
index 49ed796d9a8..7d593a77bf3 100644
--- a/spec/frontend/vue_mr_widget/components/artifacts_list_app_spec.js
+++ b/spec/frontend/vue_mr_widget/components/artifacts_list_app_spec.js
@@ -44,6 +44,7 @@ describe('Merge Requests Artifacts list app', () => {
const findButtons = () => wrapper.findAll('button');
const findTitle = () => wrapper.find('.js-title');
+ const findErrorMessage = () => wrapper.find('.js-error-state');
const findTableRows = () => wrapper.findAll('tbody tr');
describe('while loading', () => {
@@ -109,13 +110,12 @@ describe('Merge Requests Artifacts list app', () => {
});
it('renders the error state', () => {
- expect(findTitle().text()).toBe('An error occurred while fetching the artifacts');
+ expect(findErrorMessage().text()).toBe('An error occurred while fetching the artifacts');
});
- it('renders disabled buttons', () => {
+ it('does not render buttons', () => {
const buttons = findButtons();
- expect(buttons.at(0).attributes('disabled')).toBe('disabled');
- expect(buttons.at(1).attributes('disabled')).toBe('disabled');
+ expect(buttons.exists()).toBe(false);
});
});
});
diff --git a/spec/frontend/vue_mr_widget/components/mr_collapsible_extension_spec.js b/spec/frontend/vue_mr_widget/components/mr_collapsible_extension_spec.js
index 4c9507223a1..ee107f297ef 100644
--- a/spec/frontend/vue_mr_widget/components/mr_collapsible_extension_spec.js
+++ b/spec/frontend/vue_mr_widget/components/mr_collapsible_extension_spec.js
@@ -20,6 +20,7 @@ describe('Merge Request Collapsible Extension', () => {
};
const findTitle = () => wrapper.find('.js-title');
+ const findErrorMessage = () => wrapper.find('.js-error-state');
afterEach(() => {
wrapper.destroy();
@@ -87,19 +88,12 @@ describe('Merge Request Collapsible Extension', () => {
mountComponent(Object.assign({}, data, { hasError: true }));
});
- it('renders the buttons disabled', () => {
- expect(
- wrapper
- .findAll('button')
- .at(0)
- .attributes('disabled'),
- ).toEqual('disabled');
- expect(
- wrapper
- .findAll('button')
- .at(1)
- .attributes('disabled'),
- ).toEqual('disabled');
+ it('does not render the buttons', () => {
+ expect(wrapper.findAll('button').exists()).toBe(false);
+ });
+
+ it('renders title message provided', () => {
+ expect(findErrorMessage().text()).toBe(data.title);
});
});
});
diff --git a/spec/helpers/members_helper_spec.rb b/spec/helpers/members_helper_spec.rb
index e52d2166a69..169c8707bf4 100644
--- a/spec/helpers/members_helper_spec.rb
+++ b/spec/helpers/members_helper_spec.rb
@@ -5,11 +5,11 @@ require 'spec_helper'
describe MembersHelper do
describe '#remove_member_message' do
let(:requester) { create(:user) }
- let(:project) { create(:project, :public, :access_requestable) }
+ let(:project) { create(:project, :public) }
let(:project_member) { build(:project_member, project: project) }
let(:project_member_invite) { build(:project_member, project: project).tap { |m| m.generate_invite_token! } }
let(:project_member_request) { project.request_access(requester) }
- let(:group) { create(:group, :access_requestable) }
+ let(:group) { create(:group) }
let(:group_member) { build(:group_member, group: group) }
let(:group_member_invite) { build(:group_member, group: group).tap { |m| m.generate_invite_token! } }
let(:group_member_request) { group.request_access(requester) }
@@ -26,10 +26,10 @@ describe MembersHelper do
describe '#remove_member_title' do
let(:requester) { create(:user) }
- let(:project) { create(:project, :public, :access_requestable) }
+ let(:project) { create(:project, :public) }
let(:project_member) { build(:project_member, project: project) }
let(:project_member_request) { project.request_access(requester) }
- let(:group) { create(:group, :access_requestable) }
+ let(:group) { create(:group) }
let(:group_member) { build(:group_member, group: group) }
let(:group_member_request) { group.request_access(requester) }
diff --git a/spec/lib/gitlab/health_checks/puma_check_spec.rb b/spec/lib/gitlab/health_checks/puma_check_spec.rb
new file mode 100644
index 00000000000..71b6386b174
--- /dev/null
+++ b/spec/lib/gitlab/health_checks/puma_check_spec.rb
@@ -0,0 +1,65 @@
+require 'spec_helper'
+
+describe Gitlab::HealthChecks::PumaCheck do
+ let(:result_class) { Gitlab::HealthChecks::Result }
+ let(:readiness) { described_class.readiness }
+ let(:metrics) { described_class.metrics }
+
+ shared_examples 'with state' do |(state, message)|
+ it "does provide readiness" do
+ expect(readiness).to eq(result_class.new('puma_check', state, message))
+ end
+
+ it "does provide metrics" do
+ expect(metrics).to include(
+ an_object_having_attributes(name: 'puma_check_success', value: state ? 1 : 0))
+ expect(metrics).to include(
+ an_object_having_attributes(name: 'puma_check_latency_seconds', value: be >= 0))
+ end
+ end
+
+ context 'when Puma is not loaded' do
+ before do
+ hide_const('Puma')
+ end
+
+ it "does not provide readiness and metrics" do
+ expect(readiness).to be_nil
+ expect(metrics).to be_nil
+ end
+ end
+
+ context 'when Puma is loaded' do
+ before do
+ stub_const('Puma', Module.new)
+ end
+
+ context 'when stats are missing' do
+ before do
+ expect(Puma).to receive(:stats).and_raise(NoMethodError)
+ end
+
+ it_behaves_like 'with state', [false, 'unexpected Puma check result: 0']
+ end
+
+ context 'for Single mode' do
+ before do
+ expect(Puma).to receive(:stats) do
+ '{}'
+ end
+ end
+
+ it_behaves_like 'with state', true
+ end
+
+ context 'for Cluster mode' do
+ before do
+ expect(Puma).to receive(:stats) do
+ '{"workers":2}'
+ end
+ end
+
+ it_behaves_like 'with state', true
+ end
+ end
+end
diff --git a/spec/lib/gitlab/health_checks/unicorn_check_spec.rb b/spec/lib/gitlab/health_checks/unicorn_check_spec.rb
new file mode 100644
index 00000000000..c02d0c37738
--- /dev/null
+++ b/spec/lib/gitlab/health_checks/unicorn_check_spec.rb
@@ -0,0 +1,63 @@
+require 'spec_helper'
+
+describe Gitlab::HealthChecks::UnicornCheck do
+ let(:result_class) { Gitlab::HealthChecks::Result }
+ let(:readiness) { described_class.readiness }
+ let(:metrics) { described_class.metrics }
+
+ before do
+ described_class.clear_memoization(:http_servers)
+ end
+
+ shared_examples 'with state' do |(state, message)|
+ it "does provide readiness" do
+ expect(readiness).to eq(result_class.new('unicorn_check', state, message))
+ end
+
+ it "does provide metrics" do
+ expect(metrics).to include(
+ an_object_having_attributes(name: 'unicorn_check_success', value: state ? 1 : 0))
+ expect(metrics).to include(
+ an_object_having_attributes(name: 'unicorn_check_latency_seconds', value: be >= 0))
+ end
+ end
+
+ context 'when Unicorn is not loaded' do
+ before do
+ hide_const('Unicorn')
+ end
+
+ it "does not provide readiness and metrics" do
+ expect(readiness).to be_nil
+ expect(metrics).to be_nil
+ end
+ end
+
+ context 'when Unicorn is loaded' do
+ let(:http_server_class) { Struct.new(:worker_processes) }
+
+ before do
+ stub_const('Unicorn::HttpServer', http_server_class)
+ end
+
+ context 'when no servers are running' do
+ it_behaves_like 'with state', [false, 'unexpected Unicorn check result: 0']
+ end
+
+ context 'when servers without workers are running' do
+ before do
+ http_server_class.new(0)
+ end
+
+ it_behaves_like 'with state', [false, 'unexpected Unicorn check result: 0']
+ end
+
+ context 'when servers with workers are running' do
+ before do
+ http_server_class.new(1)
+ end
+
+ it_behaves_like 'with state', true
+ end
+ end
+end
diff --git a/spec/lib/gitlab/metrics/exporter/base_exporter_spec.rb b/spec/lib/gitlab/metrics/exporter/base_exporter_spec.rb
index bedf4fedcfa..0376da13595 100644
--- a/spec/lib/gitlab/metrics/exporter/base_exporter_spec.rb
+++ b/spec/lib/gitlab/metrics/exporter/base_exporter_spec.rb
@@ -64,6 +64,18 @@ describe Gitlab::Metrics::Exporter::BaseExporter do
exporter.start.join
end
end
+
+ describe 'when thread is not alive' do
+ it 'does close listeners' do
+ expect_any_instance_of(::WEBrick::HTTPServer).to receive(:start)
+ expect_any_instance_of(::WEBrick::HTTPServer).to receive(:listeners)
+ .and_call_original
+
+ expect { exporter.start.join }.to change { exporter.thread? }.from(false).to(true)
+
+ exporter.stop
+ end
+ end
end
describe '#stop' do
diff --git a/spec/mailers/notify_spec.rb b/spec/mailers/notify_spec.rb
index 56fa26d5f23..1991bac0229 100644
--- a/spec/mailers/notify_spec.rb
+++ b/spec/mailers/notify_spec.rb
@@ -714,7 +714,7 @@ describe Notify do
describe 'project access requested' do
let(:project) do
- create(:project, :public, :access_requestable) do |project|
+ create(:project, :public) do |project|
project.add_maintainer(project.owner)
end
end
@@ -743,7 +743,7 @@ describe Notify do
end
describe 'project access denied' do
- let(:project) { create(:project, :public, :access_requestable) }
+ let(:project) { create(:project, :public) }
let(:project_member) do
project.request_access(user)
project.requesters.find_by(user_id: user.id)
@@ -765,7 +765,7 @@ describe Notify do
describe 'project access changed' do
let(:owner) { create(:user, name: "Chang O'Keefe") }
- let(:project) { create(:project, :public, :access_requestable, namespace: owner.namespace) }
+ let(:project) { create(:project, :public, namespace: owner.namespace) }
let(:project_member) { create(:project_member, project: project, user: user) }
subject { described_class.member_access_granted_email('project', project_member.id) }
@@ -1167,7 +1167,7 @@ describe Notify do
context 'for a group' do
describe 'group access requested' do
- let(:group) { create(:group, :public, :access_requestable) }
+ let(:group) { create(:group, :public) }
let(:group_member) do
group.request_access(user)
group.requesters.find_by(user_id: user.id)
diff --git a/spec/models/ci/build_metadata_spec.rb b/spec/models/ci/build_metadata_spec.rb
index 67cd939b4c6..da95a2d30f5 100644
--- a/spec/models/ci/build_metadata_spec.rb
+++ b/spec/models/ci/build_metadata_spec.rb
@@ -4,7 +4,7 @@ require 'spec_helper'
describe Ci::BuildMetadata do
set(:user) { create(:user) }
- set(:group) { create(:group, :access_requestable) }
+ set(:group) { create(:group) }
set(:project) { create(:project, :repository, group: group, build_timeout: 2000) }
set(:pipeline) do
diff --git a/spec/models/ci/build_spec.rb b/spec/models/ci/build_spec.rb
index 15281c9e826..26646085921 100644
--- a/spec/models/ci/build_spec.rb
+++ b/spec/models/ci/build_spec.rb
@@ -4,7 +4,7 @@ require 'spec_helper'
describe Ci::Build do
set(:user) { create(:user) }
- set(:group) { create(:group, :access_requestable) }
+ set(:group) { create(:group) }
set(:project) { create(:project, :repository, group: group) }
set(:pipeline) do
diff --git a/spec/models/concerns/access_requestable_spec.rb b/spec/models/concerns/access_requestable_spec.rb
index de2bc3a387b..5c1694e3737 100644
--- a/spec/models/concerns/access_requestable_spec.rb
+++ b/spec/models/concerns/access_requestable_spec.rb
@@ -5,7 +5,7 @@ require 'spec_helper'
describe AccessRequestable do
describe 'Group' do
describe '#request_access' do
- let(:group) { create(:group, :public, :access_requestable) }
+ let(:group) { create(:group, :public) }
let(:user) { create(:user) }
it { expect(group.request_access(user)).to be_a(GroupMember) }
@@ -13,7 +13,7 @@ describe AccessRequestable do
end
describe '#access_requested?' do
- let(:group) { create(:group, :public, :access_requestable) }
+ let(:group) { create(:group, :public) }
let(:user) { create(:user) }
before do
@@ -26,14 +26,14 @@ describe AccessRequestable do
describe 'Project' do
describe '#request_access' do
- let(:project) { create(:project, :public, :access_requestable) }
+ let(:project) { create(:project, :public) }
let(:user) { create(:user) }
it { expect(project.request_access(user)).to be_a(ProjectMember) }
end
describe '#access_requested?' do
- let(:project) { create(:project, :public, :access_requestable) }
+ let(:project) { create(:project, :public) }
let(:user) { create(:user) }
before do
diff --git a/spec/models/group_spec.rb b/spec/models/group_spec.rb
index 3f149f9d7ee..892c31a9204 100644
--- a/spec/models/group_spec.rb
+++ b/spec/models/group_spec.rb
@@ -3,7 +3,7 @@
require 'spec_helper'
describe Group do
- let!(:group) { create(:group, :access_requestable) }
+ let!(:group) { create(:group) }
describe 'associations' do
it { is_expected.to have_many :projects }
@@ -331,7 +331,7 @@ describe Group do
end
describe '#avatar_url' do
- let!(:group) { create(:group, :access_requestable, :with_avatar) }
+ let!(:group) { create(:group, :with_avatar) }
let(:user) { create(:user) }
context 'when avatar file is uploaded' do
diff --git a/spec/models/member_spec.rb b/spec/models/member_spec.rb
index 2cb4f222ea4..e7f03226826 100644
--- a/spec/models/member_spec.rb
+++ b/spec/models/member_spec.rb
@@ -92,7 +92,7 @@ describe Member do
describe 'Scopes & finders' do
before do
- project = create(:project, :public, :access_requestable)
+ project = create(:project, :public)
group = create(:group)
@owner_user = create(:user).tap { |u| group.add_owner(u) }
@owner = group.members.find_by(user_id: @owner_user.id)
@@ -230,7 +230,7 @@ describe Member do
describe '.add_user' do
%w[project group].each do |source_type|
context "when source is a #{source_type}" do
- let!(:source) { create(source_type, :public, :access_requestable) }
+ let!(:source) { create(source_type, :public) }
let!(:user) { create(:user) }
let!(:admin) { create(:admin) }
@@ -437,7 +437,7 @@ describe Member do
describe '.add_users' do
%w[project group].each do |source_type|
context "when source is a #{source_type}" do
- let!(:source) { create(source_type, :public, :access_requestable) }
+ let!(:source) { create(source_type, :public) }
let!(:admin) { create(:admin) }
let(:user1) { create(:user) }
let(:user2) { create(:user) }
diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb
index 68833fdaf73..866003c9ffd 100644
--- a/spec/models/project_spec.rb
+++ b/spec/models/project_spec.rb
@@ -153,7 +153,7 @@ describe Project do
end
describe '#members & #requesters' do
- let(:project) { create(:project, :public, :access_requestable) }
+ let(:project) { create(:project, :public) }
let(:requester) { create(:user) }
let(:developer) { create(:user) }
before do
diff --git a/spec/models/project_team_spec.rb b/spec/models/project_team_spec.rb
index 77c88a04cde..d62fa58739a 100644
--- a/spec/models/project_team_spec.rb
+++ b/spec/models/project_team_spec.rb
@@ -141,7 +141,7 @@ describe ProjectTeam do
describe '#find_member' do
context 'personal project' do
let(:project) do
- create(:project, :public, :access_requestable)
+ create(:project, :public)
end
let(:requester) { create(:user) }
@@ -161,7 +161,7 @@ describe ProjectTeam do
end
context 'group project' do
- let(:group) { create(:group, :access_requestable) }
+ let(:group) { create(:group) }
let(:project) { create(:project, group: group) }
let(:requester) { create(:user) }
@@ -246,7 +246,7 @@ describe ProjectTeam do
context 'personal project' do
let(:project) do
- create(:project, :public, :access_requestable)
+ create(:project, :public)
end
context 'when project is not shared with group' do
@@ -292,7 +292,7 @@ describe ProjectTeam do
end
context 'group project' do
- let(:group) { create(:group, :access_requestable) }
+ let(:group) { create(:group) }
let!(:project) do
create(:project, group: group)
end
diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb
index 12292dad142..24e66fe14c3 100644
--- a/spec/models/user_spec.rb
+++ b/spec/models/user_spec.rb
@@ -79,7 +79,7 @@ describe User do
describe '#group_members' do
it 'does not include group memberships for which user is a requester' do
user = create(:user)
- group = create(:group, :public, :access_requestable)
+ group = create(:group, :public)
group.request_access(user)
expect(user.group_members).to be_empty
@@ -89,7 +89,7 @@ describe User do
describe '#project_members' do
it 'does not include project memberships for which user is a requester' do
user = create(:user)
- project = create(:project, :public, :access_requestable)
+ project = create(:project, :public)
project.request_access(user)
expect(user.project_members).to be_empty
@@ -1191,7 +1191,7 @@ describe User do
end
describe '.without_projects' do
- let!(:project) { create(:project, :public, :access_requestable) }
+ let!(:project) { create(:project, :public) }
let!(:user) { create(:user) }
let!(:user_without_project) { create(:user) }
let!(:user_without_project2) { create(:user) }
diff --git a/spec/requests/api/access_requests_spec.rb b/spec/requests/api/access_requests_spec.rb
index 1af6602ea9e..100f3d33c7b 100644
--- a/spec/requests/api/access_requests_spec.rb
+++ b/spec/requests/api/access_requests_spec.rb
@@ -7,7 +7,7 @@ describe API::AccessRequests do
set(:stranger) { create(:user) }
set(:project) do
- create(:project, :public, :access_requestable, creator_id: maintainer.id, namespace: maintainer.namespace) do |project|
+ create(:project, :public, creator_id: maintainer.id, namespace: maintainer.namespace) do |project|
project.add_developer(developer)
project.add_maintainer(maintainer)
project.request_access(access_requester)
@@ -15,7 +15,7 @@ describe API::AccessRequests do
end
set(:group) do
- create(:group, :public, :access_requestable) do |group|
+ create(:group, :public) do |group|
group.add_developer(developer)
group.add_owner(maintainer)
group.request_access(access_requester)
diff --git a/spec/requests/api/badges_spec.rb b/spec/requests/api/badges_spec.rb
index 1dd0cb4817c..771a78a2d91 100644
--- a/spec/requests/api/badges_spec.rb
+++ b/spec/requests/api/badges_spec.rb
@@ -345,7 +345,7 @@ describe API::Badges do
end
def setup_project
- create(:project, :public, :access_requestable, creator_id: maintainer.id, namespace: project_group) do |project|
+ create(:project, :public, creator_id: maintainer.id, namespace: project_group) do |project|
project.add_developer(developer)
project.add_maintainer(maintainer)
project.request_access(access_requester)
@@ -356,7 +356,7 @@ describe API::Badges do
end
def setup_group
- create(:group, :public, :access_requestable) do |group|
+ create(:group, :public) do |group|
group.add_developer(developer)
group.add_owner(maintainer)
group.request_access(access_requester)
diff --git a/spec/requests/api/members_spec.rb b/spec/requests/api/members_spec.rb
index 26f6e705528..7e67ee28bef 100644
--- a/spec/requests/api/members_spec.rb
+++ b/spec/requests/api/members_spec.rb
@@ -7,7 +7,7 @@ describe API::Members do
let(:stranger) { create(:user) }
let(:project) do
- create(:project, :public, :access_requestable, creator_id: maintainer.id, namespace: maintainer.namespace) do |project|
+ create(:project, :public, creator_id: maintainer.id, namespace: maintainer.namespace) do |project|
project.add_developer(developer)
project.add_maintainer(maintainer)
project.request_access(access_requester)
@@ -15,7 +15,7 @@ describe API::Members do
end
let!(:group) do
- create(:group, :public, :access_requestable) do |group|
+ create(:group, :public) do |group|
group.add_developer(developer)
group.add_owner(maintainer)
group.request_access(access_requester)
diff --git a/spec/services/members/approve_access_request_service_spec.rb b/spec/services/members/approve_access_request_service_spec.rb
index f56c31e51f6..5bbceac3dd0 100644
--- a/spec/services/members/approve_access_request_service_spec.rb
+++ b/spec/services/members/approve_access_request_service_spec.rb
@@ -3,8 +3,8 @@
require 'spec_helper'
describe Members::ApproveAccessRequestService do
- let(:project) { create(:project, :public, :access_requestable) }
- let(:group) { create(:group, :public, :access_requestable) }
+ let(:project) { create(:project, :public) }
+ let(:group) { create(:group, :public) }
let(:current_user) { create(:user) }
let(:access_requester_user) { create(:user) }
let(:access_requester) { source.requesters.find_by!(user_id: access_requester_user.id) }
diff --git a/spec/services/members/request_access_service_spec.rb b/spec/services/members/request_access_service_spec.rb
index 2e5275eb3f2..a0f7ae91bdb 100644
--- a/spec/services/members/request_access_service_spec.rb
+++ b/spec/services/members/request_access_service_spec.rb
@@ -41,7 +41,7 @@ describe Members::RequestAccessService do
context 'when access requests are disabled' do
%i[project group].each do |source_type|
it_behaves_like 'a service raising Gitlab::Access::AccessDeniedError' do
- let(:source) { create(source_type, :public) }
+ let(:source) { create(source_type, :public, :request_access_disabled) }
end
end
end
@@ -49,7 +49,7 @@ describe Members::RequestAccessService do
context 'when current user can request access to the project' do
%i[project group].each do |source_type|
it_behaves_like 'a service creating a access request' do
- let(:source) { create(source_type, :public, :access_requestable) }
+ let(:source) { create(source_type, :public) }
end
end
end
diff --git a/spec/services/notification_service_spec.rb b/spec/services/notification_service_spec.rb
index bd6734634cb..70ce05927b4 100644
--- a/spec/services/notification_service_spec.rb
+++ b/spec/services/notification_service_spec.rb
@@ -1942,7 +1942,7 @@ describe NotificationService, :mailer do
let(:developer) { create(:user) }
let!(:group) do
- create(:group, :public, :access_requestable) do |group|
+ create(:group, :public) do |group|
group.add_owner(owner)
group.add_maintainer(maintainer)
group.add_developer(developer)
@@ -1968,7 +1968,7 @@ describe NotificationService, :mailer do
end
it_behaves_like 'sends notification only to a maximum of ten, most recently active group owners' do
- let(:group) { create(:group, :public, :access_requestable) }
+ let(:group) { create(:group, :public) }
let(:notification_trigger) { group.request_access(added_user) }
end
end
@@ -2029,7 +2029,7 @@ describe NotificationService, :mailer do
let(:maintainer) { create(:user) }
let!(:project) do
- create(:project, :public, :access_requestable) do |project|
+ create(:project, :public) do |project|
project.add_developer(developer)
project.add_maintainer(maintainer)
end
@@ -2053,7 +2053,7 @@ describe NotificationService, :mailer do
end
it_behaves_like 'sends notification only to a maximum of ten, most recently active project maintainers' do
- let(:project) { create(:project, :public, :access_requestable) }
+ let(:project) { create(:project, :public) }
let(:notification_trigger) { project.request_access(added_user) }
end
end
@@ -2064,7 +2064,7 @@ describe NotificationService, :mailer do
context 'when the project has no maintainers' do
context 'when the group has at least one owner' do
- let!(:project) { create(:project, :public, :access_requestable, namespace: group) }
+ let!(:project) { create(:project, :public, namespace: group) }
before do
reset_delivered_emails!
@@ -2079,14 +2079,14 @@ describe NotificationService, :mailer do
end
it_behaves_like 'sends notification only to a maximum of ten, most recently active group owners' do
- let(:group) { create(:group, :public, :access_requestable) }
+ let(:group) { create(:group, :public) }
let(:notification_trigger) { project.request_access(added_user) }
end
end
context 'when the group does not have any owners' do
let(:group) { create(:group) }
- let!(:project) { create(:project, :public, :access_requestable, namespace: group) }
+ let!(:project) { create(:project, :public, namespace: group) }
context 'recipients' do
before do
@@ -2107,7 +2107,7 @@ describe NotificationService, :mailer do
let(:developer) { create(:user) }
let!(:project) do
- create(:project, :public, :access_requestable, namespace: group) do |project|
+ create(:project, :public, namespace: group) do |project|
project.add_maintainer(maintainer)
project.add_developer(developer)
end
@@ -2128,7 +2128,7 @@ describe NotificationService, :mailer do
end
it_behaves_like 'sends notification only to a maximum of ten, most recently active project maintainers' do
- let(:project) { create(:project, :public, :access_requestable, namespace: group) }
+ let(:project) { create(:project, :public, namespace: group) }
let(:notification_trigger) { project.request_access(added_user) }
end
end
diff --git a/spec/services/projects/container_repository/cleanup_tags_service_spec.rb b/spec/services/projects/container_repository/cleanup_tags_service_spec.rb
index 14247f1c71e..14772d172e8 100644
--- a/spec/services/projects/container_repository/cleanup_tags_service_spec.rb
+++ b/spec/services/projects/container_repository/cleanup_tags_service_spec.rb
@@ -157,6 +157,6 @@ describe Projects::ContainerRepository::CleanupTagsService do
def expect_delete(digest)
expect_any_instance_of(ContainerRegistry::Client)
.to receive(:delete_repository_tag)
- .with(repository.path, digest)
+ .with(repository.path, digest) { true }
end
end
diff --git a/spec/services/projects/container_repository/delete_tags_service_spec.rb b/spec/services/projects/container_repository/delete_tags_service_spec.rb
index 2ec5850c69e..f296ef3a776 100644
--- a/spec/services/projects/container_repository/delete_tags_service_spec.rb
+++ b/spec/services/projects/container_repository/delete_tags_service_spec.rb
@@ -87,6 +87,21 @@ describe Projects::ContainerRepository::DeleteTagsService do
is_expected.to include(status: :success)
end
+
+ it 'succedes when tag delete returns 404' do
+ stub_upload("{\n \"config\": {\n }\n}", 'sha256:4435000728ee66e6a80e55637fc22725c256b61de344a2ecdeaac6bdb36e8bc3')
+
+ stub_request(:put, "http://registry.gitlab/v2/#{repository.path}/manifests/A")
+ .to_return(status: 200, body: "", headers: { 'docker-content-digest' => 'sha256:dummy' })
+
+ stub_request(:put, "http://registry.gitlab/v2/#{repository.path}/manifests/Ba")
+ .to_return(status: 200, body: "", headers: { 'docker-content-digest' => 'sha256:dummy' })
+
+ stub_request(:delete, "http://registry.gitlab/v2/#{repository.path}/manifests/sha256:dummy")
+ .to_return(status: 404, body: "", headers: {})
+
+ is_expected.to include(status: :success)
+ end
end
end
end