summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2020-08-11 18:10:06 +0000
committerGitLab Bot <gitlab-bot@gitlab.com>2020-08-11 18:10:06 +0000
commit7a1895c74ad57da757c02b2675147a5a5e2cfe6d (patch)
tree7204fd4cdecbf1166f1aebca080994fcb7f290cd
parent9dde2726710184f066387d044fce4ae2b3684210 (diff)
downloadgitlab-ce-7a1895c74ad57da757c02b2675147a5a5e2cfe6d.tar.gz
Add latest changes from gitlab-org/gitlab@master
-rw-r--r--.gitlab/issue_templates/Documentation.md2
-rw-r--r--GITLAB_WORKHORSE_VERSION2
-rw-r--r--app/assets/javascripts/blob/suggest_gitlab_ci_yml/components/popover.vue12
-rw-r--r--app/assets/javascripts/boards/filtered_search_boards.js1
-rw-r--r--app/assets/javascripts/filtered_search/filtered_search_manager.js11
-rw-r--r--app/assets/javascripts/monitoring/constants.js2
-rw-r--r--app/assets/javascripts/operation_settings/components/metrics_settings.vue4
-rw-r--r--app/assets/javascripts/pages/admin/runners/index.js1
-rw-r--r--app/assets/javascripts/pages/dashboard/issues/index.js1
-rw-r--r--app/assets/javascripts/pages/dashboard/merge_requests/index.js1
-rw-r--r--app/assets/javascripts/pages/groups/issues/index.js1
-rw-r--r--app/assets/javascripts/pages/groups/merge_requests/index.js1
-rw-r--r--app/assets/javascripts/pages/groups/settings/ci_cd/show/index.js1
-rw-r--r--app/assets/javascripts/pages/projects/issues/index/index.js1
-rw-r--r--app/assets/javascripts/pages/projects/issues/service_desk/filtered_search.js1
-rw-r--r--app/assets/javascripts/pages/projects/merge_requests/index/index.js1
-rw-r--r--app/assets/javascripts/pages/search/init_filtered_search.js2
-rw-r--r--app/controllers/projects/artifacts_controller.rb2
-rw-r--r--app/models/ci/build.rb7
-rw-r--r--app/serializers/build_details_entity.rb8
-rw-r--r--app/services/projects/container_repository/cleanup_tags_service.rb3
-rw-r--r--changelogs/unreleased/213571-migrate-lm-to-ls-artifacts.yml5
-rw-r--r--changelogs/unreleased/219888-suggest-gitlab-ci-popover.yml5
-rw-r--r--changelogs/unreleased/232734-mlunoe-add-filtered-search-manager-setting-to-specify-to-use-default-state.yml5
-rw-r--r--changelogs/unreleased/astoicescu-gaugeChartToGaugeInYML.yml5
-rw-r--r--changelogs/unreleased/enable-ci_variables_api_filter_environment_scope-by-default.yml5
-rw-r--r--changelogs/unreleased/hash-cache-unlink.yml5
-rw-r--r--changelogs/unreleased/sh-bump-workhorse-8-38-0.yml5
-rw-r--r--db/post_migrate/20200808221641_add_index_for_license_compliance_artifacts.rb18
-rw-r--r--db/post_migrate/20200809221641_migrate_license_management_artifacts_to_license_scanning.rb49
-rw-r--r--db/schema_migrations/202008082216411
-rw-r--r--db/schema_migrations/202008092216411
-rw-r--r--db/structure.sql2
-rw-r--r--doc/administration/operations/moving_repositories.md47
-rw-r--r--doc/administration/redis/replication_and_failover.md68
-rw-r--r--doc/api/project_level_variables.md17
-rw-r--r--doc/install/aws/index.md3
-rw-r--r--doc/integration/jenkins.md18
-rw-r--r--doc/operations/incident_management/img/incident_list_create_v13_3.pngbin0 -> 21931 bytes
-rw-r--r--doc/operations/incident_management/img/incident_list_search_v13_3.pngbin0 -> 29780 bytes
-rw-r--r--doc/operations/incident_management/img/incident_list_sort_v13_3.pngbin0 -> 39524 bytes
-rw-r--r--doc/operations/incident_management/img/incident_list_v13_3.pngbin18894 -> 0 bytes
-rw-r--r--doc/operations/incident_management/img/incident_management_settings_v13_3.png (renamed from doc/operations/incident_management/img/incident_management_settings.png)bin14916 -> 14916 bytes
-rw-r--r--doc/operations/incident_management/img/pagerduty_incidents_integration_v13_3.png (renamed from doc/operations/incident_management/img/pagerduty_incidents_integration_13_3.png)bin43318 -> 43318 bytes
-rw-r--r--doc/operations/incident_management/index.md21
-rw-r--r--doc/operations/metrics/dashboards/panel_types.md6
-rw-r--r--doc/policy/maintenance.md6
-rw-r--r--doc/topics/autodevops/stages.md11
-rw-r--r--doc/topics/cron/index.md63
-rw-r--r--doc/topics/index.md1
-rw-r--r--doc/user/application_security/coverage_fuzzing/index.md11
-rw-r--r--lib/gitlab/ci/features.rb6
-rw-r--r--lib/gitlab/database/schema_version_files.rb38
-rw-r--r--lib/gitlab/repository_cache_adapter.rb2
-rw-r--r--lib/gitlab/repository_hash_cache.rb16
-rw-r--r--spec/fixtures/api/schemas/job/artifact.json3
-rw-r--r--spec/frontend/blob/suggest_gitlab_ci_yml/components/popover_spec.js4
-rw-r--r--spec/frontend/filtered_search/filtered_search_manager_spec.js26
-rw-r--r--spec/frontend/operation_settings/components/metrics_settings_spec.js7
-rw-r--r--spec/lib/gitlab/database/schema_version_files_spec.rb43
-rw-r--r--spec/lib/gitlab/repository_cache_adapter_spec.rb3
-rw-r--r--spec/lib/gitlab/repository_hash_cache_spec.rb18
-rw-r--r--spec/models/ci/build_spec.rb56
-rw-r--r--spec/models/repository_spec.rb12
-rw-r--r--spec/serializers/build_details_entity_spec.rb28
65 files changed, 551 insertions, 154 deletions
diff --git a/.gitlab/issue_templates/Documentation.md b/.gitlab/issue_templates/Documentation.md
index 43ee7cd448b..f05d7049b7f 100644
--- a/.gitlab/issue_templates/Documentation.md
+++ b/.gitlab/issue_templates/Documentation.md
@@ -24,7 +24,7 @@
* Any concepts, procedures, reference info we could add to make it easier to successfully use GitLab?
* Include use cases, benefits, and/or goals for this work.
* If adding content: What audience is it intended for? (What roles and scenarios?)
- For ideas, see personas at https://design.gitlab.com/research/personas or the persona labels at
+ For ideas, see personas at https://about.gitlab.com/handbook/marketing/product-marketing/roles-personas/ or the persona labels at
https://gitlab.com/groups/gitlab-org/-/labels?utf8=%E2%9C%93&subscribed=&search=persona%3A
-->
diff --git a/GITLAB_WORKHORSE_VERSION b/GITLAB_WORKHORSE_VERSION
index 2554e8ae98f..d10e2d87760 100644
--- a/GITLAB_WORKHORSE_VERSION
+++ b/GITLAB_WORKHORSE_VERSION
@@ -1 +1 @@
-8.37.0
+8.38.0
diff --git a/app/assets/javascripts/blob/suggest_gitlab_ci_yml/components/popover.vue b/app/assets/javascripts/blob/suggest_gitlab_ci_yml/components/popover.vue
index 932b6e8a0f7..aff6a56cb0b 100644
--- a/app/assets/javascripts/blob/suggest_gitlab_ci_yml/components/popover.vue
+++ b/app/assets/javascripts/blob/suggest_gitlab_ci_yml/components/popover.vue
@@ -1,5 +1,5 @@
<script>
-import { GlPopover, GlSprintf, GlDeprecatedButton, GlIcon } from '@gitlab/ui';
+import { GlPopover, GlSprintf, GlButton } from '@gitlab/ui';
import { parseBoolean, scrollToElement, setCookie, getCookie } from '~/lib/utils/common_utils';
import { s__ } from '~/locale';
import Tracking from '~/tracking';
@@ -29,8 +29,7 @@ export default {
components: {
GlPopover,
GlSprintf,
- GlIcon,
- GlDeprecatedButton,
+ GlButton,
},
mixins: [trackingMixin],
props: {
@@ -112,18 +111,17 @@ export default {
<template #title>
<span v-html="suggestTitle"></span>
<span class="ml-auto">
- <gl-deprecated-button
+ <gl-button
:aria-label="__('Close')"
class="btn-blank"
name="dismiss"
+ icon="close"
:data-track-property="humanAccess"
:data-track-value="$options.dismissTrackValue"
:data-track-event="$options.clickTrackValue"
:data-track-label="trackLabel"
@click="onDismiss"
- >
- <gl-icon name="close" aria-hidden="true" />
- </gl-deprecated-button>
+ />
</span>
</template>
diff --git a/app/assets/javascripts/boards/filtered_search_boards.js b/app/assets/javascripts/boards/filtered_search_boards.js
index ca85e54eb89..e083eecb0bc 100644
--- a/app/assets/javascripts/boards/filtered_search_boards.js
+++ b/app/assets/javascripts/boards/filtered_search_boards.js
@@ -10,6 +10,7 @@ export default class FilteredSearchBoards extends FilteredSearchManager {
isGroupDecendent: true,
stateFiltersSelector: '.issues-state-filters',
isGroup: IS_EE,
+ useDefaultState: false,
filteredSearchTokenKeys: IssuableFilteredSearchTokenKeys,
});
diff --git a/app/assets/javascripts/filtered_search/filtered_search_manager.js b/app/assets/javascripts/filtered_search/filtered_search_manager.js
index b728b2eee62..f6149d553fc 100644
--- a/app/assets/javascripts/filtered_search/filtered_search_manager.js
+++ b/app/assets/javascripts/filtered_search/filtered_search_manager.js
@@ -29,6 +29,7 @@ export default class FilteredSearchManager {
isGroup = false,
isGroupAncestor = true,
isGroupDecendent = false,
+ useDefaultState = false,
filteredSearchTokenKeys = IssuableFilteredSearchTokenKeys,
stateFiltersSelector = '.issues-state-filters',
placeholder = __('Search or filter results...'),
@@ -37,6 +38,7 @@ export default class FilteredSearchManager {
this.isGroup = isGroup;
this.isGroupAncestor = isGroupAncestor;
this.isGroupDecendent = isGroupDecendent;
+ this.useDefaultState = useDefaultState;
this.states = ['opened', 'closed', 'merged', 'all'];
this.page = page;
@@ -724,8 +726,13 @@ export default class FilteredSearchManager {
search(state = null) {
const paths = [];
const { tokens, searchToken } = this.getSearchTokens();
- const currentState = state || getParameterByName('state') || 'opened';
- paths.push(`state=${currentState}`);
+ let currentState = state || getParameterByName('state');
+ if (!currentState && this.useDefaultState) {
+ currentState = 'opened';
+ }
+ if (this.states.includes(currentState)) {
+ paths.push(`state=${currentState}`);
+ }
tokens.forEach(token => {
const condition = this.filteredSearchTokenKeys.searchByConditionKeyValue(
diff --git a/app/assets/javascripts/monitoring/constants.js b/app/assets/javascripts/monitoring/constants.js
index 7835050d033..81ad3137b8b 100644
--- a/app/assets/javascripts/monitoring/constants.js
+++ b/app/assets/javascripts/monitoring/constants.js
@@ -89,7 +89,7 @@ export const panelTypes = {
/**
* Gauge
*/
- GAUGE_CHART: 'gauge-chart',
+ GAUGE_CHART: 'gauge',
/**
* Heatmap
*/
diff --git a/app/assets/javascripts/operation_settings/components/metrics_settings.vue b/app/assets/javascripts/operation_settings/components/metrics_settings.vue
index 7fe986ef201..9df6a412930 100644
--- a/app/assets/javascripts/operation_settings/components/metrics_settings.vue
+++ b/app/assets/javascripts/operation_settings/components/metrics_settings.vue
@@ -1,6 +1,6 @@
<script>
import { mapState, mapActions } from 'vuex';
-import { GlDeprecatedButton as GlButton, GlLink } from '@gitlab/ui';
+import { GlButton, GlLink } from '@gitlab/ui';
import ExternalDashboard from './form_group/external_dashboard.vue';
import DashboardTimezone from './form_group/dashboard_timezone.vue';
@@ -45,7 +45,7 @@ export default {
<dashboard-timezone />
<external-dashboard />
<div class="gl-display-flex gl-justify-content-end">
- <gl-button variant="success" @click="saveChanges">
+ <gl-button variant="success" category="primary" @click="saveChanges">
{{ __('Save Changes') }}
</gl-button>
</div>
diff --git a/app/assets/javascripts/pages/admin/runners/index.js b/app/assets/javascripts/pages/admin/runners/index.js
index ce8fd18b6a2..e60c6133c7c 100644
--- a/app/assets/javascripts/pages/admin/runners/index.js
+++ b/app/assets/javascripts/pages/admin/runners/index.js
@@ -6,5 +6,6 @@ document.addEventListener('DOMContentLoaded', () => {
initFilteredSearch({
page: FILTERED_SEARCH.ADMIN_RUNNERS,
filteredSearchTokenKeys: AdminRunnersFilteredSearchTokenKeys,
+ useDefaultState: true,
});
});
diff --git a/app/assets/javascripts/pages/dashboard/issues/index.js b/app/assets/javascripts/pages/dashboard/issues/index.js
index 2ffeed8a584..71cdaf45052 100644
--- a/app/assets/javascripts/pages/dashboard/issues/index.js
+++ b/app/assets/javascripts/pages/dashboard/issues/index.js
@@ -8,6 +8,7 @@ document.addEventListener('DOMContentLoaded', () => {
initFilteredSearch({
page: FILTERED_SEARCH.ISSUES,
filteredSearchTokenKeys: IssuableFilteredSearchTokenKeys,
+ useDefaultState: true,
});
projectSelect();
diff --git a/app/assets/javascripts/pages/dashboard/merge_requests/index.js b/app/assets/javascripts/pages/dashboard/merge_requests/index.js
index 24d7b592948..10df18c85e7 100644
--- a/app/assets/javascripts/pages/dashboard/merge_requests/index.js
+++ b/app/assets/javascripts/pages/dashboard/merge_requests/index.js
@@ -10,6 +10,7 @@ document.addEventListener('DOMContentLoaded', () => {
initFilteredSearch({
page: FILTERED_SEARCH.MERGE_REQUESTS,
filteredSearchTokenKeys: IssuableFilteredSearchTokenKeys,
+ useDefaultState: true,
});
projectSelect();
diff --git a/app/assets/javascripts/pages/groups/issues/index.js b/app/assets/javascripts/pages/groups/issues/index.js
index 4f15f5ec58c..2496003919a 100644
--- a/app/assets/javascripts/pages/groups/issues/index.js
+++ b/app/assets/javascripts/pages/groups/issues/index.js
@@ -17,6 +17,7 @@ document.addEventListener('DOMContentLoaded', () => {
initFilteredSearch({
page: FILTERED_SEARCH.ISSUES,
isGroupDecendent: true,
+ useDefaultState: true,
filteredSearchTokenKeys: IssuableFilteredSearchTokenKeys,
});
projectSelect();
diff --git a/app/assets/javascripts/pages/groups/merge_requests/index.js b/app/assets/javascripts/pages/groups/merge_requests/index.js
index 13c5c350c24..71c67ac74ed 100644
--- a/app/assets/javascripts/pages/groups/merge_requests/index.js
+++ b/app/assets/javascripts/pages/groups/merge_requests/index.js
@@ -14,6 +14,7 @@ document.addEventListener('DOMContentLoaded', () => {
initFilteredSearch({
page: FILTERED_SEARCH.MERGE_REQUESTS,
isGroupDecendent: true,
+ useDefaultState: true,
filteredSearchTokenKeys: IssuableFilteredSearchTokenKeys,
});
projectSelect();
diff --git a/app/assets/javascripts/pages/groups/settings/ci_cd/show/index.js b/app/assets/javascripts/pages/groups/settings/ci_cd/show/index.js
index 920374924c9..add483843df 100644
--- a/app/assets/javascripts/pages/groups/settings/ci_cd/show/index.js
+++ b/app/assets/javascripts/pages/groups/settings/ci_cd/show/index.js
@@ -13,6 +13,7 @@ document.addEventListener('DOMContentLoaded', () => {
page: FILTERED_SEARCH.ADMIN_RUNNERS,
filteredSearchTokenKeys: GroupRunnersFilteredSearchTokenKeys,
anchor: FILTERED_SEARCH.GROUP_RUNNERS_ANCHOR,
+ useDefaultState: false,
});
if (gon.features.newVariablesUi) {
diff --git a/app/assets/javascripts/pages/projects/issues/index/index.js b/app/assets/javascripts/pages/projects/issues/index/index.js
index a66b665d152..1711d122080 100644
--- a/app/assets/javascripts/pages/projects/issues/index/index.js
+++ b/app/assets/javascripts/pages/projects/issues/index/index.js
@@ -17,6 +17,7 @@ document.addEventListener('DOMContentLoaded', () => {
initFilteredSearch({
page: FILTERED_SEARCH.ISSUES,
filteredSearchTokenKeys: IssuableFilteredSearchTokenKeys,
+ useDefaultState: true,
});
new IssuableIndex(ISSUABLE_INDEX.ISSUE);
diff --git a/app/assets/javascripts/pages/projects/issues/service_desk/filtered_search.js b/app/assets/javascripts/pages/projects/issues/service_desk/filtered_search.js
index 72003b61c8a..fc0922d9112 100644
--- a/app/assets/javascripts/pages/projects/issues/service_desk/filtered_search.js
+++ b/app/assets/javascripts/pages/projects/issues/service_desk/filtered_search.js
@@ -9,6 +9,7 @@ export default class FilteredSearchServiceDesk extends FilteredSearchManager {
super({
page: 'service_desk',
filteredSearchTokenKeys: IssuableFilteredSearchTokenKeys,
+ useDefaultState: true,
});
this.supportBotData = supportBotData;
diff --git a/app/assets/javascripts/pages/projects/merge_requests/index/index.js b/app/assets/javascripts/pages/projects/merge_requests/index/index.js
index 8f93cbb2a42..ce0b5c80927 100644
--- a/app/assets/javascripts/pages/projects/merge_requests/index/index.js
+++ b/app/assets/javascripts/pages/projects/merge_requests/index/index.js
@@ -13,6 +13,7 @@ document.addEventListener('DOMContentLoaded', () => {
initFilteredSearch({
page: FILTERED_SEARCH.MERGE_REQUESTS,
filteredSearchTokenKeys: IssuableFilteredSearchTokenKeys,
+ useDefaultState: true,
});
new IssuableIndex(ISSUABLE_INDEX.MERGE_REQUEST); // eslint-disable-line no-new
diff --git a/app/assets/javascripts/pages/search/init_filtered_search.js b/app/assets/javascripts/pages/search/init_filtered_search.js
index b331a2bee6a..eaed3246d06 100644
--- a/app/assets/javascripts/pages/search/init_filtered_search.js
+++ b/app/assets/javascripts/pages/search/init_filtered_search.js
@@ -6,6 +6,7 @@ export default ({
isGroup,
isGroupAncestor,
isGroupDecendent,
+ useDefaultState,
stateFiltersSelector,
anchor,
}) => {
@@ -16,6 +17,7 @@ export default ({
isGroup,
isGroupAncestor,
isGroupDecendent,
+ useDefaultState,
filteredSearchTokenKeys,
stateFiltersSelector,
anchor,
diff --git a/app/controllers/projects/artifacts_controller.rb b/app/controllers/projects/artifacts_controller.rb
index fef3c6cf424..652687932fd 100644
--- a/app/controllers/projects/artifacts_controller.rb
+++ b/app/controllers/projects/artifacts_controller.rb
@@ -108,7 +108,7 @@ class Projects::ArtifactsController < Projects::ApplicationController
end
def validate_artifacts!
- render_404 unless build&.artifacts?
+ render_404 unless build&.available_artifacts?
end
def build
diff --git a/app/models/ci/build.rb b/app/models/ci/build.rb
index b28560bf94b..af4e6bb0494 100644
--- a/app/models/ci/build.rb
+++ b/app/models/ci/build.rb
@@ -647,6 +647,13 @@ module Ci
!artifacts_expired? && artifacts_file&.exists?
end
+ # This method is similar to #artifacts? but it includes the artifacts
+ # locking mechanics. A new method was created to prevent breaking existing
+ # behavior and avoid introducing N+1s.
+ def available_artifacts?
+ (!artifacts_expired? || pipeline.artifacts_locked?) && job_artifacts_archive&.exists?
+ end
+
def artifacts_metadata?
artifacts? && artifacts_metadata&.exists?
end
diff --git a/app/serializers/build_details_entity.rb b/app/serializers/build_details_entity.rb
index 6036a9db288..523f1a0f8c6 100644
--- a/app/serializers/build_details_entity.rb
+++ b/app/serializers/build_details_entity.rb
@@ -27,11 +27,11 @@ class BuildDetailsEntity < JobEntity
end
expose :artifact, if: -> (*) { can?(current_user, :read_build, build) } do
- expose :download_path, if: -> (*) { build.artifacts? } do |build|
+ expose :download_path, if: -> (*) { build.pipeline.artifacts_locked? || build.artifacts? } do |build|
download_project_job_artifacts_path(project, build)
end
- expose :browse_path, if: -> (*) { build.browsable_artifacts? } do |build|
+ expose :browse_path, if: -> (*) { build.pipeline.artifacts_locked? || build.browsable_artifacts? } do |build|
browse_project_job_artifacts_path(project, build)
end
@@ -46,6 +46,10 @@ class BuildDetailsEntity < JobEntity
expose :expired, if: -> (*) { build.artifacts_expire_at.present? } do |build|
build.artifacts_expired?
end
+
+ expose :locked do |build|
+ build.pipeline.artifacts_locked?
+ end
end
expose :report_artifacts,
diff --git a/app/services/projects/container_repository/cleanup_tags_service.rb b/app/services/projects/container_repository/cleanup_tags_service.rb
index 085bebd225d..204a54ff23a 100644
--- a/app/services/projects/container_repository/cleanup_tags_service.rb
+++ b/app/services/projects/container_repository/cleanup_tags_service.rb
@@ -39,9 +39,6 @@ module Projects
end
def filter_by_name(tags)
- # Technical Debt: https://gitlab.com/gitlab-org/gitlab/issues/207267
- # name_regex to be removed when container_expiration_policies is updated
- # to have both regex columns
regex_delete = ::Gitlab::UntrustedRegexp.new("\\A#{params['name_regex_delete'] || params['name_regex']}\\z")
regex_retain = ::Gitlab::UntrustedRegexp.new("\\A#{params['name_regex_keep']}\\z")
diff --git a/changelogs/unreleased/213571-migrate-lm-to-ls-artifacts.yml b/changelogs/unreleased/213571-migrate-lm-to-ls-artifacts.yml
new file mode 100644
index 00000000000..29e66683519
--- /dev/null
+++ b/changelogs/unreleased/213571-migrate-lm-to-ls-artifacts.yml
@@ -0,0 +1,5 @@
+---
+title: Migrate license_management artifacts to license_scanning type
+merge_request: 36817
+author:
+type: changed
diff --git a/changelogs/unreleased/219888-suggest-gitlab-ci-popover.yml b/changelogs/unreleased/219888-suggest-gitlab-ci-popover.yml
new file mode 100644
index 00000000000..8661a4f8486
--- /dev/null
+++ b/changelogs/unreleased/219888-suggest-gitlab-ci-popover.yml
@@ -0,0 +1,5 @@
+---
+title: Update suggest gitlab ci popover to gl-button
+merge_request: 37987
+author:
+type: changed
diff --git a/changelogs/unreleased/232734-mlunoe-add-filtered-search-manager-setting-to-specify-to-use-default-state.yml b/changelogs/unreleased/232734-mlunoe-add-filtered-search-manager-setting-to-specify-to-use-default-state.yml
new file mode 100644
index 00000000000..2b40034221b
--- /dev/null
+++ b/changelogs/unreleased/232734-mlunoe-add-filtered-search-manager-setting-to-specify-to-use-default-state.yml
@@ -0,0 +1,5 @@
+---
+title: Fix bug where filtering would sometimes display only open issues on different pages listing issues
+merge_request: 38906
+author:
+type: fixed
diff --git a/changelogs/unreleased/astoicescu-gaugeChartToGaugeInYML.yml b/changelogs/unreleased/astoicescu-gaugeChartToGaugeInYML.yml
new file mode 100644
index 00000000000..43169e5819c
--- /dev/null
+++ b/changelogs/unreleased/astoicescu-gaugeChartToGaugeInYML.yml
@@ -0,0 +1,5 @@
+---
+title: Change "gauge-chart" to "gauge" in YML panel configuration for gauge charts
+merge_request: 39184
+author:
+type: changed
diff --git a/changelogs/unreleased/enable-ci_variables_api_filter_environment_scope-by-default.yml b/changelogs/unreleased/enable-ci_variables_api_filter_environment_scope-by-default.yml
new file mode 100644
index 00000000000..5f6c1d4e630
--- /dev/null
+++ b/changelogs/unreleased/enable-ci_variables_api_filter_environment_scope-by-default.yml
@@ -0,0 +1,5 @@
+---
+title: Enable FF ci_variables_api_filter_environment_scope by default
+merge_request: 39209
+author:
+type: changed
diff --git a/changelogs/unreleased/hash-cache-unlink.yml b/changelogs/unreleased/hash-cache-unlink.yml
new file mode 100644
index 00000000000..c927b8abaf9
--- /dev/null
+++ b/changelogs/unreleased/hash-cache-unlink.yml
@@ -0,0 +1,5 @@
+---
+title: Swap RepositoryHashCache to UNLINK
+merge_request: 39105
+author:
+type: performance
diff --git a/changelogs/unreleased/sh-bump-workhorse-8-38-0.yml b/changelogs/unreleased/sh-bump-workhorse-8-38-0.yml
new file mode 100644
index 00000000000..c81028e60a6
--- /dev/null
+++ b/changelogs/unreleased/sh-bump-workhorse-8-38-0.yml
@@ -0,0 +1,5 @@
+---
+title: Upgrade Workhorse to v8.38.0
+merge_request: 39223
+author:
+type: added
diff --git a/db/post_migrate/20200808221641_add_index_for_license_compliance_artifacts.rb b/db/post_migrate/20200808221641_add_index_for_license_compliance_artifacts.rb
new file mode 100644
index 00000000000..fce4ee095bd
--- /dev/null
+++ b/db/post_migrate/20200808221641_add_index_for_license_compliance_artifacts.rb
@@ -0,0 +1,18 @@
+# frozen_string_literal: true
+
+class AddIndexForLicenseComplianceArtifacts < ActiveRecord::Migration[6.0]
+ include Gitlab::Database::MigrationHelpers
+
+ DOWNTIME = false
+ INDEX_NAME = 'index_ci_job_artifacts_on_license_compliance_file_types'
+
+ disable_ddl_transaction!
+
+ def up
+ add_concurrent_index :ci_job_artifacts, [:job_id, :file_type], where: 'file_type = 10 OR file_type = 101', name: INDEX_NAME
+ end
+
+ def down
+ remove_concurrent_index_by_name :ci_job_artifacts, name: INDEX_NAME
+ end
+end
diff --git a/db/post_migrate/20200809221641_migrate_license_management_artifacts_to_license_scanning.rb b/db/post_migrate/20200809221641_migrate_license_management_artifacts_to_license_scanning.rb
new file mode 100644
index 00000000000..dcc8e4d11b2
--- /dev/null
+++ b/db/post_migrate/20200809221641_migrate_license_management_artifacts_to_license_scanning.rb
@@ -0,0 +1,49 @@
+# frozen_string_literal: true
+
+class MigrateLicenseManagementArtifactsToLicenseScanning < ActiveRecord::Migration[6.0]
+ DOWNTIME = false
+ LICENSE_MANAGEMENT_FILE_TYPE = 10
+ LICENSE_SCANNING_FILE_TYPE = 101
+
+ disable_ddl_transaction!
+
+ class JobArtifact < ActiveRecord::Base
+ include EachBatch
+
+ self.table_name = 'ci_job_artifacts'
+ end
+
+ # We're updating file_type of ci artifacts from license_management to license_scanning
+ # But before that we need to delete "rogue" artifacts for CI builds that have associated with them
+ # both license_scanning and license_management artifacts. It's an edge case and usually, we don't have
+ # such builds in the database.
+ def up
+ return unless Gitlab.ee?
+
+ JobArtifact
+ .where("file_type = 10 OR file_type = 101")
+ .each_batch(column: :job_id, of: 1000) do |relation|
+ min, max = relation.pluck('MIN(job_id)', 'MAX(job_id)').flatten
+
+ ActiveRecord::Base.connection.execute <<~SQL
+ WITH ci_job_artifacts_with_row_number as (
+ SELECT job_id, id, ROW_NUMBER() OVER (PARTITION BY job_id ORDER BY id ASC) as row_number
+ FROM ci_job_artifacts
+ WHERE (file_type = #{LICENSE_SCANNING_FILE_TYPE} OR file_type = #{LICENSE_MANAGEMENT_FILE_TYPE})
+ AND job_id >= #{Integer(min)} AND job_id < #{Integer(max)}
+ )
+ DELETE FROM ci_job_artifacts
+ WHERE ci_job_artifacts.id IN (SELECT id from ci_job_artifacts_with_row_number WHERE ci_job_artifacts_with_row_number.row_number > 1)
+ SQL
+ end
+
+ JobArtifact.where(file_type: LICENSE_MANAGEMENT_FILE_TYPE).each_batch(of: 1000) do |relation|
+ relation.update_all(file_type: LICENSE_SCANNING_FILE_TYPE)
+ end
+ end
+
+ def down
+ # no-op
+ # we're deleting duplicating artifacts and updating file_type for license_management artifacts
+ end
+end
diff --git a/db/schema_migrations/20200808221641 b/db/schema_migrations/20200808221641
new file mode 100644
index 00000000000..05e3769247e
--- /dev/null
+++ b/db/schema_migrations/20200808221641
@@ -0,0 +1 @@
+a24aa5052d37bff1bffc5df076d8422ea90f3781ae01ecf626bc59f3e299c90b \ No newline at end of file
diff --git a/db/schema_migrations/20200809221641 b/db/schema_migrations/20200809221641
new file mode 100644
index 00000000000..4e43680663a
--- /dev/null
+++ b/db/schema_migrations/20200809221641
@@ -0,0 +1 @@
+4e360aa1b375e391ec1202f1fe2eb26d64895faf326ec9c7a9b8d8351b6f4dc3 \ No newline at end of file
diff --git a/db/structure.sql b/db/structure.sql
index 86fa7a40734..c215ba1eba5 100644
--- a/db/structure.sql
+++ b/db/structure.sql
@@ -19202,6 +19202,8 @@ CREATE INDEX index_ci_job_artifacts_on_file_store ON public.ci_job_artifacts USI
CREATE UNIQUE INDEX index_ci_job_artifacts_on_job_id_and_file_type ON public.ci_job_artifacts USING btree (job_id, file_type);
+CREATE INDEX index_ci_job_artifacts_on_license_compliance_file_types ON public.ci_job_artifacts USING btree (job_id, file_type) WHERE ((file_type = 10) OR (file_type = 101));
+
CREATE INDEX index_ci_job_artifacts_on_project_id ON public.ci_job_artifacts USING btree (project_id);
CREATE INDEX index_ci_job_artifacts_on_project_id_for_security_reports ON public.ci_job_artifacts USING btree (project_id) WHERE (file_type = ANY (ARRAY[5, 6, 7, 8]));
diff --git a/doc/administration/operations/moving_repositories.md b/doc/administration/operations/moving_repositories.md
index 960005fe25d..4763c012538 100644
--- a/doc/administration/operations/moving_repositories.md
+++ b/doc/administration/operations/moving_repositories.md
@@ -9,16 +9,17 @@ We will look at three scenarios: the target directory is empty, the
target directory contains an outdated copy of the repositories, and
how to deal with thousands of repositories.
-**Each of the approaches we list can/will overwrite data in the
+DANGER: **Danger:**
+Each of the approaches we list can/will overwrite data in the
target directory `/mnt/gitlab/repositories`. Do not mix up the
-source and the target.**
+source and the target.
-## Target directory is empty: use a tar pipe
+## Target directory is empty: use a `tar` pipe
If the target directory `/mnt/gitlab/repositories` is empty the
-simplest thing to do is to use a tar pipe. This method has low
-overhead and tar is almost always already installed on your system.
-However, it is not possible to resume an interrupted tar pipe: if
+simplest thing to do is to use a `tar` pipe. This method has low
+overhead and `tar` is almost always already installed on your system.
+However, it is not possible to resume an interrupted `tar` pipe: if
that happens then all data must be copied again.
```shell
@@ -28,9 +29,9 @@ sudo -u git sh -c 'tar -C /var/opt/gitlab/git-data/repositories -cf - -- . |\
If you want to see progress, replace `-xf` with `-xvf`.
-### Tar pipe to another server
+### `tar` pipe to another server
-You can also use a tar pipe to copy data to another server. If your
+You can also use a `tar` pipe to copy data to another server. If your
`git` user has SSH access to the new server as `git@newserver`, you
can pipe the data through SSH.
@@ -42,13 +43,13 @@ sudo -u git sh -c 'tar -C /var/opt/gitlab/git-data/repositories -cf - -- . |\
If you want to compress the data before it goes over the network
(which will cost you CPU cycles) you can replace `ssh` with `ssh -C`.
-## The target directory contains an outdated copy of the repositories: use rsync
+## The target directory contains an outdated copy of the repositories: use `rsync`
If the target directory already contains a partial / outdated copy
of the repositories it may be wasteful to copy all the data again
-with tar. In this scenario it is better to use rsync. This utility
+with `tar`. In this scenario it is better to use `rsync`. This utility
is either already installed on your system or easily installable
-via apt, yum etc.
+via `apt`, `yum`, etc.
```shell
sudo -u git sh -c 'rsync -a --delete /var/opt/gitlab/git-data/repositories/. \
@@ -59,30 +60,30 @@ The `/.` in the command above is very important, without it you can
easily get the wrong directory structure in the target directory.
If you want to see progress, replace `-a` with `-av`.
-### Single rsync to another server
+### Single `rsync` to another server
If the `git` user on your source system has SSH access to the target
-server you can send the repositories over the network with rsync.
+server you can send the repositories over the network with `rsync`.
```shell
sudo -u git sh -c 'rsync -a --delete /var/opt/gitlab/git-data/repositories/. \
git@newserver:/mnt/gitlab/repositories'
```
-## Thousands of Git repositories: use one rsync per repository
+## Thousands of Git repositories: use one `rsync` per repository
-Every time you start an rsync job it has to inspect all files in
+Every time you start an `rsync` job it has to inspect all files in
the source directory, all files in the target directory, and then
decide what files to copy or not. If the source or target directory
-has many contents this startup phase of rsync can become a burden
-for your GitLab server. In cases like this you can make rsync's
+has many contents this startup phase of `rsync` can become a burden
+for your GitLab server. In cases like this you can make `rsync`'s
life easier by dividing its work in smaller pieces, and sync one
repository at a time.
-In addition to rsync we will use [GNU
+In addition to `rsync` we will use [GNU
Parallel](http://www.gnu.org/software/parallel/). This utility is
-not included in GitLab so you need to install it yourself with apt
-or yum. Also note that the GitLab scripts we used below were added
+not included in GitLab so you need to install it yourself with `apt`
+or `yum`. Also note that the GitLab scripts we used below were added
in GitLab 8.1.
**This process does not clean up repositories at the target location that no
@@ -90,9 +91,9 @@ longer exist at the source.** If you start using your GitLab instance with
`/mnt/gitlab/repositories`, you need to run `gitlab-rake gitlab:cleanup:repos`
after switching to the new repository storage directory.
-### Parallel rsync for all repositories known to GitLab
+### Parallel `rsync` for all repositories known to GitLab
-This will sync repositories with 10 rsync processes at a time. We keep
+This will sync repositories with 10 `rsync` processes at a time. We keep
track of progress so that the transfer can be restarted if necessary.
First we create a new directory, owned by `git`, to hold transfer
@@ -147,7 +148,7 @@ cat /home/git/transfer-logs/* | sort | uniq -u |\
`
```
-### Parallel rsync only for repositories with recent activity
+### Parallel `rsync` only for repositories with recent activity
Suppose you have already done one sync that started after 2015-10-1 12:00 UTC.
Then you might only want to sync repositories that were changed via GitLab
diff --git a/doc/administration/redis/replication_and_failover.md b/doc/administration/redis/replication_and_failover.md
index 66ff4b24f93..ca041adb1d8 100644
--- a/doc/administration/redis/replication_and_failover.md
+++ b/doc/administration/redis/replication_and_failover.md
@@ -637,47 +637,63 @@ lives easier. If you want to know what happens underneath keep reading.
### Running multiple Redis clusters
-GitLab supports running [separate Redis clusters for different persistent
-classes](https://docs.gitlab.com/omnibus/settings/redis.html#running-with-multiple-redis-instances):
-cache, queues, and shared_state. To make this work with Sentinel:
+Omnibus GitLab supports running separate Redis and Sentinel instances for different
+persistence classes.
-1. Set the appropriate variable in `/etc/gitlab/gitlab.rb` for each instance you are using:
+| Class | Purpose |
+| -------------- | ------------------------------------------------ |
+| `cache` | Store cached data. |
+| `queues` | Store Sidekiq background jobs. |
+| `shared_state` | Store session-related and other persistent data. |
+| `actioncable` | Pub/Sub queue backend for ActionCable. |
+
+To make this work with Sentinel:
+
+1. [Configure the different Redis/Sentinels](#configuring-redis) instances based on your needs.
+1. For each Rails application instance, edit its `/etc/gitlab/gitlab.rb` file:
```ruby
gitlab_rails['redis_cache_instance'] = REDIS_CACHE_URL
gitlab_rails['redis_queues_instance'] = REDIS_QUEUES_URL
gitlab_rails['redis_shared_state_instance'] = REDIS_SHARED_STATE_URL
- ```
-
- **Note**: Redis URLs should be in the format: `redis://:PASSWORD@SENTINEL_PRIMARY_NAME`
+ gitlab_rails['redis_actioncable_instance'] = REDIS_ACTIONCABLE_URL
- 1. PASSWORD is the plaintext password for the Redis instance
- 1. SENTINEL_PRIMARY_NAME is the Sentinel primary name (e.g. `gitlab-redis-cache`)
-
-1. Include an array of hashes with host/port combinations, such as the following:
-
- ```ruby
+ # Configure the Sentinels
gitlab_rails['redis_cache_sentinels'] = [
- { host: REDIS_CACHE_SENTINEL_HOST, port: PORT1 },
- { host: REDIS_CACHE_SENTINEL_HOST2, port: PORT2 }
+ { host: REDIS_CACHE_SENTINEL_HOST, port: 26379 },
+ { host: REDIS_CACHE_SENTINEL_HOST2, port: 26379 }
]
gitlab_rails['redis_queues_sentinels'] = [
- { host: REDIS_QUEUES_SENTINEL_HOST, port: PORT1 },
- { host: REDIS_QUEUES_SENTINEL_HOST2, port: PORT2 }
+ { host: REDIS_QUEUES_SENTINEL_HOST, port: 26379 },
+ { host: REDIS_QUEUES_SENTINEL_HOST2, port: 26379 }
]
gitlab_rails['redis_shared_state_sentinels'] = [
- { host: SHARED_STATE_SENTINEL_HOST, port: PORT1 },
- { host: SHARED_STATE_SENTINEL_HOST2, port: PORT2 }
+ { host: SHARED_STATE_SENTINEL_HOST, port: 26379 },
+ { host: SHARED_STATE_SENTINEL_HOST2, port: 26379 }
+ ]
+ gitlab_rails['redis_actioncable_sentinels'] = [
+ { host: ACTIONCABLE_SENTINEL_HOST, port: 26379 },
+ { host: ACTIONCABLE_SENTINEL_HOST2, port: 26379 }
]
```
-1. Note that for each persistence class, GitLab will default to using the
- configuration specified in `gitlab_rails['redis_sentinels']` unless
- overridden by the settings above.
-1. Be sure to include BOTH configuration options for each persistent classes. For example,
- if you choose to configure a cache instance, you must specify both `gitlab_rails['redis_cache_instance']`
- and `gitlab_rails['redis_cache_sentinels']` for GitLab to generate the proper configuration files.
-1. Run `gitlab-ctl reconfigure`
+ Note that:
+
+ - Redis URLs should be in the format: `redis://:PASSWORD@SENTINEL_PRIMARY_NAME`, where:
+ - `PASSWORD` is the plaintext password for the Redis instance.
+ - `SENTINEL_PRIMARY_NAME` is the Sentinel primary name set with `redis['master_name']`,
+ for example `gitlab-redis-cache`.
+
+1. Save the file and reconfigure GitLab for the change to take effect:
+
+ ```shell
+ sudo gitlab-ctl reconfigure
+ ```
+
+NOTE: **Note:**
+For each persistence class, GitLab will default to using the
+configuration specified in `gitlab_rails['redis_sentinels']` unless
+overridden by the previously described settings.
### Control running services
diff --git a/doc/api/project_level_variables.md b/doc/api/project_level_variables.md
index 07835b318f4..4760816f5d0 100644
--- a/doc/api/project_level_variables.md
+++ b/doc/api/project_level_variables.md
@@ -155,8 +155,10 @@ curl --request DELETE --header "PRIVATE-TOKEN: <your_access_token>" "https://git
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/34490) in GitLab 13.2.
> - It's deployed behind a feature flag, disabled by default.
-> - It's disabled on GitLab.com.
-> - To use it in GitLab self-managed instances, ask a GitLab administrator to enable it.
+> - [Became enabled by default](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/39209) on GitLab 13.3.
+> - It's enabled on GitLab.com.
+> - It's recommended for production use.
+> - For GitLab self-managed instances, GitLab administrators can opt to [disable it](#enable-or-disable).
This parameter is used for filtering by attributes, such as `environment_scope`.
@@ -168,17 +170,18 @@ curl --request DELETE --header "PRIVATE-TOKEN: <your_access_token>" "https://git
### Enable or disable
+It is deployed behind a feature flag that is **enabled by default**.
[GitLab administrators with access to the GitLab Rails console](../administration/feature_flags.md)
-can enable it for your instance.
+can opt to disable it for your instance.
-To enable it:
+To disable it:
```ruby
-Feature.enable(:ci_variables_api_filter_environment_scope)
+Feature.disable(:ci_variables_api_filter_environment_scope)
```
-To disable it:
+To enable it:
```ruby
-Feature.disable(:ci_variables_api_filter_environment_scope)
+Feature.enable(:ci_variables_api_filter_environment_scope)
```
diff --git a/doc/install/aws/index.md b/doc/install/aws/index.md
index e76d6bfa6c9..1ffeebce711 100644
--- a/doc/install/aws/index.md
+++ b/doc/install/aws/index.md
@@ -247,6 +247,9 @@ On the EC2 dashboard, look for Load Balancer in the left navigation bar:
1. For **Ping Port**, enter 80.
1. For **Ping Path**, enter `/users/sign_in`. (We use `/users/sign_in` as it's a public endpoint that does
not require authorization.)
+
+ NOTE: **Note:**
+ When booting a fresh GitLab instance for the first time, GitLab redirects you to `/users/password/` to change the admin password. Temporarily change the health check to this URL (or to the TCP protocol) and change it back to `/users/sign_in` after setting the admin password.
1. Keep the default **Advanced Details** or adjust them according to your needs.
1. Click **Add EC2 Instances** - don't add anything as we will create an Auto Scaling Group later to manage instances for us.
1. Click **Add Tags** and add any tags you need.
diff --git a/doc/integration/jenkins.md b/doc/integration/jenkins.md
index 002ee35bc59..8fc638db95a 100644
--- a/doc/integration/jenkins.md
+++ b/doc/integration/jenkins.md
@@ -147,24 +147,6 @@ Configure the GitLab integration with Jenkins.
authentication.
1. Click **Test settings and save changes**. GitLab tests the connection to Jenkins.
-## Plugin functional overview
-
-GitLab does not contain a database table listing commits. Commits are always
-read from the repository directly. Therefore, it's not possible to retain the
-build status of a commit in GitLab. This is overcome by requesting build
-information from the integrated CI tool. The CI tool is responsible for creating
-and storing build status for Commits and Merge Requests.
-
-### Steps required to implement a similar integration
-
-NOTE: **Note:**
-All steps are implemented using AJAX requests on the merge request page.
-
-1. In order to display the build status in a merge request you must create a project service in GitLab.
-1. Your project service will do a (JSON) query to a URL of the CI tool with the SHA1 of the commit.
-1. The project service builds this URL and payload based on project service settings and knowledge of the CI tool.
-1. The response is parsed to give a response in GitLab (success/failed/pending).
-
## Troubleshooting
### Error in merge requests - "Could not connect to the CI server"
diff --git a/doc/operations/incident_management/img/incident_list_create_v13_3.png b/doc/operations/incident_management/img/incident_list_create_v13_3.png
new file mode 100644
index 00000000000..a000c849099
--- /dev/null
+++ b/doc/operations/incident_management/img/incident_list_create_v13_3.png
Binary files differ
diff --git a/doc/operations/incident_management/img/incident_list_search_v13_3.png b/doc/operations/incident_management/img/incident_list_search_v13_3.png
new file mode 100644
index 00000000000..293268986cc
--- /dev/null
+++ b/doc/operations/incident_management/img/incident_list_search_v13_3.png
Binary files differ
diff --git a/doc/operations/incident_management/img/incident_list_sort_v13_3.png b/doc/operations/incident_management/img/incident_list_sort_v13_3.png
new file mode 100644
index 00000000000..4a263aa188e
--- /dev/null
+++ b/doc/operations/incident_management/img/incident_list_sort_v13_3.png
Binary files differ
diff --git a/doc/operations/incident_management/img/incident_list_v13_3.png b/doc/operations/incident_management/img/incident_list_v13_3.png
deleted file mode 100644
index 7cfa4382d4a..00000000000
--- a/doc/operations/incident_management/img/incident_list_v13_3.png
+++ /dev/null
Binary files differ
diff --git a/doc/operations/incident_management/img/incident_management_settings.png b/doc/operations/incident_management/img/incident_management_settings_v13_3.png
index 761a782ce61..761a782ce61 100644
--- a/doc/operations/incident_management/img/incident_management_settings.png
+++ b/doc/operations/incident_management/img/incident_management_settings_v13_3.png
Binary files differ
diff --git a/doc/operations/incident_management/img/pagerduty_incidents_integration_13_3.png b/doc/operations/incident_management/img/pagerduty_incidents_integration_v13_3.png
index 0991e963e02..0991e963e02 100644
--- a/doc/operations/incident_management/img/pagerduty_incidents_integration_13_3.png
+++ b/doc/operations/incident_management/img/pagerduty_incidents_integration_v13_3.png
Binary files differ
diff --git a/doc/operations/incident_management/index.md b/doc/operations/incident_management/index.md
index 6b493c79e59..5db6c76a42b 100644
--- a/doc/operations/incident_management/index.md
+++ b/doc/operations/incident_management/index.md
@@ -24,7 +24,7 @@ For users with at least Developer [permissions](../../user/permissions.md), the
Incident Management list is available at **Operations > Incidents**
in your project's sidebar. The list contains the following metrics:
-![Incident Management List](img/incident_list_v13_3.png)
+![Incident Management List](img/incident_list_sort_v13_3.png)
- **Incident** - The description of the incident, which attempts to capture the
most meaningful data.
@@ -32,6 +32,19 @@ in your project's sidebar. The list contains the following metrics:
standard GitLab pattern of `X time ago`, but is supported by a granular date/time
tooltip depending on the user's locale.
- **Assignees** - The user assigned to the incident.
+- **Published** - Whether or not an incident is published to the
+ [Status Page](./status_page.md). **(ULTIMATE)**
+
+The Incident Management list displays incidents sorted by incident created date.
+([Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/229534) to GitLab core in 13.3).)
+To see if a column is sortable, point your mouse at the header. Sortable columns
+display an arrow next to the column name.
+
+The Incident list supports a simple free text search, which filters on the
+**Title** and **Incident** fields.
+
+To filter incidents by their status, click **Open**, **Closed**, or **All**
+above the incident list.
NOTE: **Note:**
Incidents share the [Issues API](../../user/project/issues/index.md).
@@ -325,7 +338,7 @@ to create issues when alerts are triggered:
1. Navigate to **Settings > Operations > Incidents** and expand
**Incidents**:
- ![Incident Management Settings](img/incident_management_settings.png)
+ ![Incident Management Settings](img/incident_management_settings_v13_3.png)
1. For GitLab versions 11.11 and greater, you can select the **Create an issue**
checkbox to create an issue based on your own
@@ -365,6 +378,8 @@ For users with at least Developer [permissions](../../user/permissions.md), to c
- Create a new issue using the `incident` template available when creating it.
- Create a new issue and assign the `incident` label to it.
+![Incident List Create](img/incident_list_create_v13_3.png)
+
## Configure PagerDuty integration
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/119018) in GitLab 13.3.
@@ -377,7 +392,7 @@ in both PagerDuty and GitLab:
1. Navigate to **Settings > Operations > Incidents** and expand **Incidents**.
1. Select the **PagerDuty integration** tab:
- ![PagerDuty incidents integration](img/pagerduty_incidents_integration_13_3.png)
+ ![PagerDuty incidents integration](img/pagerduty_incidents_integration_v13_3.png)
1. Activate the integration, and save the changes in GitLab.
1. Copy the value of **Webhook URL** for use in a later step.
diff --git a/doc/operations/metrics/dashboards/panel_types.md b/doc/operations/metrics/dashboards/panel_types.md
index 1afad9c6181..b2cbdcb88d9 100644
--- a/doc/operations/metrics/dashboards/panel_types.md
+++ b/doc/operations/metrics/dashboards/panel_types.md
@@ -243,7 +243,7 @@ panel_groups:
- group: 'Group Title'
panels:
- title: "Gauge"
- type: "gauge-chart"
+ type: "gauge"
min_value: 0
max_value: 1000
split: 5
@@ -261,7 +261,7 @@ Note the following properties:
| Property | Type | Required | Description |
| ------ | ------ | ------ | ------ |
-| type | string | yes | Type of panel to be rendered. For gauge panel types, set to `gauge-chart`. |
+| type | string | yes | Type of panel to be rendered. For gauge panel types, set to `gauge`. |
| min_value | number | no, defaults to `0` | The minimum value of the gauge chart axis. If either of `min_value` or `max_value` are not set, they both get their default values. |
| max_value | number | no, defaults to `100` | The maximum value of the gauge chart axis. If either of `min_value` or `max_value` are not set, they both get their default values. |
| split | number | no, defaults to `10` | The amount of split segments on the gauge chart axis. |
@@ -276,7 +276,7 @@ Note the following properties:
| values | array | no, defaults to 95% of the range between `min_value` and `max_value`| An array of gauge chart axis threshold values. |
| mode | string | no, defaults to `absolute` | The mode in which the thresholds are interpreted in relation to `min_value` and `max_value`. Can be either `percentage` or `absolute`. |
-![gauge chart panel type](img/prometheus_dashboard_gauge_panel_type_v13_3.png)
+![gauge panel type](img/prometheus_dashboard_gauge_panel_type_v13_3.png)
## Heatmaps
diff --git a/doc/policy/maintenance.md b/doc/policy/maintenance.md
index 5b3fc3e0021..7f3f75d933d 100644
--- a/doc/policy/maintenance.md
+++ b/doc/policy/maintenance.md
@@ -112,9 +112,9 @@ Please see the table below for some examples:
| Target version | Your version | Recommended upgrade path | Note |
| --------------------- | ------------ | ------------------------ | ---- |
-| `13.2.0` | `11.5.0` | `11.5.0` -> `11.11.8` -> `12.0.12` -> `12.10.6` -> `13.0.0` -> `13.2.0` | Four intermediate versions are required: the final `11.11`, `12.0`, and `12.10` releases, plus `13.0`. |
-| `13.0.1` | `11.10.8` | `11.10.5` -> `11.11.8` -> `12.0.12` -> `12.10.6` -> `13.0.1` | Three intermediate versions are required: `11.11`, `12.0`, and `12.10`. |
-| `12.10.6` | `11.3.4` | `11.3.4` -> `11.11.8` -> `12.0.12` -> `12.10.6` | Two intermediate versions are required: `11.11` and `12.0` |
+| `13.2.3` | `11.5.0` | `11.5.0` -> `11.11.8` -> `12.0.12` -> `12.10.14` -> `13.0.12` -> `13.2.3` | Four intermediate versions are required: the final `11.11`, `12.0`, and `12.10` releases, plus `13.0`. |
+| `13.0.12` | `11.10.8` | `11.10.5` -> `11.11.8` -> `12.0.12` -> `12.10.14` -> `13.0.12` | Three intermediate versions are required: `11.11`, `12.0`, and `12.10`. |
+| `12.10.14` | `11.3.4` | `11.3.4` -> `11.11.8` -> `12.0.12` -> `12.10.14` | Two intermediate versions are required: `11.11` and `12.0` |
| `12.9.5` | `10.4.5` | `10.4.5` -> `10.8.7` -> `11.11.8` -> `12.0.12` -> `12.9.5` | Three intermediate versions are required: `10.8`, `11.11`, and `12.0`, then `12.9.5` |
| `12.2.5` | `9.2.6` | `9.2.6` -> `9.5.10` -> `10.8.7` -> `11.11.8` -> `12.0.12` -> `12.2.5` | Four intermediate versions are required: `9.5`, `10.8`, `11.11`, `12.0`, then `12.2`. |
| `11.3.4` | `8.13.4` | `8.13.4` -> `8.17.7` -> `9.5.10` -> `10.8.7` -> `11.3.4` | `8.17.7` is the last version in version 8, `9.5.10` is the last version in version 9, `10.8.7` is the last version in version 10. |
diff --git a/doc/topics/autodevops/stages.md b/doc/topics/autodevops/stages.md
index bf17eb55aee..7c6cf043820 100644
--- a/doc/topics/autodevops/stages.md
+++ b/doc/topics/autodevops/stages.md
@@ -460,8 +460,9 @@ For example, in a Rails application in an image built with
Unless your repository contains a `Dockerfile`, your image is built with
Herokuish, and you must prefix commands run in these images with
-`/bin/herokuish procfile exec` to replicate the environment where your application
-will run.
+`/bin/herokuish procfile exec` (for Herokuish) or `/cnb/lifecycle/launcher`
+(for Cloud Native Buildpacks) to replicate the environment where your
+application runs.
### Upgrade auto-deploy-app Chart
@@ -622,6 +623,12 @@ For example, to start a Rails console from the application root directory, run:
/bin/herokuish procfile exec bin/rails c
```
+When using Cloud Native Buildpacks, instead of `/bin/herokuish procfile exec`, use
+
+```shell
+/cnb/lifecycle/launcher $COMMAND
+```
+
## Auto Monitoring
After your application deploys, Auto Monitoring helps you monitor
diff --git a/doc/topics/cron/index.md b/doc/topics/cron/index.md
new file mode 100644
index 00000000000..a3dd3b77c22
--- /dev/null
+++ b/doc/topics/cron/index.md
@@ -0,0 +1,63 @@
+# Cron
+
+Cron syntax is used to schedule when jobs should run.
+
+You may need to use a cron syntax string to
+[trigger nightly pipelines](../../ci/triggers/README.md#using-cron-to-trigger-nightly-pipelines),
+create a [pipeline schedule](../../api/pipeline_schedules.md#create-a-new-pipeline-schedule),
+or to prevent unintentional releases by setting a
+[deploy freeze](../../user/project/releases/index.md#prevent-unintentional-releases-by-setting-a-deploy-freeze).
+
+## Cron syntax
+
+Cron scheduling uses a series of five numbers, separated by spaces:
+
+```plaintext
+# ┌───────────── minute (0 - 59)
+# │ ┌───────────── hour (0 - 23)
+# │ │ ┌───────────── day of the month (1 - 31)
+# │ │ │ ┌───────────── month (1 - 12)
+# │ │ │ │ ┌───────────── day of the week (0 - 6) (Sunday to Saturday)
+# │ │ │ │ │
+# │ │ │ │ │
+# │ │ │ │ │
+# * * * * * <command to execute>
+```
+
+[Source: [Wikipedia](https://en.wikipedia.org/wiki/Cron)]
+
+In cron syntax, the asterisk (`*`) means 'every,' so the following cron strings
+are valid:
+
+- Run once an hour at the beginning of the hour: `0 * * * *`
+- Run once a day at midnight: `0 0 * * *`
+- Run once a week at midnight on Sunday morning: `0 0 * * 0`
+- Run once a month at midnight of the first day of the month: `0 0 1 * *`
+- Run once a year at midnight of 1 January: `0 0 1 1 *`
+
+For complete cron documentation, refer to the
+[crontab(5) — Linux manual page](https://man7.org/linux/man-pages/man5/crontab.5.html).
+This documentation is accessible offline by entering `man 5 crontab` in a Linux or MacOS
+terminal.
+
+## Cron examples
+
+```plaintext
+# Run at 7:00pm every day:
+0 19 * * *
+
+# Run every minute on the 10th of June:
+* * 3 6 *
+
+# Run at 06:30 every Friday:
+30 6 * * 5
+```
+
+More examples of how to write a cron schedule can be found at
+[crontab.guru](https://crontab.guru/examples.html).
+
+## How GitLab parses cron syntax strings
+
+GitLab uses [fugit](https://github.com/floraison/fugit) to parse cron syntax
+strings on the server and [cron-validate](https://github.com/Airfooox/cron-validate)
+to validate cron syntax in the browser.
diff --git a/doc/topics/index.md b/doc/topics/index.md
index c926735482c..3b92bbb55cb 100644
--- a/doc/topics/index.md
+++ b/doc/topics/index.md
@@ -10,6 +10,7 @@ tutorials, technical overviews, blog posts) and videos.
- [Auto DevOps](autodevops/index.md)
- [Authentication](authentication/index.md)
- [Continuous Integration (GitLab CI/CD)](../ci/README.md)
+- [Cron](cron/index.md)
- [Git](git/index.md)
- [GitLab Flow](gitlab_flow.md)
- [GitLab Installation](../install/README.md)
diff --git a/doc/user/application_security/coverage_fuzzing/index.md b/doc/user/application_security/coverage_fuzzing/index.md
index 23f1ee825fd..ce0110dfdbf 100644
--- a/doc/user/application_security/coverage_fuzzing/index.md
+++ b/doc/user/application_security/coverage_fuzzing/index.md
@@ -161,6 +161,17 @@ The `gitlab-cov-fuzz` command passes all arguments it receives to the underlying
can therefore use all the options available in that fuzzing engine. For more information on these
options, see the underlying fuzzing engine's documentation.
+### Offline Environment
+
+To use coverage fuzzing in an offline environment, follow these steps:
+
+1. Clone [`gitlab-cov-fuzz`](https://gitlab.com/gitlab-org/security-products/analyzers/gitlab-cov-fuzz)
+ to a private repository that your offline GitLab instance can access.
+
+1. For each fuzzing step, set `COVFUZZ_URL_PREFIX` to `${NEW_URL_GITLAB_COV_FUZ}/-/raw`, where
+ `NEW_URL_GITLAB_COV_FUZ` is the URL of the private `gitlab-cov-fuzz` clone that you set up in the
+ first step.
+
### Glossary
- Seed corpus: The set of test cases given as initial input to the fuzz target. This usually speeds
diff --git a/lib/gitlab/ci/features.rb b/lib/gitlab/ci/features.rb
index ea40de56cbc..356e881a0a5 100644
--- a/lib/gitlab/ci/features.rb
+++ b/lib/gitlab/ci/features.rb
@@ -41,13 +41,11 @@ module Gitlab
# Remove in https://gitlab.com/gitlab-org/gitlab/-/issues/227052
def self.variables_api_filter_environment_scope?
- ::Feature.enabled?(:ci_variables_api_filter_environment_scope, default_enabled: false)
+ ::Feature.enabled?(:ci_variables_api_filter_environment_scope, default_enabled: true)
end
- # This FF is only used for development purpose to test that warnings can be
- # raised and propagated to the UI.
def self.raise_job_rules_without_workflow_rules_warning?
- ::Feature.enabled?(:ci_raise_job_rules_without_workflow_rules_warning)
+ ::Feature.enabled?(:ci_raise_job_rules_without_workflow_rules_warning, default_enabled: true)
end
def self.keep_latest_artifacts_for_ref_enabled?(project)
diff --git a/lib/gitlab/database/schema_version_files.rb b/lib/gitlab/database/schema_version_files.rb
index 97b91d1a8d1..27a942404ef 100644
--- a/lib/gitlab/database/schema_version_files.rb
+++ b/lib/gitlab/database/schema_version_files.rb
@@ -3,14 +3,19 @@
module Gitlab
module Database
class SchemaVersionFiles
- SCHEMA_DIRECTORY = "db/schema_migrations"
+ SCHEMA_DIRECTORY = 'db/schema_migrations'
+ MIGRATION_DIRECTORIES = %w[db/migrate db/post_migrate].freeze
+ MIGRATION_VERSION_GLOB = '20[0-9][0-9]*'
- def self.touch_all(versions)
- filenames_with_path = find_version_filenames.map { |f| schema_dirpath.join(f) }
- FileUtils.rm(filenames_with_path)
+ def self.touch_all(versions_from_database)
+ versions_from_migration_files = find_versions_from_migration_files
- versions.each do |version|
- version_filepath = schema_dirpath.join(version)
+ version_filepaths = find_version_filenames.map { |f| schema_directory.join(f) }
+ FileUtils.rm(version_filepaths)
+
+ versions_to_create = versions_from_database & versions_from_migration_files
+ versions_to_create.each do |version|
+ version_filepath = schema_directory.join(version)
File.open(version_filepath, 'w') do |file|
file << Digest::SHA256.hexdigest(version)
@@ -25,17 +30,30 @@ module Gitlab
values = version_filenames.map { |vf| "('#{connection.quote_string(vf)}')" }
connection.execute(<<~SQL)
INSERT INTO schema_migrations (version)
- VALUES #{values.join(",")}
+ VALUES #{values.join(',')}
ON CONFLICT DO NOTHING
SQL
end
- def self.schema_dirpath
- @schema_dirpath ||= Rails.root.join(SCHEMA_DIRECTORY)
+ def self.schema_directory
+ @schema_directory ||= Rails.root.join(SCHEMA_DIRECTORY)
+ end
+
+ def self.migration_directories
+ @migration_directories ||= MIGRATION_DIRECTORIES.map { |dir| Rails.root.join(dir) }
end
def self.find_version_filenames
- Dir.glob("20[0-9][0-9]*", base: schema_dirpath)
+ Dir.glob(MIGRATION_VERSION_GLOB, base: schema_directory)
+ end
+
+ def self.find_versions_from_migration_files
+ migration_directories.each_with_object([]) do |directory, migration_versions|
+ directory_migrations = Dir.glob(MIGRATION_VERSION_GLOB, base: directory)
+ directory_versions = directory_migrations.map! { |m| m.split('_').first }
+
+ migration_versions.concat(directory_versions)
+ end
end
def self.connection
diff --git a/lib/gitlab/repository_cache_adapter.rb b/lib/gitlab/repository_cache_adapter.rb
index 688a4a39dba..da8025d2265 100644
--- a/lib/gitlab/repository_cache_adapter.rb
+++ b/lib/gitlab/repository_cache_adapter.rb
@@ -241,7 +241,7 @@ module Gitlab
end
def expire_redis_hash_method_caches(methods)
- methods.each { |name| redis_hash_cache.delete(name) }
+ redis_hash_cache.delete(*methods)
end
# All cached repository methods depend on the existence of a Git repository,
diff --git a/lib/gitlab/repository_hash_cache.rb b/lib/gitlab/repository_hash_cache.rb
index d2a7b450000..d479d3115a6 100644
--- a/lib/gitlab/repository_hash_cache.rb
+++ b/lib/gitlab/repository_hash_cache.rb
@@ -31,10 +31,18 @@ module Gitlab
"#{type}:#{namespace}:hash"
end
- # @param key [String]
- # @return [Integer] 0 or 1 depending on success
- def delete(key)
- with { |redis| redis.del(cache_key(key)) }
+ # @param keys [String] one or multiple keys to delete
+ # @return [Integer] the number of keys successfully deleted
+ def delete(*keys)
+ return 0 if keys.empty?
+
+ with do |redis|
+ keys = keys.map { |key| cache_key(key) }
+
+ Gitlab::Instrumentation::RedisClusterValidator.allow_cross_slot_commands do
+ redis.unlink(*keys)
+ end
+ end
end
# Check if the provided hash key exists in the hash.
diff --git a/spec/fixtures/api/schemas/job/artifact.json b/spec/fixtures/api/schemas/job/artifact.json
index 1812e69fbd6..f4a69e66141 100644
--- a/spec/fixtures/api/schemas/job/artifact.json
+++ b/spec/fixtures/api/schemas/job/artifact.json
@@ -5,7 +5,8 @@
"browse_path": { "type": "string"},
"keep_path": { "type": "string"},
"expired": { "type": "boolean" },
- "expire_at": { "type": "string", "format": "date-time" }
+ "expire_at": { "type": "string", "format": "date-time" },
+ "locked": { "type": "boolean" }
},
"additionalProperties": false
}
diff --git a/spec/frontend/blob/suggest_gitlab_ci_yml/components/popover_spec.js b/spec/frontend/blob/suggest_gitlab_ci_yml/components/popover_spec.js
index 3c03e6f04ab..d82ee6f1e1f 100644
--- a/spec/frontend/blob/suggest_gitlab_ci_yml/components/popover_spec.js
+++ b/spec/frontend/blob/suggest_gitlab_ci_yml/components/popover_spec.js
@@ -2,7 +2,7 @@ import { shallowMount } from '@vue/test-utils';
import Popover from '~/blob/suggest_gitlab_ci_yml/components/popover.vue';
import { mockTracking, unmockTracking, triggerEvent } from 'helpers/tracking_helper';
import * as utils from '~/lib/utils/common_utils';
-import { GlDeprecatedButton } from '@gitlab/ui';
+import { GlButton } from '@gitlab/ui';
jest.mock('~/lib/utils/common_utils', () => ({
...jest.requireActual('~/lib/utils/common_utils'),
@@ -96,7 +96,7 @@ describe('Suggest gitlab-ci.yml Popover', () => {
const expectedAction = 'click_button';
const expectedProperty = 'owner';
const expectedValue = '10';
- const dismissButton = wrapper.find(GlDeprecatedButton);
+ const dismissButton = wrapper.find(GlButton);
trackingSpy = mockTracking('_category_', wrapper.element, jest.spyOn);
triggerEvent(dismissButton.element);
diff --git a/spec/frontend/filtered_search/filtered_search_manager_spec.js b/spec/frontend/filtered_search/filtered_search_manager_spec.js
index 37a5e294f7a..53c726a6cea 100644
--- a/spec/frontend/filtered_search/filtered_search_manager_spec.js
+++ b/spec/frontend/filtered_search/filtered_search_manager_spec.js
@@ -77,7 +77,7 @@ describe('Filtered Search Manager', () => {
jest.spyOn(FilteredSearchDropdownManager.prototype, 'setDropdown').mockImplementation();
});
- const initializeManager = () => {
+ const initializeManager = ({ useDefaultState } = {}) => {
jest.spyOn(FilteredSearchManager.prototype, 'loadSearchParamsFromURL').mockImplementation();
jest.spyOn(FilteredSearchManager.prototype, 'tokenChange').mockImplementation();
jest
@@ -88,7 +88,7 @@ describe('Filtered Search Manager', () => {
input = document.querySelector('.filtered-search');
tokensContainer = document.querySelector('.tokens-container');
- manager = new FilteredSearchManager({ page });
+ manager = new FilteredSearchManager({ page, useDefaultState });
manager.setup();
};
@@ -184,17 +184,27 @@ describe('Filtered Search Manager', () => {
});
describe('search', () => {
- const defaultParams = '?scope=all&utf8=%E2%9C%93&state=opened';
+ const defaultParams = '?scope=all&utf8=%E2%9C%93';
+ const defaultState = '&state=opened';
- beforeEach(() => {
+ it('should search with a single word', done => {
initializeManager();
+ input.value = 'searchTerm';
+
+ visitUrl.mockImplementation(url => {
+ expect(url).toEqual(`${defaultParams}&search=searchTerm`);
+ done();
+ });
+
+ manager.search();
});
- it('should search with a single word', done => {
+ it('sets default state', done => {
+ initializeManager({ useDefaultState: true });
input.value = 'searchTerm';
visitUrl.mockImplementation(url => {
- expect(url).toEqual(`${defaultParams}&search=searchTerm`);
+ expect(url).toEqual(`${defaultParams}${defaultState}&search=searchTerm`);
done();
});
@@ -202,6 +212,7 @@ describe('Filtered Search Manager', () => {
});
it('should search with multiple words', done => {
+ initializeManager();
input.value = 'awesome search terms';
visitUrl.mockImplementation(url => {
@@ -213,6 +224,7 @@ describe('Filtered Search Manager', () => {
});
it('should search with special characters', done => {
+ initializeManager();
input.value = '~!@#$%^&*()_+{}:<>,.?/';
visitUrl.mockImplementation(url => {
@@ -226,6 +238,7 @@ describe('Filtered Search Manager', () => {
});
it('should use replacement URL for condition', done => {
+ initializeManager();
tokensContainer.innerHTML = FilteredSearchSpecHelper.createTokensContainerHTML(
FilteredSearchSpecHelper.createFilterVisualTokenHTML('milestone', '=', '13', true),
);
@@ -246,6 +259,7 @@ describe('Filtered Search Manager', () => {
});
it('removes duplicated tokens', done => {
+ initializeManager();
tokensContainer.innerHTML = FilteredSearchSpecHelper.createTokensContainerHTML(`
${FilteredSearchSpecHelper.createFilterVisualTokenHTML('label', '=', '~bug')}
${FilteredSearchSpecHelper.createFilterVisualTokenHTML('label', '=', '~bug')}
diff --git a/spec/frontend/operation_settings/components/metrics_settings_spec.js b/spec/frontend/operation_settings/components/metrics_settings_spec.js
index a1b219d1d52..cb7606ed939 100644
--- a/spec/frontend/operation_settings/components/metrics_settings_spec.js
+++ b/spec/frontend/operation_settings/components/metrics_settings_spec.js
@@ -1,5 +1,5 @@
import { mount, shallowMount } from '@vue/test-utils';
-import { GlDeprecatedButton, GlLink, GlFormGroup, GlFormInput, GlFormSelect } from '@gitlab/ui';
+import { GlButton, GlLink, GlFormGroup, GlFormInput, GlFormSelect } from '@gitlab/ui';
import { TEST_HOST } from 'helpers/test_constants';
import MetricsSettings from '~/operation_settings/components/metrics_settings.vue';
@@ -61,7 +61,7 @@ describe('operation settings external dashboard component', () => {
describe('expand/collapse button', () => {
it('renders as an expand button by default', () => {
- const button = wrapper.find(GlDeprecatedButton);
+ const button = wrapper.find(GlButton);
expect(button.text()).toBe('Expand');
});
@@ -160,8 +160,7 @@ describe('operation settings external dashboard component', () => {
});
describe('submit button', () => {
- const findSubmitButton = () =>
- wrapper.find('.settings-content form').find(GlDeprecatedButton);
+ const findSubmitButton = () => wrapper.find('.settings-content form').find(GlButton);
const endpointRequest = [
operationsSettingsEndpoint,
diff --git a/spec/lib/gitlab/database/schema_version_files_spec.rb b/spec/lib/gitlab/database/schema_version_files_spec.rb
index 95122836213..c3b3ae0a07f 100644
--- a/spec/lib/gitlab/database/schema_version_files_spec.rb
+++ b/spec/lib/gitlab/database/schema_version_files_spec.rb
@@ -4,30 +4,53 @@ require 'spec_helper'
RSpec.describe Gitlab::Database::SchemaVersionFiles do
describe '.touch_all' do
- let(:versions) { %w[2020123 2020456 2020890] }
-
- it 'creates a file containing a checksum for each version given' do
+ let(:version1) { '20200123' }
+ let(:version2) { '20200410' }
+ let(:version3) { '20200602' }
+ let(:version4) { '20200809' }
+ let(:relative_schema_directory) { 'db/schema_migrations' }
+ let(:relative_migrate_directory) { 'db/migrate' }
+ let(:relative_post_migrate_directory) { 'db/post_migrate' }
+
+ it 'creates a file containing a checksum for each version with a matching migration' do
Dir.mktmpdir do |tmpdir|
- schema_dirpath = Pathname.new(tmpdir).join("test")
- FileUtils.mkdir_p(schema_dirpath)
+ schema_directory = Pathname.new(tmpdir).join(relative_schema_directory)
+ migrate_directory = Pathname.new(tmpdir).join(relative_migrate_directory)
+ post_migrate_directory = Pathname.new(tmpdir).join(relative_post_migrate_directory)
+
+ FileUtils.mkdir_p(migrate_directory)
+ FileUtils.mkdir_p(post_migrate_directory)
+ FileUtils.mkdir_p(schema_directory)
+
+ migration1_filepath = migrate_directory.join("#{version1}_migration.rb")
+ FileUtils.touch(migration1_filepath)
- old_version_filepath = schema_dirpath.join("2020001")
+ migration2_filepath = post_migrate_directory.join("#{version2}_post_migration.rb")
+ FileUtils.touch(migration2_filepath)
+
+ old_version_filepath = schema_directory.join('20200101')
FileUtils.touch(old_version_filepath)
expect(File.exist?(old_version_filepath)).to be(true)
- allow(described_class).to receive(:schema_dirpath).and_return(schema_dirpath)
+ allow(described_class).to receive(:schema_directory).and_return(schema_directory)
+ allow(described_class).to receive(:migration_directories).and_return([migrate_directory, post_migrate_directory])
- described_class.touch_all(versions)
+ described_class.touch_all([version1, version2, version3, version4])
expect(File.exist?(old_version_filepath)).to be(false)
- versions.each do |version|
- version_filepath = schema_dirpath.join(version)
+ [version1, version2].each do |version|
+ version_filepath = schema_directory.join(version)
expect(File.exist?(version_filepath)).to be(true)
hashed_value = Digest::SHA256.hexdigest(version)
expect(File.read(version_filepath)).to eq(hashed_value)
end
+
+ [version3, version4].each do |version|
+ version_filepath = schema_directory.join(version)
+ expect(File.exist?(version_filepath)).to be(false)
+ end
end
end
end
diff --git a/spec/lib/gitlab/repository_cache_adapter_spec.rb b/spec/lib/gitlab/repository_cache_adapter_spec.rb
index 3727217203e..4129deef57c 100644
--- a/spec/lib/gitlab/repository_cache_adapter_spec.rb
+++ b/spec/lib/gitlab/repository_cache_adapter_spec.rb
@@ -212,8 +212,7 @@ RSpec.describe Gitlab::RepositoryCacheAdapter do
expect(cache).to receive(:expire).with(:rendered_readme)
expect(cache).to receive(:expire).with(:branch_names)
expect(redis_set_cache).to receive(:expire).with(:rendered_readme, :branch_names)
- expect(redis_hash_cache).to receive(:delete).with(:rendered_readme)
- expect(redis_hash_cache).to receive(:delete).with(:branch_names)
+ expect(redis_hash_cache).to receive(:delete).with(:rendered_readme, :branch_names)
repository.expire_method_caches(%i(rendered_readme branch_names))
end
diff --git a/spec/lib/gitlab/repository_hash_cache_spec.rb b/spec/lib/gitlab/repository_hash_cache_spec.rb
index ea856c14a77..9b4ca3f9dca 100644
--- a/spec/lib/gitlab/repository_hash_cache_spec.rb
+++ b/spec/lib/gitlab/repository_hash_cache_spec.rb
@@ -48,6 +48,24 @@ RSpec.describe Gitlab::RepositoryHashCache, :clean_gitlab_redis_cache do
context "key doesn't exist" do
it { is_expected.to eq(0) }
end
+
+ context "multiple keys" do
+ before do
+ cache.write(:test1, test_hash)
+ cache.write(:test2, test_hash)
+ end
+
+ it "deletes multiple keys" do
+ cache.delete(:test1, :test2)
+
+ expect(cache.read_members(:test1, ["test"])).to eq("test" => nil)
+ expect(cache.read_members(:test2, ["test"])).to eq("test" => nil)
+ end
+
+ it "returns deleted key count" do
+ expect(cache.delete(:test1, :test2)).to eq(2)
+ end
+ end
end
describe "#key?" do
diff --git a/spec/models/ci/build_spec.rb b/spec/models/ci/build_spec.rb
index 0f410a15901..9e63b524d69 100644
--- a/spec/models/ci/build_spec.rb
+++ b/spec/models/ci/build_spec.rb
@@ -612,6 +612,62 @@ RSpec.describe Ci::Build do
end
end
+ describe '#available_artifacts?' do
+ let(:build) { create(:ci_build) }
+
+ subject { build.available_artifacts? }
+
+ context 'when artifacts are not expired' do
+ before do
+ build.artifacts_expire_at = Date.tomorrow
+ end
+
+ context 'when artifacts exist' do
+ before do
+ create(:ci_job_artifact, :archive, job: build)
+ end
+
+ it { is_expected.to be_truthy }
+ end
+
+ context 'when artifacts do not exist' do
+ it { is_expected.to be_falsey }
+ end
+ end
+
+ context 'when artifacts are expired' do
+ before do
+ build.artifacts_expire_at = Date.yesterday
+ end
+
+ context 'when artifacts are not locked' do
+ before do
+ build.pipeline.locked = :unlocked
+ end
+
+ it { is_expected.to be_falsey }
+ end
+
+ context 'when artifacts are locked' do
+ before do
+ build.pipeline.locked = :artifacts_locked
+ end
+
+ context 'when artifacts exist' do
+ before do
+ create(:ci_job_artifact, :archive, job: build)
+ end
+
+ it { is_expected.to be_truthy }
+ end
+
+ context 'when artifacts do not exist' do
+ it { is_expected.to be_falsey }
+ end
+ end
+ end
+ end
+
describe '#browsable_artifacts?' do
subject { build.browsable_artifacts? }
diff --git a/spec/models/repository_spec.rb b/spec/models/repository_spec.rb
index 07b32aa69ef..48dee1e6481 100644
--- a/spec/models/repository_spec.rb
+++ b/spec/models/repository_spec.rb
@@ -587,15 +587,19 @@ RSpec.describe Repository do
end
it "is expired when the branches caches are expired" do
- expect(cache).to receive(:delete).with(:merged_branch_names).at_least(:once)
+ expect(cache).to receive(:delete) do |*args|
+ expect(args).to include(:merged_branch_names)
+ end
- repository.send(:expire_branches_cache)
+ repository.expire_branches_cache
end
it "is expired when the repository caches are expired" do
- expect(cache).to receive(:delete).with(:merged_branch_names).at_least(:once)
+ expect(cache).to receive(:delete) do |*args|
+ expect(args).to include(:merged_branch_names)
+ end
- repository.send(:expire_all_method_caches)
+ repository.expire_all_method_caches
end
end
diff --git a/spec/serializers/build_details_entity_spec.rb b/spec/serializers/build_details_entity_spec.rb
index ef6472e07a0..3166c08ff4e 100644
--- a/spec/serializers/build_details_entity_spec.rb
+++ b/spec/serializers/build_details_entity_spec.rb
@@ -185,12 +185,38 @@ RSpec.describe BuildDetailsEntity do
end
end
+ context 'when the build has expired artifacts' do
+ let!(:build) { create(:ci_build, :artifacts, artifacts_expire_at: 7.days.ago) }
+
+ it 'does not expose any artifact actions path' do
+ expect(subject[:artifact].keys).not_to include(:download_path, :browse_path, :keep_path)
+ end
+
+ it 'artifact locked is false' do
+ expect(subject.dig(:artifact, :locked)).to eq(false)
+ end
+
+ context 'when the pipeline is artifacts_locked' do
+ before do
+ build.pipeline.update!(locked: :artifacts_locked)
+ end
+
+ it 'artifact locked is true' do
+ expect(subject.dig(:artifact, :locked)).to eq(true)
+ end
+
+ it 'exposes download and browse artifact actions path' do
+ expect(subject[:artifact].keys).to include(:download_path, :browse_path)
+ end
+ end
+ end
+
context 'when the build has archive type artifacts' do
let!(:build) { create(:ci_build, :artifacts, artifacts_expire_at: 7.days.from_now) }
let!(:report) { create(:ci_job_artifact, :codequality, job: build) }
it 'exposes artifact details' do
- expect(subject[:artifact].keys).to include(:download_path, :browse_path, :keep_path, :expire_at, :expired)
+ expect(subject[:artifact].keys).to include(:download_path, :browse_path, :keep_path, :expire_at, :expired, :locked)
end
end
end