Commit f368be61 authored by Fabio Pitino's avatar Fabio Pitino

Merge branch '276583-make-keep-latest-artifact-an-instance-level-configuration' into 'master'

Make "keep latest artifact" an instance-level configuration

See merge request gitlab-org/gitlab!50889
parents 2c6adeb8 af89c610
query getKeepLatestArtifactApplicationSetting {
ciApplicationSettings {
keepLatestArtifact
}
}
......@@ -2,12 +2,22 @@
import { GlAlert, GlFormCheckbox, GlLink } from '@gitlab/ui';
import { __ } from '~/locale';
import GetKeepLatestArtifactProjectSetting from './graphql/queries/get_keep_latest_artifact_project_setting.query.graphql';
import GetKeepLatestArtifactApplicationSetting from './graphql/queries/get_keep_latest_artifact_application_setting.query.graphql';
import UpdateKeepLatestArtifactProjectSetting from './graphql/mutations/update_keep_latest_artifact_project_setting.mutation.graphql';
const FETCH_ERROR = __('There was a problem fetching the keep latest artifact setting.');
const UPDATE_ERROR = __('There was a problem updating the keep latest artifact setting.');
export default {
errors: {
fetchError: __('There was a problem fetching the keep latest artifacts setting.'),
updateError: __('There was a problem updating the keep latest artifacts setting.'),
},
i18n: {
enabledHelpText: __(
'The latest artifacts created by jobs in the most recent successful pipeline will be stored.',
),
disabledHelpText: __('This feature is disabled at the instance level.'),
helpLinkText: __('More information'),
checkboxText: __('Keep artifacts from most recent successful jobs'),
},
components: {
GlAlert,
GlFormCheckbox,
......@@ -33,21 +43,33 @@ export default {
return data.project?.ciCdSettings?.keepLatestArtifact;
},
error() {
this.reportError(FETCH_ERROR);
this.reportError(this.$options.errors.fetchError);
},
},
projectSettingDisabled: {
query: GetKeepLatestArtifactApplicationSetting,
update(data) {
return !data.ciApplicationSettings?.keepLatestArtifact;
},
},
},
data() {
return {
keepLatestArtifact: true,
keepLatestArtifact: null,
errorMessage: '',
isAlertDismissed: false,
projectSettingDisabled: true,
};
},
computed: {
shouldShowAlert() {
return this.errorMessage && !this.isAlertDismissed;
},
helpText() {
return this.projectSettingDisabled
? this.$options.i18n.disabledHelpText
: this.$options.i18n.enabledHelpText;
},
},
methods: {
reportError(error) {
......@@ -65,10 +87,10 @@ export default {
});
if (data.ciCdSettingsUpdate.errors.length) {
this.reportError(UPDATE_ERROR);
this.reportError(this.$options.errors.updateError);
}
} catch (error) {
this.reportError(UPDATE_ERROR);
this.reportError(this.$options.errors.updateError);
}
},
},
......@@ -84,16 +106,13 @@ export default {
@dismiss="isAlertDismissed = true"
>{{ errorMessage }}</gl-alert
>
<gl-form-checkbox v-model="keepLatestArtifact" @change="updateSetting"
><b class="gl-mr-3">{{ __('Keep artifacts from most recent successful jobs') }}</b>
<gl-link :href="helpPagePath">{{ __('More information') }}</gl-link></gl-form-checkbox
>
<p>
{{
__(
'The latest artifacts created by jobs in the most recent successful pipeline will be stored.',
)
}}
</p>
<gl-form-checkbox
v-model="keepLatestArtifact"
:disabled="projectSettingDisabled"
@change="updateSetting"
><strong class="gl-mr-3">{{ $options.i18n.checkboxText }}</strong>
<gl-link :href="helpPagePath">{{ $options.i18n.helpLinkText }}</gl-link>
<template v-if="!$apollo.loading" #help>{{ helpText }}</template>
</gl-form-checkbox>
</div>
</template>
# frozen_string_literal: true
module Types
module Ci
class ApplicationSettingType < BaseObject
graphql_name 'CiApplicationSettings'
authorize :read_application_setting
field :keep_latest_artifact, GraphQL::BOOLEAN_TYPE, null: true,
description: 'Whether to keep the latest jobs artifacts.'
end
end
end
......@@ -14,7 +14,8 @@ module Types
description: 'Whether merge trains are enabled.',
method: :merge_trains_enabled?
field :keep_latest_artifact, GraphQL::BOOLEAN_TYPE, null: true,
description: 'Whether to keep the latest builds artifacts.'
description: 'Whether to keep the latest builds artifacts.',
method: :keep_latest_artifacts_available?
field :project, Types::ProjectType, null: true,
description: 'Project the CI/CD settings belong to.'
end
......
......@@ -87,6 +87,10 @@ module Types
description: 'Get statistics on the instance.',
resolver: Resolvers::Admin::Analytics::InstanceStatistics::MeasurementsResolver
field :ci_application_settings, Types::Ci::ApplicationSettingType,
null: true,
description: 'CI related settings that apply to the entire instance.'
field :runner_platforms, Types::Ci::RunnerPlatformType.connection_type,
null: true, description: 'Supported runner platforms.',
resolver: Resolvers::Ci::RunnerPlatformsResolver
......@@ -128,6 +132,14 @@ module Types
def current_user
context[:current_user]
end
def ci_application_settings
application_settings
end
def application_settings
Gitlab::CurrentSettings.current_application_settings
end
end
end
......
......@@ -339,7 +339,8 @@ module ApplicationSettingsHelper
:container_registry_delete_tags_service_timeout,
:rate_limiting_response_text,
:container_registry_expiration_policies_worker_capacity,
:container_registry_cleanup_tags_service_max_list_size
:container_registry_cleanup_tags_service_max_list_size,
:keep_latest_artifact
]
end
......
......@@ -525,6 +525,10 @@ class ApplicationSetting < ApplicationRecord
current_without_cache
end
def self.find_or_create_without_cache
current_without_cache || create_from_defaults
end
# Due to the frequency with which settings are accessed, it is
# likely that during a backup restore a running GitLab process
# will insert a new `application_settings` row before the
......
......@@ -411,7 +411,7 @@ class Project < ApplicationRecord
delegate :dashboard_timezone, to: :metrics_setting, allow_nil: true, prefix: true
delegate :default_git_depth, :default_git_depth=, to: :ci_cd_settings, prefix: :ci
delegate :forward_deployment_enabled, :forward_deployment_enabled=, :forward_deployment_enabled?, to: :ci_cd_settings, prefix: :ci
delegate :keep_latest_artifact, :keep_latest_artifact=, :keep_latest_artifact?, to: :ci_cd_settings, prefix: :ci
delegate :keep_latest_artifact, :keep_latest_artifact=, :keep_latest_artifact?, :keep_latest_artifacts_available?, to: :ci_cd_settings
delegate :restrict_user_defined_variables, :restrict_user_defined_variables=, :restrict_user_defined_variables?,
to: :ci_cd_settings
delegate :actual_limits, :actual_plan_name, to: :namespace, allow_nil: true
......@@ -837,8 +837,12 @@ class Project < ApplicationRecord
webide_pipelines.running_or_pending.for_user(user)
end
def latest_pipeline_locked
ci_keep_latest_artifact? ? :artifacts_locked : :unlocked
def default_pipeline_lock
if keep_latest_artifacts_available?
return :artifacts_locked
end
:unlocked
end
def autoclose_referenced_issues
......
......@@ -21,6 +21,11 @@ class ProjectCiCdSetting < ApplicationRecord
super && ::Feature.enabled?(:forward_deployment_enabled, project, default_enabled: true)
end
def keep_latest_artifacts_available?
# The project level feature can only be enabled when the feature is enabled instance wide
Gitlab::CurrentSettings.current_application_settings.keep_latest_artifact? && keep_latest_artifact?
end
private
def set_default_git_depth
......
# frozen_string_literal: true
class ApplicationSettingPolicy < BasePolicy # rubocop:disable Gitlab/NamespacedClass
rule { admin }.enable :read_application_setting
end
......@@ -41,6 +41,14 @@
.form-text.text-muted
= html_escape(_("Set the default expiration time for each job's artifacts. 0 for unlimited. The default unit is in seconds, but you can define an alternative. For example: %{code_open}4 mins 2 sec%{code_close}, %{code_open}2h42min%{code_close}.")) % { code_open: '<code>'.html_safe, code_close: '</code>'.html_safe }
= link_to sprite_icon('question-o'), help_page_path('user/admin_area/settings/continuous_integration', anchor: 'default-artifacts-expiration')
.form-group
.form-check
= f.check_box :keep_latest_artifact, class: 'form-check-input'
= f.label :keep_latest_artifact, class: 'form-check-label' do
%strong
= s_('AdminSettings|Keep the latest artifacts for all jobs in the latest successful pipelines')
.form-text.text-muted
= s_('AdminSettings|The latest artifacts for all jobs in the most recent successful pipelines in each project are stored and do not expire.')
.form-group
= f.label :archive_builds_in_human_readable, _('Archive jobs'), class: 'label-bold'
= f.text_field :archive_builds_in_human_readable, class: 'form-control gl-form-input', placeholder: 'never'
......@@ -51,8 +59,8 @@
= f.check_box :protected_ci_variables, class: 'form-check-input'
= f.label :protected_ci_variables, class: 'form-check-label' do
= s_('AdminSettings|Environment variables are protected by default')
.form-text.text-muted
= s_('AdminSettings|When creating a new environment variable it will be protected by default.')
.form-text.text-muted
= s_('AdminSettings|When creating a new environment variable it will be protected by default.')
.form-group
= f.label :ci_config_path, _('Default CI configuration path'), class: 'label-bold'
= f.text_field :default_ci_config_path, class: 'form-control gl-form-input', placeholder: '.gitlab-ci.yml'
......
---
title: Add keep latest artifact option for instances
merge_request: 50889
author:
type: added
# frozen_string_literal: true
class AddKeepLatestArtifactsToApplicationSettings < ActiveRecord::Migration[6.0]
DOWNTIME = false
def change
# This is named keep_latest_artifact for consistency with the project level setting but
# turning it on keeps all (multiple) artifacts on the latest pipeline per ref
add_column :application_settings, :keep_latest_artifact, :boolean, default: true, null: false
end
end
a0561e52982756aded22563e833ab8005b4f45b84c81e872dd8c7188aeb84434
\ No newline at end of file
......@@ -9412,6 +9412,7 @@ CREATE TABLE application_settings (
enforce_ssh_key_expiration boolean DEFAULT false NOT NULL,
git_two_factor_session_expiry integer DEFAULT 15 NOT NULL,
asset_proxy_allowlist text,
keep_latest_artifact boolean DEFAULT true NOT NULL,
CONSTRAINT app_settings_container_reg_cleanup_tags_max_list_size_positive CHECK ((container_registry_cleanup_tags_service_max_list_size >= 0)),
CONSTRAINT app_settings_registry_exp_policies_worker_capacity_positive CHECK ((container_registry_expiration_policies_worker_capacity >= 0)),
CONSTRAINT check_17d9558205 CHECK ((char_length((kroki_url)::text) <= 1024)),
......
......@@ -2533,6 +2533,13 @@ type BurnupChartDailyTotals {
scopeWeight: Int!
}
type CiApplicationSettings {
"""
Whether to keep the latest jobs artifacts.
"""
keepLatestArtifact: Boolean
}
type CiBuildNeed {
"""
Name of the job we need to complete.
......@@ -20898,6 +20905,11 @@ type PromoteToEpicPayload {
}
type Query {
"""
CI related settings that apply to the entire instance.
"""
ciApplicationSettings: CiApplicationSettings
"""
Get linted and processed contents of a CI config. Should not be requested more than once per request.
"""
......
......@@ -6681,6 +6681,33 @@
"enumValues": null,
"possibleTypes": null
},
{
"kind": "OBJECT",
"name": "CiApplicationSettings",
"description": null,
"fields": [
{
"name": "keepLatestArtifact",
"description": "Whether to keep the latest jobs artifacts.",
"args": [
],
"type": {
"kind": "SCALAR",
"name": "Boolean",
"ofType": null
},
"isDeprecated": false,
"deprecationReason": null
}
],
"inputFields": null,
"interfaces": [
],
"enumValues": null,
"possibleTypes": null
},
{
"kind": "OBJECT",
"name": "CiBuildNeed",
......@@ -60807,6 +60834,20 @@
"name": "Query",
"description": null,
"fields": [
{
"name": "ciApplicationSettings",
"description": "CI related settings that apply to the entire instance.",
"args": [
],
"type": {
"kind": "OBJECT",
"name": "CiApplicationSettings",
"ofType": null
},
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "ciConfig",
"description": "Get linted and processed contents of a CI config. Should not be requested more than once per request.",
......@@ -407,6 +407,12 @@ Represents the total number of issues and their weights for a particular day.
| `scopeCount` | Int! | Number of issues as of this day |
| `scopeWeight` | Int! | Total weight of issues as of this day |
### CiApplicationSettings
| Field | Type | Description |
| ----- | ---- | ----------- |
| `keepLatestArtifact` | Boolean | Whether to keep the latest jobs artifacts. |
### CiBuildNeed
| Field | Type | Description |
......
......@@ -85,7 +85,8 @@ Example response:
"wiki_page_max_content_bytes": 52428800,
"require_admin_approval_after_user_signup": false,
"personal_access_token_prefix": "GL-",
"rate_limiting_response_text": null
"rate_limiting_response_text": null,
"keep_latest_artifact": true
}
```
......@@ -179,7 +180,8 @@ Example response:
"wiki_page_max_content_bytes": 52428800,
"require_admin_approval_after_user_signup": false,
"personal_access_token_prefix": "GL-",
"rate_limiting_response_text": null
"rate_limiting_response_text": null,
"keep_latest_artifact": true
}
```
......
......@@ -484,6 +484,9 @@ a project, you can disable this behavior to save space:
1. Navigate to **Settings > CI/CD > Artifacts**.
1. Uncheck **Keep artifacts from most recent successful jobs**.
You can disable this behavior for all projects on a self-managed instance in the
[instance's CI/CD settings](../../user/admin_area/settings/continuous_integration.md#keep-the-latest-artifacts-for-all-jobs-in-the-latest-successful-pipelines). **(CORE ONLY)**
When you disable the feature, the latest artifacts do not immediately expire.
A new pipeline must run before the latest artifacts can expire and be deleted.
......
......@@ -3331,7 +3331,9 @@ job:
The latest artifacts for refs are locked against deletion, and kept regardless of
the expiry time. [Introduced in](https://gitlab.com/gitlab-org/gitlab/-/issues/16267)
GitLab 13.0 behind a disabled feature flag, and [made the default behavior](https://gitlab.com/gitlab-org/gitlab/-/issues/229936)
in GitLab 13.4. In [GitLab 13.8 and later](https://gitlab.com/gitlab-org/gitlab/-/issues/241026), you can [disable this behavior in the CI/CD settings](../pipelines/job_artifacts.md#keep-artifacts-from-most-recent-successful-jobs).
in GitLab 13.4.
In [GitLab 13.8 and later](https://gitlab.com/gitlab-org/gitlab/-/issues/241026), you can [disable this behavior at the project level in the CI/CD settings](../pipelines/job_artifacts.md#keep-artifacts-from-most-recent-successful-jobs). In [GitLab 13.9 and later](https://gitlab.com/gitlab-org/gitlab/-/issues/276583), you can [disable this behavior instance-wide](../../user/admin_area/settings/continuous_integration.md#keep-the-latest-artifacts-for-all-jobs-in-the-latest-successful-pipelines).
#### `artifacts:reports`
......
......@@ -86,6 +86,25 @@ be updated for artifacts created before this setting was changed.
The administrator may need to manually search for and expire previously-created
artifacts, as described in the [troubleshooting documentation](../../../administration/troubleshooting/gitlab_rails_cheat_sheet.md#remove-artifacts-more-than-a-week-old).
## Keep the latest artifacts for all jobs in the latest successful pipelines **(CORE ONLY)**
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/50889) in GitLab Core 13.9.
When enabled (default), the artifacts for the most recent pipeline for a ref are
locked against deletion and kept regardless of the expiry time.
When disabled, the latest artifacts for any **new** successful or fixed pipelines
are allowed to expire.
This setting takes precedence over the [project level setting](../../../ci/pipelines/job_artifacts.md#keep-artifacts-from-most-recent-successful-jobs).
If disabled at the instance level, you cannot enable this per-project.
When you disable the feature, the latest artifacts do not immediately expire.
A new pipeline must run before the latest artifacts can expire and be deleted.
NOTE:
All application settings have a [customizable cache expiry interval](../../../administration/application_settings_cache.md) which can delay the settings affect.
## Shared runners pipeline minutes quota **(PREMIUM SELF)**
> [Moved](https://about.gitlab.com/blog/2021/01/26/new-gitlab-product-subscription-model/) to GitLab Premium in 13.9.
......
......@@ -10,8 +10,7 @@ module API
helpers do
def current_settings
@current_setting ||=
(ApplicationSetting.current_without_cache || ApplicationSetting.create_from_defaults)
@current_setting ||= ApplicationSetting.find_or_create_without_cache
end
def filter_attributes_using_license(attrs)
......
......@@ -23,7 +23,7 @@ module Gitlab
pipeline_schedule: @command.schedule,
merge_request: @command.merge_request,
external_pull_request: @command.external_pull_request,
locked: @command.project.latest_pipeline_locked,
locked: @command.project.default_pipeline_lock,
variables_attributes: variables_attributes
)
end
......
......@@ -2070,6 +2070,9 @@ msgstr ""
msgid "AdminSettings|Integrations configured here will automatically apply to all projects on this instance."
msgstr ""
msgid "AdminSettings|Keep the latest artifacts for all jobs in the latest successful pipelines"
msgstr ""
msgid "AdminSettings|Maximum duration of a session for Git operations when 2FA is enabled."
msgstr ""
......@@ -2109,6 +2112,9 @@ msgstr ""
msgid "AdminSettings|Specify a domain to use by default for every project's Auto Review Apps and Auto Deploy stages."
msgstr ""
msgid "AdminSettings|The latest artifacts for all jobs in the most recent successful pipelines in each project are stored and do not expire."
msgstr ""
msgid "AdminSettings|The required pipeline configuration can be selected from the %{code_start}gitlab-ci%{code_end} directory inside of the configured %{link_start}instance template repository%{link_end} or from GitLab provided configurations."
msgstr ""
......@@ -29320,7 +29326,7 @@ msgstr ""
msgid "There was a problem fetching project users."
msgstr ""
msgid "There was a problem fetching the keep latest artifact setting."
msgid "There was a problem fetching the keep latest artifacts setting."
msgstr ""
msgid "There was a problem fetching users."
......@@ -29335,7 +29341,7 @@ msgstr ""
msgid "There was a problem sending the confirmation email"
msgstr ""
msgid "There was a problem updating the keep latest artifact setting."
msgid "There was a problem updating the keep latest artifacts setting."
msgstr ""
msgid "There was an error %{message} todo."
......@@ -29689,6 +29695,9 @@ msgstr ""
msgid "This epic does not exist or you don't have sufficient permission."
msgstr ""
msgid "This feature is disabled at the instance level."
msgstr ""
msgid "This feature requires local storage to be enabled"
msgstr ""
......
......@@ -39,7 +39,7 @@ FactoryBot.define do
group_runners_enabled { nil }
merge_pipelines_enabled { nil }
merge_trains_enabled { nil }
ci_keep_latest_artifact { nil }
keep_latest_artifact { nil }
import_status { nil }
import_jid { nil }
import_correlation_id { nil }
......@@ -84,7 +84,7 @@ FactoryBot.define do
project.group_runners_enabled = evaluator.group_runners_enabled unless evaluator.group_runners_enabled.nil?
project.merge_pipelines_enabled = evaluator.merge_pipelines_enabled unless evaluator.merge_pipelines_enabled.nil?
project.merge_trains_enabled = evaluator.merge_trains_enabled unless evaluator.merge_trains_enabled.nil?
project.ci_keep_latest_artifact = evaluator.ci_keep_latest_artifact unless evaluator.ci_keep_latest_artifact.nil?
project.keep_latest_artifact = evaluator.keep_latest_artifact unless evaluator.keep_latest_artifact.nil?
project.restrict_user_defined_variables = evaluator.restrict_user_defined_variables unless evaluator.restrict_user_defined_variables.nil?
if evaluator.import_status
......
......@@ -306,11 +306,13 @@ RSpec.describe 'Admin updates settings' do
page.within('.as-ci-cd') do
check 'Default to Auto DevOps pipeline for all projects'
fill_in 'application_setting_auto_devops_domain', with: 'domain.com'
uncheck 'Keep the latest artifacts for all jobs in the latest successful pipelines'
click_button 'Save changes'
end
expect(current_settings.auto_devops_enabled?).to be true
expect(current_settings.auto_devops_domain).to eq('domain.com')
expect(current_settings.keep_latest_artifact).to be false
expect(page).to have_content "Application settings saved successfully"
end
......
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`Keep latest artifact checkbox sets correct setting value in checkbox with query result 1`] = `
exports[`Keep latest artifact checkbox when application keep latest artifact setting is disabled checkbox is disabled when application setting is disabled 1`] = `
<div>
<!---->
<gl-form-checkbox-stub
<b-form-checkbox-stub
checked="true"
class="gl-form-checkbox"
disabled="true"
plain="true"
value="true"
>
<b
<strong
class="gl-mr-3"
>
Keep artifacts from most recent successful jobs
</b>
</strong>
<gl-link-stub
href="/help/ci/pipelines/job_artifacts"
>
More information
</gl-link-stub>
</gl-form-checkbox-stub>
<p
class="help-text"
>
This feature is disabled at the instance level.
</p>
</b-form-checkbox-stub>
</div>
`;
exports[`Keep latest artifact checkbox when application keep latest artifact setting is enabled sets correct setting value in checkbox with query result 1`] = `
<div>
<!---->
<p>
The latest artifacts created by jobs in the most recent successful pipeline will be stored.
</p>
<b-form-checkbox-stub
checked="true"
class="gl-form-checkbox"
plain="true"
value="true"
>
<strong
class="gl-mr-3"
>
Keep artifacts from most recent successful jobs
</strong>
<gl-link-stub
href="/help/ci/pipelines/job_artifacts"
>
More information
</gl-link-stub>
<p
class="help-text"
>
The latest artifacts created by jobs in the most recent successful pipeline will be stored.
</p>
</b-form-checkbox-stub>
</div>
`;
......@@ -4,12 +4,13 @@ import VueApollo from 'vue-apollo';
import createMockApollo from 'helpers/mock_apollo_helper';
import KeepLatestArtifactCheckbox from '~/artifacts_settings/keep_latest_artifact_checkbox.vue';
import GetKeepLatestArtifactProjectSetting from '~/artifacts_settings/graphql/queries/get_keep_latest_artifact_project_setting.query.graphql';
import GetKeepLatestArtifactApplicationSetting from '~/artifacts_settings/graphql/queries/get_keep_latest_artifact_application_setting.query.graphql';
import UpdateKeepLatestArtifactProjectSetting from '~/artifacts_settings/graphql/mutations/update_keep_latest_artifact_project_setting.mutation.graphql';
const localVue = createLocalVue();
localVue.use(VueApollo);
const keepLatestArtifactMock = {
const keepLatestArtifactProjectMock = {
data: {
project: {
ciCdSettings: { keepLatestArtifact: true },
......@@ -17,6 +18,14 @@ const keepLatestArtifactMock = {
},
};
const keepLatestArtifactApplicationMock = {
data: {
ciApplicationSettings: {
keepLatestArtifact: true,
},
},
};
const keepLatestArtifactMockResponse = {
data: { ciCdSettingsUpdate: { errors: [], __typename: 'CiCdSettingsUpdatePayload' } },
};
......@@ -34,7 +43,12 @@ describe('Keep latest artifact checkbox', () => {
const createComponent = (handlers) => {
requestHandlers = {
keepLatestArtifactQueryHandler: jest.fn().mockResolvedValue(keepLatestArtifactMock),
keepLatestArtifactProjectQueryHandler: jest
.fn()
.mockResolvedValue(keepLatestArtifactProjectMock),
keepLatestArtifactApplicationQueryHandler: jest
.fn()
.mockResolvedValue(keepLatestArtifactApplicationMock),
keepLatestArtifactMutationHandler: jest
.fn()
.mockResolvedValue(keepLatestArtifactMockResponse),
......@@ -42,7 +56,11 @@ describe('Keep latest artifact checkbox', () => {
};
apolloProvider = createMockApollo([
[GetKeepLatestArtifactProjectSetting, requestHandlers.keepLatestArtifactQueryHandler],
[GetKeepLatestArtifactProjectSetting, requestHandlers.keepLatestArtifactProjectQueryHandler],
[
GetKeepLatestArtifactApplicationSetting,
requestHandlers.keepLatestArtifactApplicationQueryHandler,
],
[UpdateKeepLatestArtifactProjectSetting, requestHandlers.keepLatestArtifactMutationHandler],
]);
......@@ -51,38 +69,74 @@ describe('Keep latest artifact checkbox', () => {
fullPath,
helpPagePath,
},
stubs: {
GlFormCheckbox,
},
localVue,
apolloProvider,
});
};
beforeEach(() => {
createComponent();
});
afterEach(() => {
wrapper.destroy();
wrapper = null;
apolloProvider = null;
});
it('displays the checkbox and the help link', () => {
expect(findCheckbox().exists()).toBe(true);
expect(findHelpLink().exists()).toBe(true);
});
describe('default', () => {
beforeEach(() => {
createComponent();
});
it('sets correct setting value in checkbox with query result', async () => {
await wrapper.vm.$nextTick();
it('displays the checkbox and the help link', () => {
expect(findCheckbox().exists()).toBe(true);
expect(findHelpLink().exists()).toBe(true);
});
it('calls mutation on artifact setting change with correct payload', () => {
findCheckbox().vm.$emit('change', false);
expect(wrapper.element).toMatchSnapshot();
expect(requestHandlers.keepLatestArtifactMutationHandler).toHaveBeenCalledWith({
fullPath,
keepLatestArtifact: false,
});
});
});
it('calls mutation on artifact setting change with correct payload', () => {
findCheckbox().vm.$emit('change', false);
describe('when application keep latest artifact setting is enabled', () => {
beforeEach(() => {
createComponent();
});
it('sets correct setting value in checkbox with query result', async () => {
await wrapper.vm.$nextTick();
expect(wrapper.element).toMatchSnapshot();
});
it('checkbox is enabled when application setting is enabled', async () => {
await wrapper.vm.$nextTick();
expect(findCheckbox().attributes('disabled')).toBeUndefined();
});
});
expect(requestHandlers.keepLatestArtifactMutationHandler).toHaveBeenCalledWith({
fullPath,
keepLatestArtifact: false,
describe('when application keep latest artifact setting is disabled', () => {
it('checkbox is disabled when application setting is disabled', async () => {
createComponent({
keepLatestArtifactApplicationQueryHandler: jest.fn().mockResolvedValue({
data: {
ciApplicationSettings: {
keepLatestArtifact: false,
},
},
}),
});
await wrapper.vm.$nextTick();
expect(wrapper.element).toMatchSnapshot();
expect(findCheckbox().attributes('disabled')).toBe('true');
});
});
});
......@@ -235,7 +235,7 @@ RSpec.describe Gitlab::Ci::Pipeline::Chain::Build do
with_them do
before do
project.update!(ci_keep_latest_artifact: keep_latest_artifact)
project.update!(keep_latest_artifact: keep_latest_artifact)
end
it 'builds a pipeline with appropriate locked value' do
......
......@@ -3,6 +3,8 @@
require 'spec_helper'
RSpec.describe ProjectCiCdSetting do
using RSpec::Parameterized::TableSyntax
describe 'validations' do
it 'validates default_git_depth is between 0 and 1000 or nil' do
expect(subject).to validate_numericality_of(:default_git_depth)
......@@ -36,4 +38,39 @@ RSpec.describe ProjectCiCdSetting do
expect(project.reload.ci_cd_settings.default_git_depth).to eq(0)
end
end
describe '#keep_latest_artifacts_available?' do
let(:attrs) { { keep_latest_artifact: project_enabled } }
let(:project_settings) { described_class.new(attrs) }
subject { project_settings.keep_latest_artifacts_available? }
context 'without application setting record' do
where(:project_enabled, :result_keep_latest_artifact) do
false | false
true | true
end
with_them do
it { expect(subject).to eq(result_keep_latest_artifact) }
end
end
context 'with application setting record' do
where(:instance_enabled, :project_enabled, :result_keep_latest_artifact) do
false | false | false
false | true | false
true | false | false
true | true | true
end
before do
Gitlab::CurrentSettings.current_application_settings.update!(keep_latest_artifact: instance_enabled)
end
with_them do
it { expect(subject).to eq(result_keep_latest_artifact) }
end
end
end
end
......@@ -559,6 +559,25 @@ RSpec.describe Project, factory_default: :keep do
end
end
describe '#default_pipeline_lock' do
let(:project) { build_stubbed(:project) }
subject { project.default_pipeline_lock }
where(:keep_latest_artifact_enabled, :result_pipeline_locked) do
false | :unlocked
true | :artifacts_locked
end
before do
allow(project).to receive(:keep_latest_artifacts_available?).and_return(keep_latest_artifact_enabled)
end
with_them do
it { expect(subject).to eq(result_pipeline_locked) }
end
end
describe '#autoclose_referenced_issues' do
context 'when DB entry is nil' do
let(:project) { build(:project, autoclose_referenced_issues: nil) }
......
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe 'getting Application Settings' do
include GraphqlHelpers
let(:fields) do
<<~QUERY
#{all_graphql_fields_for('CiApplicationSettings', max_depth: 1)}
QUERY
end
let(:query) do
graphql_query_for(
'ciApplicationSettings',
fields
)
end
let(:settings_data) { graphql_data['ciApplicationSettings'] }
context 'without admin permissions' do
let(:user) { create(:user) }
before do
post_graphql(query, current_user: user)
end
it_behaves_like 'a working graphql query'
specify { expect(settings_data).to be nil }
end
context 'with admin permissions' do
let(:user) { create(:user, :admin) }
before do
post_graphql(query, current_user: user)
end
it_behaves_like 'a working graphql query'
it 'fetches the settings data' do
# assert against hash to ensure no additional fields are exposed
expect(settings_data).to match({ 'keepLatestArtifact' => Gitlab::CurrentSettings.current_application_settings.keep_latest_artifact })
end
end
end
......@@ -46,7 +46,7 @@ RSpec.describe 'Getting Ci Cd Setting' do
it 'fetches the settings data' do
expect(settings_data['mergePipelinesEnabled']).to eql project.ci_cd_settings.merge_pipelines_enabled?
expect(settings_data['mergeTrainsEnabled']).to eql project.ci_cd_settings.merge_trains_enabled?
expect(settings_data['keepLatestArtifact']).to eql project.ci_keep_latest_artifact?
expect(settings_data['keepLatestArtifact']).to eql project.keep_latest_artifacts_available?
end
end
end
......@@ -5,7 +5,7 @@ require 'spec_helper'
RSpec.describe 'CiCdSettingsUpdate' do
include GraphqlHelpers
let_it_be(:project) { create(:project, ci_keep_latest_artifact: true) }
let_it_be(:project) { create(:project, keep_latest_artifact: true) }
let(:variables) { { full_path: project.full_path, keep_latest_artifact: false } }
let(:mutation) { graphql_mutation(:ci_cd_settings_update, variables) }
......@@ -42,7 +42,7 @@ RSpec.describe 'CiCdSettingsUpdate' do
project.reload
expect(response).to have_gitlab_http_status(:success)
expect(project.ci_keep_latest_artifact).to eq(false)
expect(project.keep_latest_artifact).to eq(false)
end
context 'when bad arguments are provided' do
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment