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

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2021-04-10 03:09:11 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2021-04-10 03:09:11 +0300
commit89cb3fa7748cad1d71417bcd5b69bf30b94c25b5 (patch)
treed1109effbce81cadbb3009b937f629be94113795
parent017841e3c03105efd0b94e730652c5774f2c136f (diff)
Add latest changes from gitlab-org/gitlab@master
-rw-r--r--.gitlab-ci.yml1
-rw-r--r--.gitlab/ci/rules.gitlab-ci.yml10
-rw-r--r--.gitlab/ci/vendored-gems.gitlab-ci.yml7
-rw-r--r--Gemfile1
-rw-r--r--Gemfile.lock8
-rw-r--r--app/assets/javascripts/ci_variable_list/components/ci_variable_modal.vue15
-rw-r--r--app/assets/javascripts/ci_variable_list/components/ci_variable_table.vue4
-rw-r--r--app/assets/javascripts/contributors/index.js9
-rw-r--r--app/assets/javascripts/contributors/stores/index.js6
-rw-r--r--app/assets/javascripts/contributors/stores/state.js4
-rw-r--r--app/assets/javascripts/performance_bar/components/request_selector.vue8
-rw-r--r--app/assets/javascripts/performance_bar/components/request_warning.vue4
-rw-r--r--app/controllers/groups/settings/ci_cd_controller.rb12
-rw-r--r--app/controllers/groups/variables_controller.rb2
-rw-r--r--app/models/group.rb2
-rw-r--r--app/serializers/ci/group_variable_entity.rb1
-rw-r--r--app/views/projects/graphs/show.html.haml2
-rw-r--r--changelogs/unreleased/230717-add-mail-smtp-pool-gem.yml5
-rw-r--r--changelogs/unreleased/pb-popover-improvement.yml5
-rw-r--r--config/initializers/smtp_settings.rb.sample25
-rw-r--r--doc/api/usage_data.md50
-rw-r--r--spec/frontend/ci_variable_list/components/ci_variable_modal_spec.js61
-rw-r--r--spec/frontend/ci_variable_list/components/ci_variable_table_spec.js20
-rw-r--r--spec/serializers/ci/group_variable_entity_spec.rb2
-rw-r--r--vendor/gems/mail-smtp_pool/.gitignore3
-rw-r--r--vendor/gems/mail-smtp_pool/.gitlab-ci.yml29
-rw-r--r--vendor/gems/mail-smtp_pool/Gemfile5
-rw-r--r--vendor/gems/mail-smtp_pool/LICENSE21
-rw-r--r--vendor/gems/mail-smtp_pool/README.md57
-rw-r--r--vendor/gems/mail-smtp_pool/lib/mail/smtp_pool.rb34
-rw-r--r--vendor/gems/mail-smtp_pool/lib/mail/smtp_pool/connection.rb60
-rw-r--r--vendor/gems/mail-smtp_pool/mail-smtp_pool.gemspec26
-rw-r--r--vendor/gems/mail-smtp_pool/spec/lib/mail/smtp_pool/connection_spec.rb93
-rw-r--r--vendor/gems/mail-smtp_pool/spec/lib/mail/smtp_pool_spec.rb68
-rw-r--r--vendor/gems/mail-smtp_pool/spec/spec_helper.rb84
35 files changed, 715 insertions, 29 deletions
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 423a62b159b..c722f0a597d 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -102,6 +102,7 @@ include:
- local: .gitlab/ci/qa.gitlab-ci.yml
- local: .gitlab/ci/reports.gitlab-ci.yml
- local: .gitlab/ci/rails.gitlab-ci.yml
+ - local: .gitlab/ci/vendored-gems.gitlab-ci.yml
- local: .gitlab/ci/review.gitlab-ci.yml
- local: .gitlab/ci/rules.gitlab-ci.yml
- local: .gitlab/ci/setup.gitlab-ci.yml
diff --git a/.gitlab/ci/rules.gitlab-ci.yml b/.gitlab/ci/rules.gitlab-ci.yml
index 8062f3d59cb..5dc156fbcaa 100644
--- a/.gitlab/ci/rules.gitlab-ci.yml
+++ b/.gitlab/ci/rules.gitlab-ci.yml
@@ -920,6 +920,16 @@
- <<: *if-merge-request
changes: [".gitlab/ci/rails.gitlab-ci.yml"]
+#######################
+# Vendored gems rules #
+#######################
+
+.vendor:rules:mail-smtp_pool:
+ rules:
+ - <<: *if-merge-request
+ changes: ["vendor/gems/mail-smtp_pool/**/*"]
+ - <<: *if-merge-request-title-run-all-rspec
+
##################
# Releases rules #
##################
diff --git a/.gitlab/ci/vendored-gems.gitlab-ci.yml b/.gitlab/ci/vendored-gems.gitlab-ci.yml
new file mode 100644
index 00000000000..a39c4307c13
--- /dev/null
+++ b/.gitlab/ci/vendored-gems.gitlab-ci.yml
@@ -0,0 +1,7 @@
+vendor mail-smtp_pool:
+ extends:
+ - .vendor:rules:mail-smtp_pool
+ needs: []
+ trigger:
+ include: vendor/gems/mail-smtp_pool/.gitlab-ci.yml
+ strategy: depend
diff --git a/Gemfile b/Gemfile
index 1ca67840692..759d0cb3047 100644
--- a/Gemfile
+++ b/Gemfile
@@ -511,6 +511,7 @@ gem 'erubi', '~> 1.9.0'
# Monkey-patched in `config/initializers/mail_encoding_patch.rb`
# See https://gitlab.com/gitlab-org/gitlab/issues/197386
gem 'mail', '= 2.7.1'
+gem 'mail-smtp_pool', '~> 0.1.0', path: 'vendor/gems/mail-smtp_pool', require: false
# File encryption
gem 'lockbox', '~> 0.6.2'
diff --git a/Gemfile.lock b/Gemfile.lock
index 724412fa8ed..b587b0f77c6 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -1,4 +1,11 @@
PATH
+ remote: vendor/gems/mail-smtp_pool
+ specs:
+ mail-smtp_pool (0.1.0)
+ connection_pool (~> 2.0)
+ mail (~> 2.7)
+
+PATH
remote: vendor/shims/mimemagic
specs:
mimemagic (0.3.7)
@@ -1483,6 +1490,7 @@ DEPENDENCIES
loofah (~> 2.2)
lru_redux
mail (= 2.7.1)
+ mail-smtp_pool (~> 0.1.0)!
marginalia (~> 1.10.0)
memory_profiler (~> 0.9)
method_source (~> 1.0)
diff --git a/app/assets/javascripts/ci_variable_list/components/ci_variable_modal.vue b/app/assets/javascripts/ci_variable_list/components/ci_variable_modal.vue
index be7c0b68b4c..e520b9b8b92 100644
--- a/app/assets/javascripts/ci_variable_list/components/ci_variable_modal.vue
+++ b/app/assets/javascripts/ci_variable_list/components/ci_variable_modal.vue
@@ -7,6 +7,7 @@ import {
GlFormCombobox,
GlFormGroup,
GlFormSelect,
+ GlFormInput,
GlFormTextarea,
GlIcon,
GlLink,
@@ -41,6 +42,7 @@ export default {
GlFormCombobox,
GlFormGroup,
GlFormSelect,
+ GlFormInput,
GlFormTextarea,
GlIcon,
GlLink,
@@ -128,6 +130,12 @@ export default {
return true;
},
+ scopedVariablesEnabled() {
+ return !this.isGroup || this.glFeatures.scopedGroupVariables;
+ },
+ scopedVariablesAvailable() {
+ return !this.isGroup || this.glFeatures.groupScopedCiVariables;
+ },
variableValidationFeedback() {
return `${this.tokenValidationFeedback} ${this.maskedFeedback}`;
},
@@ -226,24 +234,27 @@ export default {
:label="__('Type')"
label-for="ci-variable-type"
class="w-50 gl-mr-5"
- :class="{ 'w-100': isGroup }"
+ :class="{ 'w-100': !scopedVariablesEnabled }"
>
<gl-form-select id="ci-variable-type" v-model="variable_type" :options="typeOptions" />
</gl-form-group>
<gl-form-group
- v-if="!isGroup"
+ v-if="scopedVariablesEnabled"
:label="__('Environment scope')"
label-for="ci-variable-env"
class="w-50"
data-testid="environment-scope"
>
<ci-environments-dropdown
+ v-if="scopedVariablesAvailable"
class="w-100"
:value="environment_scope"
@selectEnvironment="setEnvironmentScope"
@createClicked="addWildCardScope"
/>
+
+ <gl-form-input v-else v-model="environment_scope" class="w-100" readonly />
</gl-form-group>
</div>
diff --git a/app/assets/javascripts/ci_variable_list/components/ci_variable_table.vue b/app/assets/javascripts/ci_variable_list/components/ci_variable_table.vue
index c9943052356..c5f47cf8e84 100644
--- a/app/assets/javascripts/ci_variable_list/components/ci_variable_table.vue
+++ b/app/assets/javascripts/ci_variable_list/components/ci_variable_table.vue
@@ -2,6 +2,7 @@
import { GlTable, GlButton, GlModalDirective, GlIcon } from '@gitlab/ui';
import { mapState, mapActions } from 'vuex';
import { s__, __ } from '~/locale';
+import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
import { ADD_CI_VARIABLE_MODAL_ID } from '../constants';
import CiVariablePopover from './ci_variable_popover.vue';
@@ -59,6 +60,7 @@ export default {
directives: {
GlModalDirective,
},
+ mixins: [glFeatureFlagsMixin()],
computed: {
...mapState(['variables', 'valuesHidden', 'isGroup', 'isLoading', 'isDeleting']),
valuesButtonText() {
@@ -68,7 +70,7 @@ export default {
return this.variables && this.variables.length > 0;
},
fields() {
- if (this.isGroup) {
+ if (this.isGroup && !this.glFeatures.scopedGroupVariables) {
return this.$options.fields.filter((field) => field.key !== 'environment_scope');
}
return this.$options.fields;
diff --git a/app/assets/javascripts/contributors/index.js b/app/assets/javascripts/contributors/index.js
index b6063589734..f66133a074d 100644
--- a/app/assets/javascripts/contributors/index.js
+++ b/app/assets/javascripts/contributors/index.js
@@ -1,12 +1,15 @@
import Vue from 'vue';
import ContributorsGraphs from './components/contributors.vue';
-import store from './stores';
+import { createStore } from './stores';
export default () => {
const el = document.querySelector('.js-contributors-graph');
if (!el) return null;
+ const { projectGraphPath, projectBranch, defaultBranch } = el.dataset;
+ const store = createStore(defaultBranch);
+
return new Vue({
el,
store,
@@ -14,8 +17,8 @@ export default () => {
render(createElement) {
return createElement(ContributorsGraphs, {
props: {
- endpoint: el.dataset.projectGraphPath,
- branch: el.dataset.projectBranch,
+ endpoint: projectGraphPath,
+ branch: projectBranch,
},
});
},
diff --git a/app/assets/javascripts/contributors/stores/index.js b/app/assets/javascripts/contributors/stores/index.js
index 38259f46d4c..a4d0004cee5 100644
--- a/app/assets/javascripts/contributors/stores/index.js
+++ b/app/assets/javascripts/contributors/stores/index.js
@@ -7,12 +7,12 @@ import state from './state';
Vue.use(Vuex);
-export const createStore = () =>
+export const createStore = (defaultBranch) =>
new Vuex.Store({
actions,
mutations,
getters,
- state: state(),
+ state: state(defaultBranch),
});
-export default createStore();
+export default createStore;
diff --git a/app/assets/javascripts/contributors/stores/state.js b/app/assets/javascripts/contributors/stores/state.js
index 1dc1a3c7b75..9c6b993e5cb 100644
--- a/app/assets/javascripts/contributors/stores/state.js
+++ b/app/assets/javascripts/contributors/stores/state.js
@@ -1,5 +1,5 @@
-export default () => ({
+export default (branch) => ({
loading: false,
chartData: null,
- branch: 'master',
+ branch,
});
diff --git a/app/assets/javascripts/performance_bar/components/request_selector.vue b/app/assets/javascripts/performance_bar/components/request_selector.vue
index 7f2064b3167..75fb7bbc5c5 100644
--- a/app/assets/javascripts/performance_bar/components/request_selector.vue
+++ b/app/assets/javascripts/performance_bar/components/request_selector.vue
@@ -58,9 +58,13 @@ export default {
<span v-if="request.hasWarnings">(!)</span>
</option>
</select>
- <span v-if="requestsWithWarnings.length">
+ <span v-if="requestsWithWarnings.length" class="gl-cursor-default">
<span id="performance-bar-request-selector-warning" v-html="glEmojiTag('warning')"></span>
- <gl-popover target="performance-bar-request-selector-warning" :content="warningMessage" />
+ <gl-popover
+ placement="bottom"
+ target="performance-bar-request-selector-warning"
+ :content="warningMessage"
+ />
</span>
</div>
</template>
diff --git a/app/assets/javascripts/performance_bar/components/request_warning.vue b/app/assets/javascripts/performance_bar/components/request_warning.vue
index c74257b176a..7fe6b088ebb 100644
--- a/app/assets/javascripts/performance_bar/components/request_warning.vue
+++ b/app/assets/javascripts/performance_bar/components/request_warning.vue
@@ -35,8 +35,8 @@ export default {
};
</script>
<template>
- <span v-if="hasWarnings">
+ <span v-if="hasWarnings" class="gl-cursor-default">
<span :id="htmlId" v-html="glEmojiTag('warning')"></span>
- <gl-popover :target="htmlId" :content="warningMessage" />
+ <gl-popover placement="bottom" :target="htmlId" :content="warningMessage" />
</span>
</template>
diff --git a/app/controllers/groups/settings/ci_cd_controller.rb b/app/controllers/groups/settings/ci_cd_controller.rb
index e79d43dba93..3e1413da615 100644
--- a/app/controllers/groups/settings/ci_cd_controller.rb
+++ b/app/controllers/groups/settings/ci_cd_controller.rb
@@ -10,6 +10,8 @@ module Groups
before_action :authorize_admin_group!
before_action :authorize_update_max_artifacts_size!, only: [:update]
before_action :define_variables, only: [:show]
+ before_action :push_feature_flags, only: [:show]
+ before_action :push_licensed_features, only: [:show]
feature_category :continuous_integration
@@ -91,6 +93,16 @@ module Groups
def update_group_params
params.require(:group).permit(:max_artifacts_size)
end
+
+ def push_feature_flags
+ push_frontend_feature_flag(:scoped_group_variables, group)
+ end
+
+ # Overridden in EE
+ def push_licensed_features
+ end
end
end
end
+
+Groups::Settings::CiCdController.prepend_if_ee('EE::Groups::Settings::CiCdController')
diff --git a/app/controllers/groups/variables_controller.rb b/app/controllers/groups/variables_controller.rb
index a2289b540ec..75bb6975c6e 100644
--- a/app/controllers/groups/variables_controller.rb
+++ b/app/controllers/groups/variables_controller.rb
@@ -56,3 +56,5 @@ module Groups
end
end
end
+
+Groups::VariablesController.prepend_if_ee('EE::Groups::VariablesController')
diff --git a/app/models/group.rb b/app/models/group.rb
index a0f58fd61b7..a065ea8924e 100644
--- a/app/models/group.rb
+++ b/app/models/group.rb
@@ -86,7 +86,7 @@ class Group < Namespace
validate :visibility_level_allowed_by_sub_groups
validate :visibility_level_allowed_by_parent
validate :two_factor_authentication_allowed
- validates :variables, nested_attributes_duplicates: true
+ validates :variables, nested_attributes_duplicates: { scope: :environment_scope }
validates :two_factor_grace_period, presence: true, numericality: { greater_than_or_equal_to: 0 }
diff --git a/app/serializers/ci/group_variable_entity.rb b/app/serializers/ci/group_variable_entity.rb
index e7d0a957082..30c8239541a 100644
--- a/app/serializers/ci/group_variable_entity.rb
+++ b/app/serializers/ci/group_variable_entity.rb
@@ -2,5 +2,6 @@
module Ci
class GroupVariableEntity < Ci::BasicVariableEntity
+ expose :environment_scope
end
end
diff --git a/app/views/projects/graphs/show.html.haml b/app/views/projects/graphs/show.html.haml
index 27bb5c076a4..1973b23a062 100644
--- a/app/views/projects/graphs/show.html.haml
+++ b/app/views/projects/graphs/show.html.haml
@@ -5,4 +5,4 @@
= render 'shared/ref_switcher', destination: 'graphs'
= link_to s_('Commits|History'), project_commits_path(@project, current_ref), class: 'btn gl-button btn-default'
-.js-contributors-graph{ class: container_class, 'data-project-graph-path': project_graph_path(@project, current_ref, format: :json), 'data-project-branch': current_ref }
+.js-contributors-graph{ class: container_class, data: { project_graph_path: project_graph_path(@project, current_ref, format: :json), project_branch: current_ref, default_branch: @project.default_branch } }
diff --git a/changelogs/unreleased/230717-add-mail-smtp-pool-gem.yml b/changelogs/unreleased/230717-add-mail-smtp-pool-gem.yml
new file mode 100644
index 00000000000..80787d1864a
--- /dev/null
+++ b/changelogs/unreleased/230717-add-mail-smtp-pool-gem.yml
@@ -0,0 +1,5 @@
+---
+title: Add support for SMTP connection pooling when sending emails
+merge_request: 57805
+author:
+type: added
diff --git a/changelogs/unreleased/pb-popover-improvement.yml b/changelogs/unreleased/pb-popover-improvement.yml
new file mode 100644
index 00000000000..572bcd38ac5
--- /dev/null
+++ b/changelogs/unreleased/pb-popover-improvement.yml
@@ -0,0 +1,5 @@
+---
+title: Update popover placement and cursor on warning icon in PB
+merge_request: 58552
+author: Yogi (@yo)
+type: changed
diff --git a/config/initializers/smtp_settings.rb.sample b/config/initializers/smtp_settings.rb.sample
index babc0a81938..4a50c29143d 100644
--- a/config/initializers/smtp_settings.rb.sample
+++ b/config/initializers/smtp_settings.rb.sample
@@ -22,3 +22,28 @@ if Rails.env.production?
openssl_verify_mode: 'peer' # See ActionMailer documentation for other possible options
}
end
+
+# To use an SMTP connection pool, uncomment the following section:
+#
+# require 'mail/smtp_pool'
+#
+# ActionMailer::Base.add_delivery_method :smtp_pool, Mail::SMTPPool
+#
+# if Rails.env.production?
+# Rails.application.config.action_mailer.delivery_method = :smtp_pool
+#
+# ActionMailer::Base.delivery_method = :smtp_pool
+# ActionMailer::Base.smtp_pool_settings = {
+# pool: Mail::SMTPPool.create_pool(
+# pool_size: Gitlab::Runtime.max_threads,
+# address: "email.server.com",
+# port: 465,
+# user_name: "smtp",
+# password: "123456",
+# domain: "gitlab.company.com",
+# authentication: :login,
+# enable_starttls_auto: true,
+# openssl_verify_mode: 'peer' # See ActionMailer documentation for other possible options
+# )
+# }
+# end
diff --git a/doc/api/usage_data.md b/doc/api/usage_data.md
index f54a0808d51..671e60be587 100644
--- a/doc/api/usage_data.md
+++ b/doc/api/usage_data.md
@@ -20,7 +20,7 @@ Return all of the raw SQL queries used to compute usage ping.
Example request:
```shell
-curl --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/usage_data/queries
+curl --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/usage_data/queries"
```
Sample response
@@ -66,3 +66,51 @@ Sample response
"ci_runners": "SELECT COUNT(\"ci_runners\".\"id\") FROM \"ci_runners\"",
...
```
+
+## UsageDataNonSqlMetrics API
+
+> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/57050) in GitLab 13.11.
+> - [Deployed behind a feature flag](../user/feature_flags.md), disabled by default.
+
+Return all non-SQL metrics data used in the usage ping.
+
+Example request:
+
+```shell
+curl --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/usage_data/non_sql_metrics"
+```
+
+Sample response:
+
+```json
+{
+ "recorded_at": "2021-03-26T07:04:03.724Z",
+ "uuid": null,
+ "hostname": "localhost",
+ "version": "13.11.0-pre",
+ "installation_type": "gitlab-development-kit",
+ "active_user_count": -3,
+ "edition": "EE",
+ "license_md5": "bb8cd0d8a6d9569ff3f70b8927a1f949",
+ "license_id": null,
+ "historical_max_users": 0,
+ "licensee": {
+ "Name": "John Doe1"
+ },
+ "license_user_count": null,
+ "license_starts_at": "1970-01-01",
+ "license_expires_at": "2022-02-26",
+ "license_plan": "starter",
+ "license_add_ons": {
+ "GitLab_FileLocks": 1,
+ "GitLab_Auditor_User": 1
+ },
+ "license_trial": null,
+ "license_subscription_id": "0000",
+ "license": {},
+ "settings": {
+ "ldap_encrypted_secrets_enabled": false,
+ "operating_system": "mac_os_x-11.2.2"
+ },
+...
+```
diff --git a/spec/frontend/ci_variable_list/components/ci_variable_modal_spec.js b/spec/frontend/ci_variable_list/components/ci_variable_modal_spec.js
index 991dc8592e9..fbc0bf1323a 100644
--- a/spec/frontend/ci_variable_list/components/ci_variable_modal_spec.js
+++ b/spec/frontend/ci_variable_list/components/ci_variable_modal_spec.js
@@ -1,6 +1,7 @@
-import { GlButton } from '@gitlab/ui';
+import { GlButton, GlFormInput } from '@gitlab/ui';
import { createLocalVue, shallowMount, mount } from '@vue/test-utils';
import Vuex from 'vuex';
+import CiEnvironmentsDropdown from '~/ci_variable_list/components/ci_environments_dropdown.vue';
import CiVariableModal from '~/ci_variable_list/components/ci_variable_modal.vue';
import { AWS_ACCESS_KEY_ID } from '~/ci_variable_list/constants';
import createStore from '~/ci_variable_list/store';
@@ -15,7 +16,7 @@ describe('Ci variable modal', () => {
let store;
const createComponent = (method, options = {}) => {
- store = createStore();
+ store = createStore({ isGroup: options.isGroup });
wrapper = method(CiVariableModal, {
attachTo: document.body,
stubs: {
@@ -27,6 +28,7 @@ describe('Ci variable modal', () => {
});
};
+ const findCiEnvironmentsDropdown = () => wrapper.find(CiEnvironmentsDropdown);
const findModal = () => wrapper.find(ModalStub);
const findAddorUpdateButton = () =>
findModal()
@@ -149,6 +151,61 @@ describe('Ci variable modal', () => {
});
});
+ describe('Environment scope', () => {
+ describe('group level variables', () => {
+ it('renders the environment dropdown', () => {
+ createComponent(shallowMount, {
+ isGroup: true,
+ provide: {
+ glFeatures: {
+ scopedGroupVariables: true,
+ groupScopedCiVariables: true,
+ },
+ },
+ });
+
+ expect(findCiEnvironmentsDropdown().exists()).toBe(true);
+ expect(findCiEnvironmentsDropdown().isVisible()).toBe(true);
+ });
+
+ describe('feature flag is disabled', () => {
+ it('hides the dropdown', () => {
+ createComponent(shallowMount, {
+ isGroup: true,
+ provide: {
+ glFeatures: {
+ scopedGroupVariables: false,
+ groupScopedCiVariables: true,
+ },
+ },
+ });
+
+ expect(findCiEnvironmentsDropdown().exists()).toBe(false);
+ });
+ });
+
+ describe('licensed feature is not available', () => {
+ it('disables the dropdown', () => {
+ createComponent(mount, {
+ isGroup: true,
+ provide: {
+ glFeatures: {
+ scopedGroupVariables: true,
+ groupScopedCiVariables: false,
+ },
+ },
+ });
+
+ const environmentScopeInput = wrapper
+ .find('[data-testid="environment-scope"]')
+ .find(GlFormInput);
+ expect(findCiEnvironmentsDropdown().exists()).toBe(false);
+ expect(environmentScopeInput.attributes('readonly')).toBe('readonly');
+ });
+ });
+ });
+ });
+
describe('Validations', () => {
const maskError = 'This variable can not be masked.';
diff --git a/spec/frontend/ci_variable_list/components/ci_variable_table_spec.js b/spec/frontend/ci_variable_list/components/ci_variable_table_spec.js
index ade2d65b857..abdf14a419a 100644
--- a/spec/frontend/ci_variable_list/components/ci_variable_table_spec.js
+++ b/spec/frontend/ci_variable_list/components/ci_variable_table_spec.js
@@ -1,4 +1,3 @@
-import { GlTable } from '@gitlab/ui';
import { createLocalVue, mount } from '@vue/test-utils';
import Vuex from 'vuex';
import CiVariableTable from '~/ci_variable_list/components/ci_variable_table.vue';
@@ -12,21 +11,24 @@ describe('Ci variable table', () => {
let wrapper;
let store;
- const createComponent = () => {
- store = createStore();
- store.state.isGroup = true;
+ const createComponent = (isGroup = false, scopedGroupVariables = false) => {
+ store = createStore({ isGroup });
jest.spyOn(store, 'dispatch').mockImplementation();
wrapper = mount(CiVariableTable, {
attachTo: document.body,
localVue,
store,
+ provide: {
+ glFeatures: {
+ scopedGroupVariables,
+ },
+ },
});
};
const findRevealButton = () => wrapper.find({ ref: 'secret-value-reveal-button' });
const findEditButton = () => wrapper.find({ ref: 'edit-ci-variable' });
const findEmptyVariablesPlaceholder = () => wrapper.find({ ref: 'empty-variables' });
- const findTable = () => wrapper.find(GlTable);
beforeEach(() => {
createComponent();
@@ -40,12 +42,14 @@ describe('Ci variable table', () => {
expect(store.dispatch).toHaveBeenCalledWith('fetchVariables');
});
- it('fields prop does not contain environment_scope if group', () => {
- expect(findTable().props('fields')).not.toEqual(
+ it('fields do not contain environment_scope if group level and feature is disabled', () => {
+ createComponent(true, false);
+
+ expect(wrapper.vm.fields).not.toEqual(
expect.arrayContaining([
expect.objectContaining({
key: 'environment_scope',
- label: 'Environment Scope',
+ label: 'Environments',
}),
]),
);
diff --git a/spec/serializers/ci/group_variable_entity_spec.rb b/spec/serializers/ci/group_variable_entity_spec.rb
index a7e12905924..9b64e263992 100644
--- a/spec/serializers/ci/group_variable_entity_spec.rb
+++ b/spec/serializers/ci/group_variable_entity_spec.rb
@@ -10,7 +10,7 @@ RSpec.describe Ci::GroupVariableEntity do
subject { entity.as_json }
it 'contains required fields' do
- expect(subject).to include(:id, :key, :value, :protected, :variable_type)
+ expect(subject).to include(:id, :key, :value, :protected, :variable_type, :environment_scope)
end
end
end
diff --git a/vendor/gems/mail-smtp_pool/.gitignore b/vendor/gems/mail-smtp_pool/.gitignore
new file mode 100644
index 00000000000..1fbdf80cd36
--- /dev/null
+++ b/vendor/gems/mail-smtp_pool/.gitignore
@@ -0,0 +1,3 @@
+Gemfile.lock
+*.gem
+.bundle
diff --git a/vendor/gems/mail-smtp_pool/.gitlab-ci.yml b/vendor/gems/mail-smtp_pool/.gitlab-ci.yml
new file mode 100644
index 00000000000..56eff5b30a7
--- /dev/null
+++ b/vendor/gems/mail-smtp_pool/.gitlab-ci.yml
@@ -0,0 +1,29 @@
+workflow:
+ rules:
+ - if: $CI_MERGE_REQUEST_ID
+
+.rspec:
+ cache:
+ key: mail-smtp_pool-ruby
+ paths:
+ - vendor/gems/mail-smtp_pool/vendor/ruby
+ before_script:
+ - cd vendor/gems/mail-smtp_pool
+ - ruby -v # Print out ruby version for debugging
+ - gem install bundler --no-document # Bundler is not installed with the image
+ - bundle config set --local path 'vendor' # Install dependencies into ./vendor/ruby
+ - bundle install -j $(nproc)
+ script:
+ - bundle exec rspec
+
+rspec-2.6:
+ image: "ruby:2.6"
+ extends: .rspec
+
+rspec-2.7:
+ image: "ruby:2.7"
+ extends: .rspec
+
+rspec-3.0:
+ image: "ruby:3.0"
+ extends: .rspec
diff --git a/vendor/gems/mail-smtp_pool/Gemfile b/vendor/gems/mail-smtp_pool/Gemfile
new file mode 100644
index 00000000000..7f4f5e950d1
--- /dev/null
+++ b/vendor/gems/mail-smtp_pool/Gemfile
@@ -0,0 +1,5 @@
+# frozen_string_literal: true
+
+source 'https://rubygems.org'
+
+gemspec
diff --git a/vendor/gems/mail-smtp_pool/LICENSE b/vendor/gems/mail-smtp_pool/LICENSE
new file mode 100644
index 00000000000..e6de2f90864
--- /dev/null
+++ b/vendor/gems/mail-smtp_pool/LICENSE
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2016-2021 GitLab B.V.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
diff --git a/vendor/gems/mail-smtp_pool/README.md b/vendor/gems/mail-smtp_pool/README.md
new file mode 100644
index 00000000000..bdb2be97663
--- /dev/null
+++ b/vendor/gems/mail-smtp_pool/README.md
@@ -0,0 +1,57 @@
+# Mail::SMTPPool
+
+This gem is an extension to `Mail` that allows delivery of emails using an SMTP connection pool
+
+## Installation
+
+Add this line to your application's Gemfile:
+
+```ruby
+gem 'mail-smtp_pool'
+```
+
+And then execute:
+
+```shell
+bundle
+```
+
+Or install it yourself as:
+
+```shell
+gem install mail-smtp_pool
+```
+
+## Usage with ActionMailer
+
+```ruby
+# config/environments/development.rb
+
+Rails.application.configure do
+ ...
+
+ ActionMailer::Base.add_delivery_method :smtp_pool, Mail::SMTPPool
+
+ config.action_mailer.perform_deliveries = true
+ config.action_mailer.smtp_pool_settings = {
+ pool: Mail::SMTPPool.create_pool(
+ pool_size: 5,
+ pool_timeout: 5,
+ address: 'smtp.gmail.com',
+ port: 587,
+ domain: 'example.com',
+ user_name: '<username>',
+ password: '<password>',
+ authentication: 'plain',
+ enable_starttls_auto: true
+ )
+ }
+end
+```
+
+Configuration options:
+
+* `pool_size` - The maximum number of SMTP connections in the pool. Connections are created lazily as needed.
+* `pool_timeout` - The number of seconds to wait for a connection in the pool to be available. A `Timeout::Error` exception is raised when this is exceeded.
+
+This also accepts all options supported by `Mail::SMTP`. See https://www.rubydoc.info/gems/mail/2.6.1/Mail/SMTP for more information.
diff --git a/vendor/gems/mail-smtp_pool/lib/mail/smtp_pool.rb b/vendor/gems/mail-smtp_pool/lib/mail/smtp_pool.rb
new file mode 100644
index 00000000000..ab8a7652058
--- /dev/null
+++ b/vendor/gems/mail-smtp_pool/lib/mail/smtp_pool.rb
@@ -0,0 +1,34 @@
+# frozen_string_literal: true
+
+require 'connection_pool'
+require 'mail/smtp_pool/connection'
+
+module Mail
+ class SMTPPool
+ POOL_DEFAULTS = {
+ pool_size: 5,
+ pool_timeout: 5
+ }.freeze
+
+ class << self
+ def create_pool(settings = {})
+ pool_settings = POOL_DEFAULTS.merge(settings)
+ smtp_settings = settings.reject { |k, v| POOL_DEFAULTS.keys.include?(k) }
+
+ ConnectionPool.new(size: pool_settings[:pool_size], timeout: pool_settings[:pool_timeout]) do
+ Mail::SMTPPool::Connection.new(smtp_settings)
+ end
+ end
+ end
+
+ def initialize(settings)
+ raise ArgumentError, 'pool is required. You can create one using Mail::SMTPPool.create_pool.' if settings[:pool].nil?
+
+ @pool = settings[:pool]
+ end
+
+ def deliver!(mail)
+ @pool.with { |conn| conn.deliver!(mail) }
+ end
+ end
+end
diff --git a/vendor/gems/mail-smtp_pool/lib/mail/smtp_pool/connection.rb b/vendor/gems/mail-smtp_pool/lib/mail/smtp_pool/connection.rb
new file mode 100644
index 00000000000..ab0d20153d8
--- /dev/null
+++ b/vendor/gems/mail-smtp_pool/lib/mail/smtp_pool/connection.rb
@@ -0,0 +1,60 @@
+# frozen_string_literal: true
+
+# A connection object that can be used to deliver mail.
+#
+# This is meant to be used in a pool so the main difference between this
+# and Mail::SMTP is that this expects deliver! to be called multiple times.
+#
+# SMTP connection reset and error handling is handled by this class and
+# the SMTP connection is not closed after a delivery.
+
+require 'mail'
+
+module Mail
+ class SMTPPool
+ class Connection < Mail::SMTP
+ def initialize(values)
+ super
+
+ @smtp_session = nil
+ end
+
+ def deliver!(mail)
+ response = Mail::SMTPConnection.new(connection: smtp_session, return_response: true).deliver!(mail)
+
+ settings[:return_response] ? response : self
+ end
+
+ def finish
+ finish_smtp_session if @smtp_session && @smtp_session.started?
+ end
+
+ private
+
+ def smtp_session
+ return start_smtp_session if @smtp_session.nil? || !@smtp_session.started?
+ return @smtp_session if reset_smtp_session
+
+ finish_smtp_session
+ start_smtp_session
+ end
+
+ def start_smtp_session
+ @smtp_session = build_smtp_session.start(settings[:domain], settings[:user_name], settings[:password], settings[:authentication])
+ end
+
+ def reset_smtp_session
+ !@smtp_session.instance_variable_get(:@error_occurred) && @smtp_session.rset.success?
+ rescue Net::SMTPError, IOError
+ false
+ end
+
+ def finish_smtp_session
+ @smtp_session.finish
+ rescue Net::SMTPError, IOError
+ ensure
+ @smtp_session = nil
+ end
+ end
+ end
+end
diff --git a/vendor/gems/mail-smtp_pool/mail-smtp_pool.gemspec b/vendor/gems/mail-smtp_pool/mail-smtp_pool.gemspec
new file mode 100644
index 00000000000..3d9036f19b1
--- /dev/null
+++ b/vendor/gems/mail-smtp_pool/mail-smtp_pool.gemspec
@@ -0,0 +1,26 @@
+# frozen_string_literal: true
+
+lib = File.expand_path('lib', __dir__)
+$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
+
+Gem::Specification.new do |spec|
+ spec.name = 'mail-smtp_pool'
+ spec.version = '0.1.0'
+ spec.authors = ['Heinrich Lee Yu']
+ spec.email = ['heinrich@gitlab.com']
+
+ spec.summary = 'Mail extension for sending using an SMTP connection pool'
+ spec.homepage = 'https://gitlab.com/gitlab-org/gitlab/-/tree/master/vendor/gems/mail-smtp_pool'
+ spec.metadata = { 'source_code_uri' => 'https://gitlab.com/gitlab-org/gitlab/-/tree/master/vendor/gems/mail-smtp_pool' }
+ spec.license = 'MIT'
+
+ spec.files = Dir['lib/**/*.rb']
+ spec.require_paths = ['lib']
+
+ # Please maintain alphabetical order for dependencies
+ spec.add_runtime_dependency 'connection_pool', '~> 2.0'
+ spec.add_runtime_dependency 'mail', '~> 2.7'
+
+ # Please maintain alphabetical order for dev dependencies
+ spec.add_development_dependency 'rspec', '~> 3.10.0'
+end
diff --git a/vendor/gems/mail-smtp_pool/spec/lib/mail/smtp_pool/connection_spec.rb b/vendor/gems/mail-smtp_pool/spec/lib/mail/smtp_pool/connection_spec.rb
new file mode 100644
index 00000000000..78426296406
--- /dev/null
+++ b/vendor/gems/mail-smtp_pool/spec/lib/mail/smtp_pool/connection_spec.rb
@@ -0,0 +1,93 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe Mail::SMTPPool::Connection do
+ let(:connection) { described_class.new({}) }
+ let(:mail) do
+ Mail.new do
+ from 'mikel@test.lindsaar.net'
+ to 'you@test.lindsaar.net'
+ subject 'This is a test email'
+ body 'Test body'
+ end
+ end
+
+ after do
+ MockSMTP.clear_deliveries
+ end
+
+ describe '#deliver!' do
+ it 'delivers mail using the same SMTP connection' do
+ mock_smtp = MockSMTP.new
+
+ expect(Net::SMTP).to receive(:new).once.and_return(mock_smtp)
+ expect(mock_smtp).to receive(:sendmail).twice.and_call_original
+ expect(mock_smtp).to receive(:rset).once.and_call_original
+
+ connection.deliver!(mail)
+ connection.deliver!(mail)
+
+ expect(MockSMTP.deliveries.size).to eq(2)
+ end
+
+ context 'when RSET fails' do
+ let(:mock_smtp) { MockSMTP.new }
+ let(:mock_smtp_2) { MockSMTP.new }
+
+ before do
+ expect(Net::SMTP).to receive(:new).twice.and_return(mock_smtp, mock_smtp_2)
+ end
+
+ context 'with an IOError' do
+ before do
+ expect(mock_smtp).to receive(:rset).once.and_raise(IOError)
+ end
+
+ it 'creates a new SMTP connection' do
+ expect(mock_smtp).to receive(:sendmail).once.and_call_original
+ expect(mock_smtp).to receive(:finish).once.and_call_original
+ expect(mock_smtp_2).to receive(:sendmail).once.and_call_original
+
+ connection.deliver!(mail)
+ connection.deliver!(mail)
+
+ expect(MockSMTP.deliveries.size).to eq(2)
+ end
+ end
+
+ context 'with an SMTP error' do
+ before do
+ expect(mock_smtp).to receive(:rset).once.and_raise(Net::SMTPServerBusy)
+ end
+
+ it 'creates a new SMTP connection' do
+ expect(mock_smtp).to receive(:sendmail).once.and_call_original
+ expect(mock_smtp).to receive(:finish).once.and_call_original
+ expect(mock_smtp_2).to receive(:sendmail).once.and_call_original
+
+ connection.deliver!(mail)
+ connection.deliver!(mail)
+
+ expect(MockSMTP.deliveries.size).to eq(2)
+ end
+
+ context 'and closing the old connection fails' do
+ before do
+ expect(mock_smtp).to receive(:finish).once.and_raise(IOError)
+ end
+
+ it 'creates a new SMTP connection' do
+ expect(mock_smtp).to receive(:sendmail).once.and_call_original
+ expect(mock_smtp_2).to receive(:sendmail).once.and_call_original
+
+ connection.deliver!(mail)
+ connection.deliver!(mail)
+
+ expect(MockSMTP.deliveries.size).to eq(2)
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/vendor/gems/mail-smtp_pool/spec/lib/mail/smtp_pool_spec.rb b/vendor/gems/mail-smtp_pool/spec/lib/mail/smtp_pool_spec.rb
new file mode 100644
index 00000000000..aa2a0e19ac8
--- /dev/null
+++ b/vendor/gems/mail-smtp_pool/spec/lib/mail/smtp_pool_spec.rb
@@ -0,0 +1,68 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe Mail::SMTPPool do
+ describe '.create_pool' do
+ it 'sets the default pool settings' do
+ expect(ConnectionPool).to receive(:new).with(size: 5, timeout: 5).once
+
+ described_class.create_pool
+ end
+
+ it 'allows overriding pool size and timeout' do
+ expect(ConnectionPool).to receive(:new).with(size: 3, timeout: 2).once
+
+ described_class.create_pool(pool_size: 3, pool_timeout: 2)
+ end
+
+ it 'creates an SMTP connection with the correct settings' do
+ settings = { address: 'smtp.example.com', port: '465' }
+
+ smtp_pool = described_class.create_pool(settings)
+
+ expect(Mail::SMTPPool::Connection).to receive(:new).with(settings).once.and_call_original
+
+ smtp_pool.checkout
+ end
+ end
+
+ describe '#initialize' do
+ it 'raises an error if a pool is not specified' do
+ expect { described_class.new({}) }.to raise_error(
+ ArgumentError, 'pool is required. You can create one using Mail::SMTPPool.create_pool.'
+ )
+ end
+ end
+
+ describe '#deliver!' do
+ let(:mail) do
+ Mail.new do
+ from 'mikel@test.lindsaar.net'
+ to 'you@test.lindsaar.net'
+ subject 'This is a test email'
+ body 'Test body'
+ end
+ end
+
+ after do
+ MockSMTP.clear_deliveries
+ end
+
+ it 'delivers mail using a connection from the pool' do
+ connection_pool = double(ConnectionPool)
+ connection = double(Mail::SMTPPool::Connection)
+
+ expect(connection_pool).to receive(:with).and_yield(connection)
+ expect(connection).to receive(:deliver!).with(mail)
+
+ described_class.new(pool: connection_pool).deliver!(mail)
+ end
+
+ it 'delivers mail' do
+ described_class.new(pool: described_class.create_pool).deliver!(mail)
+
+ expect(MockSMTP.deliveries.size).to eq(1)
+ end
+ end
+end
diff --git a/vendor/gems/mail-smtp_pool/spec/spec_helper.rb b/vendor/gems/mail-smtp_pool/spec/spec_helper.rb
new file mode 100644
index 00000000000..4d339850381
--- /dev/null
+++ b/vendor/gems/mail-smtp_pool/spec/spec_helper.rb
@@ -0,0 +1,84 @@
+# frozen_string_literal: true
+
+require 'mail/smtp_pool'
+
+# Original mockup from ActionMailer
+# Based on https://github.com/mikel/mail/blob/22a7afc23f253319965bf9228a0a430eec94e06d/spec/spec_helper.rb#L74-L138
+class MockSMTP
+ def self.deliveries
+ @@deliveries
+ end
+
+ def self.security
+ @@security
+ end
+
+ def initialize
+ @@deliveries = []
+ @@security = nil
+ @started = false
+ end
+
+ def sendmail(mail, from, to)
+ @@deliveries << [mail, from, to]
+ 'OK'
+ end
+
+ def rset
+ Net::SMTP::Response.parse('250 OK')
+ end
+
+ def start(*args)
+ @started = true
+
+ if block_given?
+ result = yield(self)
+ @started = false
+
+ return result
+ else
+ return self
+ end
+ end
+
+ def started?
+ @started
+ end
+
+ def finish
+ @started = false
+ return true
+ end
+
+ def self.clear_deliveries
+ @@deliveries = []
+ end
+
+ def self.clear_security
+ @@security = nil
+ end
+
+ def enable_tls(context)
+ raise ArgumentError, "SMTPS and STARTTLS is exclusive" if @@security && @@security != :enable_tls
+ @@security = :enable_tls
+ context
+ end
+
+ def enable_starttls(context = nil)
+ raise ArgumentError, "SMTPS and STARTTLS is exclusive" if @@security == :enable_tls
+ @@security = :enable_starttls
+ context
+ end
+
+ def enable_starttls_auto(context)
+ raise ArgumentError, "SMTPS and STARTTLS is exclusive" if @@security == :enable_tls
+ @@security = :enable_starttls_auto
+ context
+ end
+end
+
+class Net::SMTP
+ def self.new(*args)
+ MockSMTP.new
+ end
+end