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

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2021-12-13 21:15:18 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2021-12-13 21:15:18 +0300
commit999cc13e0a77fad7322fbbe559013565355c2bfb (patch)
treecda92e5b004f6e4527f91acb1d24f228880a4526
parentaacba12c6e9817b552989de77b54e89b7c863b85 (diff)
Add latest changes from gitlab-org/gitlab@master
-rw-r--r--.gitlab/ci/rails.gitlab-ci.yml11
-rw-r--r--.rubocop_todo/gitlab/delegate_predicate_methods.yml3
-rw-r--r--GITALY_SERVER_VERSION2
-rw-r--r--app/assets/javascripts/environments/components/confirm_rollback_modal.vue41
-rw-r--r--app/assets/javascripts/environments/components/environment_rollback.vue34
-rw-r--r--app/assets/javascripts/environments/graphql/mutations/set_environment_to_rollback.mutation.graphql3
-rw-r--r--app/assets/javascripts/environments/graphql/queries/environment_to_rollback.query.graphql7
-rw-r--r--app/assets/javascripts/environments/graphql/resolvers.js7
-rw-r--r--app/assets/javascripts/environments/graphql/typedefs.graphql2
-rw-r--r--app/assets/javascripts/issuable/bulk_update_sidebar/issuable_bulk_update_actions.js2
-rw-r--r--app/assets/javascripts/issuable/bulk_update_sidebar/issuable_bulk_update_sidebar.js8
-rw-r--r--app/assets/javascripts/issuable/index.js2
-rw-r--r--app/assets/javascripts/issues/show/components/incidents/highlight_bar.vue2
-rw-r--r--app/assets/javascripts/issues/show/components/incidents/incident_tabs.vue2
-rw-r--r--app/assets/javascripts/issues_list/components/issuables_list_app.vue8
-rw-r--r--app/assets/javascripts/jobs/components/table/cells/actions_cell.vue11
-rw-r--r--app/assets/javascripts/jobs/components/table/constants.js3
-rw-r--r--app/assets/javascripts/jobs/components/table/graphql/queries/get_jobs.query.graphql1
-rw-r--r--app/assets/javascripts/labels/labels_select.js2
-rw-r--r--app/controllers/projects/issues_controller.rb4
-rw-r--r--app/graphql/types/packages/package_type.rb3
-rw-r--r--app/models/concerns/resolvable_discussion.rb5
-rw-r--r--app/models/repository.rb2
-rw-r--r--app/views/projects/issues/index.html.haml2
-rw-r--r--app/views/projects/merge_requests/index.html.haml2
-rw-r--r--config/feature_flags/development/geo_pages_deployment_verification.yml8
-rw-r--r--data/deprecations/14-6-pipeline-fields-package-deprecation.yml12
-rw-r--r--db/migrate/20211119154221_create_pages_deployment_states.rb38
-rw-r--r--db/post_migrate/20211208171402_reschedule_recalculate_vulnerability_finding_signatures_for_findings.rb27
-rw-r--r--db/schema_migrations/202111191542211
-rw-r--r--db/schema_migrations/202112081714021
-rw-r--r--db/structure.sql39
-rw-r--r--doc/administration/monitoring/prometheus/gitlab_metrics.md12
-rw-r--r--doc/api/graphql/reference/index.md4
-rw-r--r--doc/raketasks/index.md1
-rw-r--r--doc/raketasks/user_management.md4
-rw-r--r--doc/security/reset_user_password.md149
-rw-r--r--doc/update/deprecations.md9
-rw-r--r--doc/user/application_security/dast/index.md5
-rw-r--r--doc/user/packages/container_registry/index.md15
-rw-r--r--doc/user/project/releases/img/feature_count_v14_6.pngbin0 -> 24569 bytes
-rw-r--r--doc/user/project/releases/index.md23
-rw-r--r--doc/user/project/wiki/img/content_editor_v14.0.pngbin13771 -> 0 bytes
-rw-r--r--doc/user/project/wiki/img/content_editor_v14.6.pngbin0 -> 15534 bytes
-rw-r--r--doc/user/project/wiki/img/use_new_editor_button_v14.0.pngbin16719 -> 0 bytes
-rw-r--r--doc/user/project/wiki/img/use_new_editor_button_v14.6.pngbin0 -> 11192 bytes
-rw-r--r--doc/user/project/wiki/index.md13
-rw-r--r--lib/gitlab/database/gitlab_schemas.yml1
-rw-r--r--locale/gitlab.pot9
-rwxr-xr-xscripts/db_migrate11
-rw-r--r--spec/features/projects/jobs/user_browses_jobs_spec.rb2
-rw-r--r--spec/frontend/environments/confirm_rollback_modal_spec.js134
-rw-r--r--spec/frontend/environments/environment_rollback_spec.js29
-rw-r--r--spec/frontend/environments/graphql/mock_data.js27
-rw-r--r--spec/frontend/environments/graphql/resolvers_spec.js29
-rw-r--r--spec/frontend/issues/show/issue_spec.js2
-rw-r--r--spec/frontend/issues_list/components/issuables_list_app_spec.js22
-rw-r--r--spec/frontend/jobs/components/table/cells/actions_cell_spec.js8
-rw-r--r--spec/frontend/jobs/mock_data.js27
-rw-r--r--spec/models/repository_spec.rb10
-rw-r--r--spec/requests/api/todos_spec.rb2
61 files changed, 673 insertions, 170 deletions
diff --git a/.gitlab/ci/rails.gitlab-ci.yml b/.gitlab/ci/rails.gitlab-ci.yml
index 9db4a2afd91..28c24c0dd26 100644
--- a/.gitlab/ci/rails.gitlab-ci.yml
+++ b/.gitlab/ci/rails.gitlab-ci.yml
@@ -342,9 +342,8 @@ rspec fast_spec_helper minimal:
db:rollback:
extends: .db-job-base
script:
- - if [[ -d "ee/" ]]; then task="db:migrate:main"; else task="db:migrate"; fi
- - bundle exec rake "${task}" VERSION=20181228175414
- - bundle exec rake "${task}" SKIP_SCHEMA_VERSION_CHECK=true
+ - scripts/db_migrate VERSION=20181228175414
+ - scripts/db_migrate SKIP_SCHEMA_VERSION_CHECK=true
db:migrate:reset:
extends: .db-job-base
@@ -369,8 +368,7 @@ db:migrate-from-previous-major-version:
- git checkout -f $CI_COMMIT_SHA
- SETUP_DB=false USE_BUNDLE_INSTALL=true bash scripts/prepare_build.sh
script:
- - if [[ -d "ee/" ]]; then task="db:migrate:main"; else task="db:migrate"; fi
- - run_timed_command "bundle exec rake ${task}"
+ - run_timed_command "scripts/db_migrate"
db:check-schema:
extends:
@@ -379,8 +377,7 @@ db:check-schema:
variables:
TAG_TO_CHECKOUT: "v14.4.0"
script:
- - if [[ -d "ee/" ]]; then task="db:migrate:main"; else task="db:migrate"; fi
- - run_timed_command "bundle exec rake ${task}"
+ - run_timed_command "scripts/db_migrate"
- scripts/schema_changed.sh
- scripts/validate_migration_timestamps
diff --git a/.rubocop_todo/gitlab/delegate_predicate_methods.yml b/.rubocop_todo/gitlab/delegate_predicate_methods.yml
index 2f3a1dce1e8..d31b4a30fc8 100644
--- a/.rubocop_todo/gitlab/delegate_predicate_methods.yml
+++ b/.rubocop_todo/gitlab/delegate_predicate_methods.yml
@@ -4,10 +4,7 @@ Gitlab/DelegatePredicateMethods:
- app/models/clusters/cluster.rb
- app/models/concerns/ci/metadatable.rb
- app/models/concerns/integrations/base_data_fields.rb
- - app/models/concerns/resolvable_discussion.rb
- app/models/project.rb
- ee/app/models/concerns/ee/ci/metadatable.rb
- - ee/app/models/ee/group.rb
- - ee/app/models/ee/namespace.rb
- ee/app/models/license.rb
- lib/gitlab/ci/trace/stream.rb
diff --git a/GITALY_SERVER_VERSION b/GITALY_SERVER_VERSION
index f16099effce..d39801c5c67 100644
--- a/GITALY_SERVER_VERSION
+++ b/GITALY_SERVER_VERSION
@@ -1 +1 @@
-8ede1944ec9793c06dba5011234af7f5c5ec92b7
+15a1323ae16dffd3ba6b078f6cb81e283a96c72d
diff --git a/app/assets/javascripts/environments/components/confirm_rollback_modal.vue b/app/assets/javascripts/environments/components/confirm_rollback_modal.vue
index 4783b92942c..0e556f093e2 100644
--- a/app/assets/javascripts/environments/components/confirm_rollback_modal.vue
+++ b/app/assets/javascripts/environments/components/confirm_rollback_modal.vue
@@ -7,6 +7,7 @@ import { escape } from 'lodash';
import csrf from '~/lib/utils/csrf';
import { __, s__, sprintf } from '~/locale';
+import rollbackEnvironment from '../graphql/mutations/rollback_environment.mutation.graphql';
import eventHub from '../event_hub';
export default {
@@ -40,10 +41,15 @@ export default {
required: false,
default: null,
},
+ graphql: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
},
computed: {
modalTitle() {
- const title = this.environment.isLastDeployment
+ const title = this.isLastDeployment
? s__('Environments|Re-deploy environment %{name}?')
: s__('Environments|Rollback environment %{name}?');
@@ -53,6 +59,11 @@ export default {
},
commitShortSha() {
if (this.hasMultipleCommits) {
+ if (this.graphql) {
+ const { lastDeployment } = this.environment;
+ return this.commitData(lastDeployment, 'shortId');
+ }
+
const { last_deployment } = this.environment;
return this.commitData(last_deployment, 'short_id');
}
@@ -61,6 +72,11 @@ export default {
},
commitUrl() {
if (this.hasMultipleCommits) {
+ if (this.graphql) {
+ const { lastDeployment } = this.environment;
+ return this.commitData(lastDeployment, 'commitPath');
+ }
+
const { last_deployment } = this.environment;
return this.commitData(last_deployment, 'commit_path');
}
@@ -68,9 +84,7 @@ export default {
return this.environment.commitUrl;
},
modalActionText() {
- return this.environment.isLastDeployment
- ? s__('Environments|Re-deploy')
- : s__('Environments|Rollback');
+ return this.isLastDeployment ? s__('Environments|Re-deploy') : s__('Environments|Rollback');
},
primaryProps() {
let attributes = [{ variant: 'danger' }];
@@ -84,20 +98,27 @@ export default {
attributes,
};
},
+ isLastDeployment() {
+ // eslint-disable-next-line @gitlab/require-i18n-strings
+ return this.environment?.isLastDeployment || this.environment?.lastDeployment?.['last?'];
+ },
},
methods: {
handleChange(event) {
this.$emit('change', event);
},
onOk() {
- eventHub.$emit('rollbackEnvironment', this.environment);
+ if (this.graphql) {
+ this.$apollo.mutate({
+ mutation: rollbackEnvironment,
+ variables: { environment: this.environment },
+ });
+ } else {
+ eventHub.$emit('rollbackEnvironment', this.environment);
+ }
},
commitData(lastDeployment, key) {
- if (lastDeployment && lastDeployment.commit) {
- return lastDeployment.commit[key];
- }
-
- return '';
+ return lastDeployment?.commit?.[key] ?? '';
},
},
csrf,
diff --git a/app/assets/javascripts/environments/components/environment_rollback.vue b/app/assets/javascripts/environments/components/environment_rollback.vue
index 00497b3c683..f7f0cf4cb8d 100644
--- a/app/assets/javascripts/environments/components/environment_rollback.vue
+++ b/app/assets/javascripts/environments/components/environment_rollback.vue
@@ -8,6 +8,7 @@
import { GlModalDirective, GlDropdownItem } from '@gitlab/ui';
import { s__ } from '~/locale';
import eventHub from '../event_hub';
+import setEnvironmentToRollback from '../graphql/mutations/set_environment_to_rollback.mutation.graphql';
export default {
components: {
@@ -32,11 +33,12 @@ export default {
type: String,
required: true,
},
- },
- data() {
- return {
- isLoading: false,
- };
+
+ graphql: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
},
computed: {
@@ -49,16 +51,18 @@ export default {
methods: {
onClick() {
- eventHub.$emit('requestRollbackEnvironment', {
- ...this.environment,
- retryUrl: this.retryUrl,
- isLastDeployment: this.isLastDeployment,
- });
- eventHub.$on('rollbackEnvironment', (environment) => {
- if (environment.id === this.environment.id) {
- this.isLoading = true;
- }
- });
+ if (this.graphql) {
+ this.$apollo.mutate({
+ mutation: setEnvironmentToRollback,
+ variables: { environment: this.environment },
+ });
+ } else {
+ eventHub.$emit('requestRollbackEnvironment', {
+ ...this.environment,
+ retryUrl: this.retryUrl,
+ isLastDeployment: this.isLastDeployment,
+ });
+ }
},
},
};
diff --git a/app/assets/javascripts/environments/graphql/mutations/set_environment_to_rollback.mutation.graphql b/app/assets/javascripts/environments/graphql/mutations/set_environment_to_rollback.mutation.graphql
new file mode 100644
index 00000000000..aba978ed79e
--- /dev/null
+++ b/app/assets/javascripts/environments/graphql/mutations/set_environment_to_rollback.mutation.graphql
@@ -0,0 +1,3 @@
+mutation SetEnvironmentToRollback($environment: Environment) {
+ setEnvironmentToRollback(environment: $environment) @client
+}
diff --git a/app/assets/javascripts/environments/graphql/queries/environment_to_rollback.query.graphql b/app/assets/javascripts/environments/graphql/queries/environment_to_rollback.query.graphql
new file mode 100644
index 00000000000..f7586e27665
--- /dev/null
+++ b/app/assets/javascripts/environments/graphql/queries/environment_to_rollback.query.graphql
@@ -0,0 +1,7 @@
+query environmentToRollback {
+ environmentToRollback @client {
+ id
+ name
+ lastDeployment
+ }
+}
diff --git a/app/assets/javascripts/environments/graphql/resolvers.js b/app/assets/javascripts/environments/graphql/resolvers.js
index 56e552fe461..b8d570a2d78 100644
--- a/app/assets/javascripts/environments/graphql/resolvers.js
+++ b/app/assets/javascripts/environments/graphql/resolvers.js
@@ -2,6 +2,7 @@ import axios from '~/lib/utils/axios_utils';
import { s__ } from '~/locale';
import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils';
import pollIntervalQuery from './queries/poll_interval.query.graphql';
+import environmentToRollbackQuery from './queries/environment_to_rollback.query.graphql';
const buildErrors = (errors = []) => ({
errors,
@@ -84,6 +85,12 @@ export const resolvers = (endpoint) => ({
]);
});
},
+ setEnvironmentToRollback(_, { environment }, { client }) {
+ client.writeQuery({
+ query: environmentToRollbackQuery,
+ data: { environmentToRollback: environment },
+ });
+ },
cancelAutoStop(_, { environment: { autoStopPath } }) {
return axios
.post(autoStopPath)
diff --git a/app/assets/javascripts/environments/graphql/typedefs.graphql b/app/assets/javascripts/environments/graphql/typedefs.graphql
index 026f2ca9375..9c205a6b7b3 100644
--- a/app/assets/javascripts/environments/graphql/typedefs.graphql
+++ b/app/assets/javascripts/environments/graphql/typedefs.graphql
@@ -58,6 +58,7 @@ type LocalErrors {
extend type Query {
environmentApp: LocalEnvironmentApp
folder(environment: NestedLocalEnvironmentInput): LocalEnvironmentFolder
+ environmentToRollback: LocalEnvironment
isLastDeployment: Boolean
}
@@ -66,4 +67,5 @@ extend type Mutation {
deleteEnvironment(environment: LocalEnvironmentInput): LocalErrors
rollbackEnvironment(environment: LocalEnvironmentInput): LocalErrors
cancelAutoStop(environment: LocalEnvironmentInput): LocalErrors
+ setEnvironmentToRollback(environment: LocalEnvironmentInput): LocalErrors
}
diff --git a/app/assets/javascripts/issuable/bulk_update_sidebar/issuable_bulk_update_actions.js b/app/assets/javascripts/issuable/bulk_update_sidebar/issuable_bulk_update_actions.js
index 463e0e5837e..14824820c0d 100644
--- a/app/assets/javascripts/issuable/bulk_update_sidebar/issuable_bulk_update_actions.js
+++ b/app/assets/javascripts/issuable/bulk_update_sidebar/issuable_bulk_update_actions.js
@@ -115,7 +115,7 @@ export default {
});
// Add uniqueIds to add it as argument for _.intersection
labelIds.unshift(uniqueIds);
- // Return IDs that are present but not in all selected issueables
+ // Return IDs that are present but not in all selected issuables
return uniqueIds.filter((x) => !intersection.apply(this, labelIds).includes(x));
},
diff --git a/app/assets/javascripts/issuable/bulk_update_sidebar/issuable_bulk_update_sidebar.js b/app/assets/javascripts/issuable/bulk_update_sidebar/issuable_bulk_update_sidebar.js
index 8f94f54dc78..1eb3ffc9808 100644
--- a/app/assets/javascripts/issuable/bulk_update_sidebar/issuable_bulk_update_sidebar.js
+++ b/app/assets/javascripts/issuable/bulk_update_sidebar/issuable_bulk_update_sidebar.js
@@ -3,7 +3,7 @@
import $ from 'jquery';
import { property } from 'lodash';
-import issueableEventHub from '~/issues_list/eventhub';
+import issuableEventHub from '~/issues_list/eventhub';
import LabelsSelect from '~/labels/labels_select';
import MilestoneSelect from '~/milestones/milestone_select';
import initIssueStatusSelect from './init_issue_status_select';
@@ -50,8 +50,8 @@ export default class IssuableBulkUpdateSidebar {
// The event hub connects this bulk update logic with `issues_list_app.vue`.
// We can remove it once we've refactored the issues list page bulk edit sidebar to Vue.
// https://gitlab.com/gitlab-org/gitlab/-/issues/325874
- issueableEventHub.$on('issuables:enableBulkEdit', () => this.toggleBulkEdit(null, true));
- issueableEventHub.$on('issuables:updateBulkEdit', () => this.updateFormState());
+ issuableEventHub.$on('issuables:enableBulkEdit', () => this.toggleBulkEdit(null, true));
+ issuableEventHub.$on('issuables:updateBulkEdit', () => this.updateFormState());
}
initDropdowns() {
@@ -110,7 +110,7 @@ export default class IssuableBulkUpdateSidebar {
toggleBulkEdit(e, enable) {
e?.preventDefault();
- issueableEventHub.$emit('issuables:toggleBulkEdit', enable);
+ issuableEventHub.$emit('issuables:toggleBulkEdit', enable);
this.toggleSidebarDisplay(enable);
this.toggleBulkEditButtonDisabled(enable);
diff --git a/app/assets/javascripts/issuable/index.js b/app/assets/javascripts/issuable/index.js
index ad7c1942074..072422944f5 100644
--- a/app/assets/javascripts/issuable/index.js
+++ b/app/assets/javascripts/issuable/index.js
@@ -56,7 +56,7 @@ export function initCsvImportExportButtons() {
export function initIssuableByEmail() {
Vue.use(GlToast);
- const el = document.querySelector('.js-issueable-by-email');
+ const el = document.querySelector('.js-issuable-by-email');
if (!el) return null;
diff --git a/app/assets/javascripts/issues/show/components/incidents/highlight_bar.vue b/app/assets/javascripts/issues/show/components/incidents/highlight_bar.vue
index 96f187f26dd..d509f0dbc09 100644
--- a/app/assets/javascripts/issues/show/components/incidents/highlight_bar.vue
+++ b/app/assets/javascripts/issues/show/components/incidents/highlight_bar.vue
@@ -5,7 +5,7 @@ import { formatDate } from '~/lib/utils/datetime_utility';
export default {
components: {
GlLink,
- IncidentSla: () => import('ee_component/issue_show/components/incidents/incident_sla.vue'),
+ IncidentSla: () => import('ee_component/issues/show/components/incidents/incident_sla.vue'),
},
directives: {
GlTooltip: GlTooltipDirective,
diff --git a/app/assets/javascripts/issues/show/components/incidents/incident_tabs.vue b/app/assets/javascripts/issues/show/components/incidents/incident_tabs.vue
index 84107d3eaca..4790062ab7d 100644
--- a/app/assets/javascripts/issues/show/components/incidents/incident_tabs.vue
+++ b/app/assets/javascripts/issues/show/components/incidents/incident_tabs.vue
@@ -16,7 +16,7 @@ export default {
GlTab,
GlTabs,
HighlightBar,
- MetricsTab: () => import('ee_component/issue_show/components/incidents/metrics_tab.vue'),
+ MetricsTab: () => import('ee_component/issues/show/components/incidents/metrics_tab.vue'),
},
inject: ['fullPath', 'iid', 'uploadMetricsFeatureAvailable'],
apollo: {
diff --git a/app/assets/javascripts/issues_list/components/issuables_list_app.vue b/app/assets/javascripts/issues_list/components/issuables_list_app.vue
index 516a48aaa5b..71136bf0159 100644
--- a/app/assets/javascripts/issues_list/components/issuables_list_app.vue
+++ b/app/assets/javascripts/issues_list/components/issuables_list_app.vue
@@ -21,7 +21,7 @@ import {
PAGE_SIZE_MANUAL,
LOADING_LIST_ITEMS_LENGTH,
} from '../constants';
-import issueableEventHub from '../eventhub';
+import issuableEventHub from '../eventhub';
import { emptyStateHelper } from '../service_desk_helper';
import Issuable from './issuable.vue';
@@ -192,7 +192,7 @@ export default {
// We need to call nextTick here to wait for all of the boxes to be checked and rendered
// before we query the dom in issuable_bulk_update_actions.js.
this.$nextTick(() => {
- issueableEventHub.$emit('issuables:updateBulkEdit');
+ issuableEventHub.$emit('issuables:updateBulkEdit');
});
},
issuables() {
@@ -203,7 +203,7 @@ export default {
},
mounted() {
if (this.canBulkEdit) {
- this.unsubscribeToggleBulkEdit = issueableEventHub.$on('issuables:toggleBulkEdit', (val) => {
+ this.unsubscribeToggleBulkEdit = issuableEventHub.$on('issuables:toggleBulkEdit', (val) => {
this.isBulkEditing = val;
});
}
@@ -211,7 +211,7 @@ export default {
},
beforeDestroy() {
// eslint-disable-next-line @gitlab/no-global-event-off
- issueableEventHub.$off('issuables:toggleBulkEdit');
+ issuableEventHub.$off('issuables:toggleBulkEdit');
},
methods: {
isSelected(issuableId) {
diff --git a/app/assets/javascripts/jobs/components/table/cells/actions_cell.vue b/app/assets/javascripts/jobs/components/table/cells/actions_cell.vue
index 9a8ec30bb2d..7dfa963a857 100644
--- a/app/assets/javascripts/jobs/components/table/cells/actions_cell.vue
+++ b/app/assets/javascripts/jobs/components/table/cells/actions_cell.vue
@@ -12,6 +12,7 @@ import {
JOB_SCHEDULED,
PLAY_JOB_CONFIRMATION_MESSAGE,
RUN_JOB_NOW_HEADER_TITLE,
+ FILE_TYPE_ARCHIVE,
} from '../constants';
import eventHub from '../event_hub';
import cancelJobMutation from '../graphql/mutations/job_cancel.mutation.graphql';
@@ -58,8 +59,11 @@ export default {
},
},
computed: {
+ hasArtifacts() {
+ return this.job.artifacts.nodes.find((artifact) => artifact.fileType === FILE_TYPE_ARCHIVE);
+ },
artifactDownloadPath() {
- return this.job.artifacts?.nodes[0]?.downloadPath;
+ return this.hasArtifacts.downloadPath;
},
canReadJob() {
return this.job.userPermissions?.readBuild;
@@ -67,6 +71,9 @@ export default {
canUpdateJob() {
return this.job.userPermissions?.updateBuild;
},
+ canReadArtifacts() {
+ return this.job.userPermissions?.readJobArtifacts;
+ },
isActive() {
return this.job.active;
},
@@ -89,7 +96,7 @@ export default {
return this.job.detailedStatus?.action?.method;
},
shouldDisplayArtifacts() {
- return this.job.userPermissions?.readJobArtifacts && this.job.artifacts?.nodes.length > 0;
+ return this.canReadArtifacts && this.hasArtifacts;
},
},
methods: {
diff --git a/app/assets/javascripts/jobs/components/table/constants.js b/app/assets/javascripts/jobs/components/table/constants.js
index e5d1bc01cbf..d3c2f4ec39f 100644
--- a/app/assets/javascripts/jobs/components/table/constants.js
+++ b/app/assets/javascripts/jobs/components/table/constants.js
@@ -17,6 +17,9 @@ export const DEFAULT = 'default';
/* Job Status Constants */
export const JOB_SCHEDULED = 'SCHEDULED';
+/* Artifact file types */
+export const FILE_TYPE_ARCHIVE = 'ARCHIVE';
+
/* i18n */
export const ACTIONS_DOWNLOAD_ARTIFACTS = __('Download artifacts');
export const ACTIONS_START_NOW = s__('DelayedJobs|Start now');
diff --git a/app/assets/javascripts/jobs/components/table/graphql/queries/get_jobs.query.graphql b/app/assets/javascripts/jobs/components/table/graphql/queries/get_jobs.query.graphql
index df37e084408..88937185a8c 100644
--- a/app/assets/javascripts/jobs/components/table/graphql/queries/get_jobs.query.graphql
+++ b/app/assets/javascripts/jobs/components/table/graphql/queries/get_jobs.query.graphql
@@ -19,6 +19,7 @@ query getJobs(
artifacts {
nodes {
downloadPath
+ fileType
}
}
allowFailure
diff --git a/app/assets/javascripts/labels/labels_select.js b/app/assets/javascripts/labels/labels_select.js
index ae0cf94b861..9d8ee165df2 100644
--- a/app/assets/javascripts/labels/labels_select.js
+++ b/app/assets/javascripts/labels/labels_select.js
@@ -101,7 +101,7 @@ export default class LabelsSelect {
if (IS_EE) {
/**
* For Scoped labels, the last label selected with the
- * same key will be applied to the current issueable.
+ * same key will be applied to the current issuable.
*
* If these are the labels - priority::1, priority::2; and if
* we apply them in the same order, only priority::2 will stick
diff --git a/app/controllers/projects/issues_controller.rb b/app/controllers/projects/issues_controller.rb
index 8a6ae268376..fc67cd98d15 100644
--- a/app/controllers/projects/issues_controller.rb
+++ b/app/controllers/projects/issues_controller.rb
@@ -10,7 +10,7 @@ class Projects::IssuesController < Projects::ApplicationController
include RecordUserLastActivity
ISSUES_EXCEPT_ACTIONS = %i[index calendar new create bulk_update import_csv export_csv service_desk].freeze
- SET_ISSUEABLES_INDEX_ONLY_ACTIONS = %i[index calendar service_desk].freeze
+ SET_ISSUABLES_INDEX_ONLY_ACTIONS = %i[index calendar service_desk].freeze
prepend_before_action(only: [:index]) { authenticate_sessionless_user!(:rss) }
prepend_before_action(only: [:calendar]) { authenticate_sessionless_user!(:ics) }
@@ -22,7 +22,7 @@ class Projects::IssuesController < Projects::ApplicationController
before_action :issue, unless: ->(c) { ISSUES_EXCEPT_ACTIONS.include?(c.action_name.to_sym) }
after_action :log_issue_show, unless: ->(c) { ISSUES_EXCEPT_ACTIONS.include?(c.action_name.to_sym) }
- before_action :set_issuables_index, if: ->(c) { SET_ISSUEABLES_INDEX_ONLY_ACTIONS.include?(c.action_name.to_sym) }
+ before_action :set_issuables_index, if: ->(c) { SET_ISSUABLES_INDEX_ONLY_ACTIONS.include?(c.action_name.to_sym) }
# Allow write(create) issue
before_action :authorize_create_issue!, only: [:new, :create]
diff --git a/app/graphql/types/packages/package_type.rb b/app/graphql/types/packages/package_type.rb
index 9851c6aec7e..d1312cb963d 100644
--- a/app/graphql/types/packages/package_type.rb
+++ b/app/graphql/types/packages/package_type.rb
@@ -21,7 +21,8 @@ module Types
field :tags, Types::Packages::PackageTagType.connection_type, null: true, description: 'Package tags.'
field :project, Types::ProjectType, null: false, description: 'Project where the package is stored.'
field :pipelines, Types::Ci::PipelineType.connection_type, null: true,
- description: 'Pipelines that built the package.'
+ description: 'Pipelines that built the package.',
+ deprecated: { reason: 'Due to scalability concerns, this field is going to be removed', milestone: '14.6' }
field :metadata, Types::Packages::MetadataType, null: true,
description: 'Package metadata.'
field :versions, ::Types::Packages::PackageType.connection_type, null: true,
diff --git a/app/models/concerns/resolvable_discussion.rb b/app/models/concerns/resolvable_discussion.rb
index 60e1dde17b9..aae338e9759 100644
--- a/app/models/concerns/resolvable_discussion.rb
+++ b/app/models/concerns/resolvable_discussion.rb
@@ -30,11 +30,14 @@ module ResolvableDiscussion
delegate :resolved_at,
:resolved_by,
- :resolved_by_push?,
to: :last_resolved_note,
allow_nil: true
end
+ def resolved_by_push?
+ !!last_resolved_note&.resolved_by_push?
+ end
+
def resolvable?
strong_memoize(:resolvable) do
potentially_resolvable? && notes.any?(&:resolvable?)
diff --git a/app/models/repository.rb b/app/models/repository.rb
index 47482f04bca..645cc9773bd 100644
--- a/app/models/repository.rb
+++ b/app/models/repository.rb
@@ -519,6 +519,8 @@ class Repository
raw_repository.batch_blobs(items, blob_size_limit: blob_size_limit).map do |blob|
Blob.decorate(blob, container)
end
+ rescue Gitlab::Git::Repository::NoRepository
+ []
end
def root_ref
diff --git a/app/views/projects/issues/index.html.haml b/app/views/projects/issues/index.html.haml
index 53c2052bfab..10c48177ae4 100644
--- a/app/views/projects/issues/index.html.haml
+++ b/app/views/projects/issues/index.html.haml
@@ -30,7 +30,7 @@
= render 'issues'
- if new_issue_email
.gl-text-center.gl-pt-5.gl-pb-7
- .js-issueable-by-email{ data: { initial_email: new_issue_email, issuable_type: issuable_type, emails_help_page_path: help_page_path('development/emails', anchor: 'email-namespace'), quick_actions_help_path: help_page_path('user/project/quick_actions'), markdown_help_path: help_page_path('user/markdown'), reset_path: new_issuable_address_project_path(@project, issuable_type: issuable_type) } }
+ .js-issuable-by-email{ data: { initial_email: new_issue_email, issuable_type: issuable_type, emails_help_page_path: help_page_path('development/emails', anchor: 'email-namespace'), quick_actions_help_path: help_page_path('user/project/quick_actions'), markdown_help_path: help_page_path('user/markdown'), reset_path: new_issuable_address_project_path(@project, issuable_type: issuable_type) } }
- else
- new_project_issue_button_path = @project.archived? ? false : new_project_issue_path(@project)
= render 'shared/empty_states/issues', new_project_issue_button_path: new_project_issue_button_path, show_import_button: true
diff --git a/app/views/projects/merge_requests/index.html.haml b/app/views/projects/merge_requests/index.html.haml
index 41c6696789d..a3f40207d20 100644
--- a/app/views/projects/merge_requests/index.html.haml
+++ b/app/views/projects/merge_requests/index.html.haml
@@ -26,6 +26,6 @@
= render 'merge_requests', new_merge_request_path: new_merge_request_path
- if new_merge_request_email
.gl-text-center.gl-pt-5.gl-pb-7
- .js-issueable-by-email{ data: { initial_email: new_merge_request_email, issuable_type: issuable_type, emails_help_page_path: help_page_path('development/emails', anchor: 'email-namespace'), quick_actions_help_path: help_page_path('user/project/quick_actions'), markdown_help_path: help_page_path('user/markdown'), reset_path: new_issuable_address_project_path(@project, issuable_type: issuable_type) } }
+ .js-issuable-by-email{ data: { initial_email: new_merge_request_email, issuable_type: issuable_type, emails_help_page_path: help_page_path('development/emails', anchor: 'email-namespace'), quick_actions_help_path: help_page_path('user/project/quick_actions'), markdown_help_path: help_page_path('user/markdown'), reset_path: new_issuable_address_project_path(@project, issuable_type: issuable_type) } }
- else
= render 'shared/empty_states/merge_requests', button_path: new_merge_request_path
diff --git a/config/feature_flags/development/geo_pages_deployment_verification.yml b/config/feature_flags/development/geo_pages_deployment_verification.yml
new file mode 100644
index 00000000000..3c74d4d3485
--- /dev/null
+++ b/config/feature_flags/development/geo_pages_deployment_verification.yml
@@ -0,0 +1,8 @@
+---
+name: geo_pages_deployment_verification
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/74905
+rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/346754
+milestone: '14.6'
+type: development
+group: group::geo
+default_enabled: false
diff --git a/data/deprecations/14-6-pipeline-fields-package-deprecation.yml b/data/deprecations/14-6-pipeline-fields-package-deprecation.yml
new file mode 100644
index 00000000000..b06bb4d16dc
--- /dev/null
+++ b/data/deprecations/14-6-pipeline-fields-package-deprecation.yml
@@ -0,0 +1,12 @@
+- name: "Deprecate `pipelines` fields in the Package GraphQL types"
+ announcement_milestone: "14.6" # The milestone when this feature was first announced as deprecated.
+ announcement_date: "2021-12-22" # The date of the milestone release when this feature was first announced as deprecated. This should almost always be the 22nd of a month (YYYY-MM-22), unless you did an out of band blog post.
+ removal_milestone: "15.0" # The milestone when this feature is planned to be removed
+ removal_date: "2022-05-22" # the date of the milestone release when this feature is planned to be removed
+ body: | # Do not modify this line, instead modify the lines below.
+ As part of the work to create a [Package Registry GraphQL API](https://gitlab.com/groups/gitlab-org/-/epics/6318), the Package group deprecated the `pipelines` fields in all Package-related GraphQL types. As of GitLab 14.6, the `pipelines` field is deprecated in [`Package`](https://docs.gitlab.com/ee/api/graphql/reference/index.html#package) and [`PackageDetailsType`](https://docs.gitlab.com/ee/api/graphql/reference/index.html#packagedetailstype) due to scalability and performance concerns.
+
+ In milestone 15.0, we will completely remove `pipelines` from `Package` and `PackageDetailsType`. You can follow and contribute to work on a replacement in the epic [GitLab-#7214](https://gitlab.com/groups/gitlab-org/-/epics/7214).
+ stage: package
+ tiers: Free
+ issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/347219
diff --git a/db/migrate/20211119154221_create_pages_deployment_states.rb b/db/migrate/20211119154221_create_pages_deployment_states.rb
new file mode 100644
index 00000000000..283f6c7d0d7
--- /dev/null
+++ b/db/migrate/20211119154221_create_pages_deployment_states.rb
@@ -0,0 +1,38 @@
+# frozen_string_literal: true
+
+class CreatePagesDeploymentStates < Gitlab::Database::Migration[1.0]
+ VERIFICATION_STATE_INDEX_NAME = "index_pages_deployment_states_on_verification_state"
+ PENDING_VERIFICATION_INDEX_NAME = "index_pages_deployment_states_pending_verification"
+ FAILED_VERIFICATION_INDEX_NAME = "index_pages_deployment_states_failed_verification"
+ NEEDS_VERIFICATION_INDEX_NAME = "index_pages_deployment_states_needs_verification"
+
+ disable_ddl_transaction!
+
+ def up
+ unless table_exists?(:pages_deployment_states)
+ with_lock_retries do
+ create_table :pages_deployment_states, id: false do |t|
+ t.references :pages_deployment, primary_key: true, null: false, foreign_key: { on_delete: :cascade }
+ t.integer :verification_state, default: 0, limit: 2, null: false
+ t.column :verification_started_at, :datetime_with_timezone
+ t.datetime_with_timezone :verification_retry_at
+ t.datetime_with_timezone :verified_at
+ t.integer :verification_retry_count, limit: 2
+ t.binary :verification_checksum, using: 'verification_checksum::bytea'
+ t.text :verification_failure
+
+ t.index :verification_state, name: VERIFICATION_STATE_INDEX_NAME
+ t.index :verified_at, where: "(verification_state = 0)", order: { verified_at: 'ASC NULLS FIRST' }, name: PENDING_VERIFICATION_INDEX_NAME
+ t.index :verification_retry_at, where: "(verification_state = 3)", order: { verification_retry_at: 'ASC NULLS FIRST' }, name: FAILED_VERIFICATION_INDEX_NAME
+ t.index :verification_state, where: "(verification_state = 0 OR verification_state = 3)", name: NEEDS_VERIFICATION_INDEX_NAME
+ end
+ end
+ end
+
+ add_text_limit :pages_deployment_states, :verification_failure, 255
+ end
+
+ def down
+ drop_table :pages_deployment_states
+ end
+end
diff --git a/db/post_migrate/20211208171402_reschedule_recalculate_vulnerability_finding_signatures_for_findings.rb b/db/post_migrate/20211208171402_reschedule_recalculate_vulnerability_finding_signatures_for_findings.rb
new file mode 100644
index 00000000000..8eee082809b
--- /dev/null
+++ b/db/post_migrate/20211208171402_reschedule_recalculate_vulnerability_finding_signatures_for_findings.rb
@@ -0,0 +1,27 @@
+# frozen_string_literal: true
+
+class RescheduleRecalculateVulnerabilityFindingSignaturesForFindings < Gitlab::Database::Migration[1.0]
+ MIGRATION = 'RecalculateVulnerabilityFindingSignaturesForFindings'
+ BATCH_SIZE = 1_000
+ DELAY_INTERVAL = 2.minutes
+
+ disable_ddl_transaction!
+
+ # Due to production incident previous migration was orphaned and must be rescheduled,
+ # See https://gitlab.com/gitlab-org/gitlab/-/merge_requests/72919#note_741188600
+ def up
+ return unless Gitlab.ee?
+
+ delete_queued_jobs(MIGRATION)
+
+ requeue_background_migration_jobs_by_range_at_intervals(
+ MIGRATION,
+ DELAY_INTERVAL,
+ batch_size: BATCH_SIZE
+ )
+ end
+
+ def down
+ # no-op
+ end
+end
diff --git a/db/schema_migrations/20211119154221 b/db/schema_migrations/20211119154221
new file mode 100644
index 00000000000..c8b6005b48b
--- /dev/null
+++ b/db/schema_migrations/20211119154221
@@ -0,0 +1 @@
+020e17ffd6851fb861a17c1b120ca7cdfa300434d4a9ec923a4edcaa7f951b31 \ No newline at end of file
diff --git a/db/schema_migrations/20211208171402 b/db/schema_migrations/20211208171402
new file mode 100644
index 00000000000..a563797dea5
--- /dev/null
+++ b/db/schema_migrations/20211208171402
@@ -0,0 +1 @@
+09a9e7fc042aab19bf768a79401f33b6e7408acff303fc0ee68360dfd7605101 \ No newline at end of file
diff --git a/db/structure.sql b/db/structure.sql
index b25db1fbfbc..bde98b6932f 100644
--- a/db/structure.sql
+++ b/db/structure.sql
@@ -17493,6 +17493,27 @@ CREATE SEQUENCE packages_tags_id_seq
ALTER SEQUENCE packages_tags_id_seq OWNED BY packages_tags.id;
+CREATE TABLE pages_deployment_states (
+ pages_deployment_id bigint NOT NULL,
+ verification_state smallint DEFAULT 0 NOT NULL,
+ verification_started_at timestamp with time zone,
+ verification_retry_at timestamp with time zone,
+ verified_at timestamp with time zone,
+ verification_retry_count smallint,
+ verification_checksum bytea,
+ verification_failure text,
+ CONSTRAINT check_15217e8c3a CHECK ((char_length(verification_failure) <= 255))
+);
+
+CREATE SEQUENCE pages_deployment_states_pages_deployment_id_seq
+ START WITH 1
+ INCREMENT BY 1
+ NO MINVALUE
+ NO MAXVALUE
+ CACHE 1;
+
+ALTER SEQUENCE pages_deployment_states_pages_deployment_id_seq OWNED BY pages_deployment_states.pages_deployment_id;
+
CREATE TABLE pages_deployments (
id bigint NOT NULL,
created_at timestamp with time zone NOT NULL,
@@ -21954,6 +21975,8 @@ ALTER TABLE ONLY packages_packages ALTER COLUMN id SET DEFAULT nextval('packages
ALTER TABLE ONLY packages_tags ALTER COLUMN id SET DEFAULT nextval('packages_tags_id_seq'::regclass);
+ALTER TABLE ONLY pages_deployment_states ALTER COLUMN pages_deployment_id SET DEFAULT nextval('pages_deployment_states_pages_deployment_id_seq'::regclass);
+
ALTER TABLE ONLY pages_deployments ALTER COLUMN id SET DEFAULT nextval('pages_deployments_id_seq'::regclass);
ALTER TABLE ONLY pages_domain_acme_orders ALTER COLUMN id SET DEFAULT nextval('pages_domain_acme_orders_id_seq'::regclass);
@@ -23793,6 +23816,9 @@ ALTER TABLE ONLY packages_rubygems_metadata
ALTER TABLE ONLY packages_tags
ADD CONSTRAINT packages_tags_pkey PRIMARY KEY (id);
+ALTER TABLE ONLY pages_deployment_states
+ ADD CONSTRAINT pages_deployment_states_pkey PRIMARY KEY (pages_deployment_id);
+
ALTER TABLE ONLY pages_deployments
ADD CONSTRAINT pages_deployments_pkey PRIMARY KEY (id);
@@ -27022,6 +27048,16 @@ CREATE INDEX index_packages_tags_on_package_id ON packages_tags USING btree (pac
CREATE INDEX index_packages_tags_on_package_id_and_updated_at ON packages_tags USING btree (package_id, updated_at DESC);
+CREATE INDEX index_pages_deployment_states_failed_verification ON pages_deployment_states USING btree (verification_retry_at NULLS FIRST) WHERE (verification_state = 3);
+
+CREATE INDEX index_pages_deployment_states_needs_verification ON pages_deployment_states USING btree (verification_state) WHERE ((verification_state = 0) OR (verification_state = 3));
+
+CREATE INDEX index_pages_deployment_states_on_pages_deployment_id ON pages_deployment_states USING btree (pages_deployment_id);
+
+CREATE INDEX index_pages_deployment_states_on_verification_state ON pages_deployment_states USING btree (verification_state);
+
+CREATE INDEX index_pages_deployment_states_pending_verification ON pages_deployment_states USING btree (verified_at NULLS FIRST) WHERE (verification_state = 0);
+
CREATE INDEX index_pages_deployments_on_ci_build_id ON pages_deployments USING btree (ci_build_id);
CREATE INDEX index_pages_deployments_on_file_store_and_id ON pages_deployments USING btree (file_store, id);
@@ -31570,6 +31606,9 @@ ALTER TABLE ONLY project_tracing_settings
ALTER TABLE ONLY resource_label_events
ADD CONSTRAINT fk_rails_fe91ece594 FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE SET NULL;
+ALTER TABLE ONLY pages_deployment_states
+ ADD CONSTRAINT fk_rails_ff6ca551a4 FOREIGN KEY (pages_deployment_id) REFERENCES pages_deployments(id) ON DELETE CASCADE;
+
ALTER TABLE ONLY ci_builds_metadata
ADD CONSTRAINT fk_rails_ffcf702a02 FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE;
diff --git a/doc/administration/monitoring/prometheus/gitlab_metrics.md b/doc/administration/monitoring/prometheus/gitlab_metrics.md
index c6a1a93af7c..4a504b07a1b 100644
--- a/doc/administration/monitoring/prometheus/gitlab_metrics.md
+++ b/doc/administration/monitoring/prometheus/gitlab_metrics.md
@@ -262,15 +262,15 @@ configuration option in `gitlab.yml`. These metrics are served from the
| `geo_group_wiki_repositories_failed` | Gauge | 13.10 | Number of syncable group wikis failed on secondary | `url` |
| `geo_group_wiki_repositories_registry` | Gauge | 13.10 | Number of syncable group wikis in the registry | `url` |
| `geo_pages_deployments` | Gauge | 14.3 | Number of pages deployments on primary | `url` |
-| `geo_pages_deployments_checksum_total` | Gauge | 14.3 | Number of pages deployments tried to checksum on primary | `url` |
-| `geo_pages_deployments_checksummed` | Gauge | 14.3 | Number of pages deployments successfully checksummed on primary | `url` |
-| `geo_pages_deployments_checksum_failed` | Gauge | 14.3 | Number of pages deployments failed to calculate the checksum on primary | `url` |
+| `geo_pages_deployments_checksum_total` | Gauge | 14.6 | Number of pages deployments tried to checksum on primary | `url` |
+| `geo_pages_deployments_checksummed` | Gauge | 14.6 | Number of pages deployments successfully checksummed on primary | `url` |
+| `geo_pages_deployments_checksum_failed` | Gauge | 14.6 | Number of pages deployments failed to calculate the checksum on primary | `url` |
| `geo_pages_deployments_synced` | Gauge | 14.3 | Number of syncable pages deployments synced on secondary | `url` |
| `geo_pages_deployments_failed` | Gauge | 14.3 | Number of syncable pages deployments failed to sync on secondary | `url` |
| `geo_pages_deployments_registry` | Gauge | 14.3 | Number of pages deployments in the registry | `url` |
-| `geo_pages_deployments_verification_total` | Gauge | 14.3 | Number of pages deployments verifications tried on secondary | `url` |
-| `geo_pages_deployments_verified` | Gauge | 14.3 | Number of pages deployments verified on secondary | `url` |
-| `geo_pages_deployments_verification_failed` | Gauge | 14.3 | Number of pages deployments verifications failed on secondary | `url` |
+| `geo_pages_deployments_verification_total` | Gauge | 14.6 | Number of pages deployments verifications tried on secondary | `url` |
+| `geo_pages_deployments_verified` | Gauge | 14.6 | Number of pages deployments verified on secondary | `url` |
+| `geo_pages_deployments_verification_failed` | Gauge | 14.6 | Number of pages deployments verifications failed on secondary | `url` |
| `limited_capacity_worker_running_jobs` | Gauge | 13.5 | Number of running jobs | `worker` |
| `limited_capacity_worker_max_running_jobs` | Gauge | 13.5 | Maximum number of running jobs | `worker` |
| `limited_capacity_worker_remaining_work_count` | Gauge | 13.5 | Number of jobs waiting to be enqueued | `worker` |
diff --git a/doc/api/graphql/reference/index.md b/doc/api/graphql/reference/index.md
index 7fa58f59717..e4c7907c278 100644
--- a/doc/api/graphql/reference/index.md
+++ b/doc/api/graphql/reference/index.md
@@ -12497,7 +12497,7 @@ Represents a package in the Package Registry. Note that this type is in beta and
| <a id="packagemetadata"></a>`metadata` | [`PackageMetadata`](#packagemetadata) | Package metadata. |
| <a id="packagename"></a>`name` | [`String!`](#string) | Name of the package. |
| <a id="packagepackagetype"></a>`packageType` | [`PackageTypeEnum!`](#packagetypeenum) | Package type. |
-| <a id="packagepipelines"></a>`pipelines` | [`PipelineConnection`](#pipelineconnection) | Pipelines that built the package. (see [Connections](#connections)) |
+| <a id="packagepipelines"></a>`pipelines` **{warning-solid}** | [`PipelineConnection`](#pipelineconnection) | **Deprecated** in 14.6. Due to scalability concerns, this field is going to be removed. |
| <a id="packageproject"></a>`project` | [`Project!`](#project) | Project where the package is stored. |
| <a id="packagestatus"></a>`status` | [`PackageStatus!`](#packagestatus) | Package status. |
| <a id="packagetags"></a>`tags` | [`PackageTagConnection`](#packagetagconnection) | Package tags. (see [Connections](#connections)) |
@@ -12559,7 +12559,7 @@ Represents a package details in the Package Registry. Note that this type is in
| <a id="packagedetailstypename"></a>`name` | [`String!`](#string) | Name of the package. |
| <a id="packagedetailstypepackagefiles"></a>`packageFiles` | [`PackageFileConnection`](#packagefileconnection) | Package files. (see [Connections](#connections)) |
| <a id="packagedetailstypepackagetype"></a>`packageType` | [`PackageTypeEnum!`](#packagetypeenum) | Package type. |
-| <a id="packagedetailstypepipelines"></a>`pipelines` | [`PipelineConnection`](#pipelineconnection) | Pipelines that built the package. (see [Connections](#connections)) |
+| <a id="packagedetailstypepipelines"></a>`pipelines` **{warning-solid}** | [`PipelineConnection`](#pipelineconnection) | **Deprecated** in 14.6. Due to scalability concerns, this field is going to be removed. |
| <a id="packagedetailstypeproject"></a>`project` | [`Project!`](#project) | Project where the package is stored. |
| <a id="packagedetailstypestatus"></a>`status` | [`PackageStatus!`](#packagestatus) | Package status. |
| <a id="packagedetailstypetags"></a>`tags` | [`PackageTagConnection`](#packagetagconnection) | Package tags. (see [Connections](#connections)) |
diff --git a/doc/raketasks/index.md b/doc/raketasks/index.md
index 80aa52ed5a4..6227731e807 100644
--- a/doc/raketasks/index.md
+++ b/doc/raketasks/index.md
@@ -45,6 +45,7 @@ The following Rake tasks are available for use with GitLab:
| [SMTP maintenance](../administration/raketasks/smtp.md) | SMTP-related tasks. |
| [SPDX license list import](spdx.md) | Import a local copy of the [SPDX license list](https://spdx.org/licenses/) for matching [License Compliance policies](../user/compliance/license_compliance/index.md). |
| [Repository storage](../administration/raketasks/storage.md) | List and migrate existing projects and attachments from legacy storage to hashed storage. |
+| [Reset user passwords](../security/reset_user_password.md#use-a-rake-task) | Reset user passwords using Rake. |
| [Uploads migrate](../administration/raketasks/uploads/migrate.md) | Migrate uploads between local storage and object storage. |
| [Uploads sanitize](../administration/raketasks/uploads/sanitize.md) | Remove EXIF data from images uploaded to earlier versions of GitLab. |
| [Service Data](../administration/troubleshooting/gitlab_rails_cheat_sheet.md#generate-service-ping) | Generate and troubleshoot [Service Ping](../development/service_ping/index.md). |
diff --git a/doc/raketasks/user_management.md b/doc/raketasks/user_management.md
index f63c35ab475..09e1b626c0a 100644
--- a/doc/raketasks/user_management.md
+++ b/doc/raketasks/user_management.md
@@ -176,3 +176,7 @@ cp config/secrets.yml.bak config/secrets.yml
sudo /etc/init.d/gitlab start
```
+
+## Related topics
+
+- [Reset a user's password](../security/reset_user_password.md#use-a-rake-task).
diff --git a/doc/security/reset_user_password.md b/doc/security/reset_user_password.md
index 8b89200e1a7..a61660f6a2f 100644
--- a/doc/security/reset_user_password.md
+++ b/doc/security/reset_user_password.md
@@ -5,121 +5,120 @@ info: To determine the technical writer assigned to the Stage/Group associated w
type: howto
---
-# How to reset user password **(FREE SELF)**
+# Reset a user's password **(FREE SELF)**
-There are a few ways to reset the password of a user.
+You can reset user passwords by using a Rake task, a Rails console, or the
+[Users API](../api/users.md#user-modification).
-## Rake Task
+## Prerequisites
+
+To reset a user password, you must be an administrator of a self-managed GitLab instance.
+
+## Use a Rake task
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/52347) in GitLab 13.9.
-GitLab provides a Rake Task to reset passwords of users using their usernames,
-which can be invoked by the following command:
+Use the following Rake task to reset a user's password:
-```shell
-sudo gitlab-rake "gitlab:password:reset"
-```
+- **For Omnibus installations**
-GitLab asks for a username, a password, and a password confirmation. Upon giving
-proper values for them, the password of the specified user is updated.
+ ```shell
+ sudo gitlab-rake "gitlab:password:reset"
+ ```
-The Rake task also takes the username as an argument, as shown in the example
-below:
+- **For installations from source**
-```shell
-sudo gitlab-rake "gitlab:password:reset[johndoe]"
-```
+ ```shell
+ bundle exec rake "gitlab:password:reset"
+ ```
-NOTE:
-To reset the default admin password, run this Rake task with the username
-`root`, which is the default username of that administrator account.
+GitLab requests a username, a password, and confirmation of the password. When complete, the user's password is updated.
-## Rails console
+The Rake task can take a username as an argument. For example, to reset the password for the user with username
+`sidneyjones`:
-The Rake task is capable of finding users via their usernames. However, if only
-user ID or email ID of the user is known, Rails console can be used to find user
-using user ID and then change password of the user manually.
+- **For Omnibus installations**
-1. [Start a Rails console](../administration/operations/rails_console.md)
+ ```shell
+ sudo gitlab-rake "gitlab:password:reset[sidneyjones]"
+ ```
-1. Find the user either by username, user ID or email ID:
+- **For installations from source**
- ```ruby
- user = User.find_by_username 'exampleuser'
+ ```shell
+ bundle exec rake "gitlab:password:reset[sidneyjones]"
+ ```
- #or
+## Use a Rails console
- user = User.find(123)
+If you know the username, user ID, or email address, you can use the Rails console to reset their password:
- #or
+1. Open a [Rails console](../administration/operations/rails_console.md).
+1. Find the user:
- user = User.find_by(email: 'user@example.com')
- ```
+ - By username:
-1. Reset the password
+ ```ruby
+ user = User.find_by_username 'exampleuser'
+ ```
- ```ruby
- user.password = 'secret_pass'
- user.password_confirmation = 'secret_pass'
- ```
+ - By user ID:
-1. When using this method instead of the [Users API](../api/users.md#user-modification),
- GitLab sends an email to the user stating that the user changed their
- password. If the password was changed by an administrator, execute the
- following command to notify the user by email:
+ ```ruby
+ user = User.find(123)
+ ```
- ```ruby
- user.send_only_admin_changed_your_password_notification!
+ - By email address:
+
+ ```ruby
+ user = User.find_by(email: 'user@example.com')
+ ```
+
+1. Reset the password:
+
+ ```ruby
+ user.password = 'secret_pass'
+ user.password_confirmation = 'secret_pass'
```
+1. Optional. Notify the user that an administrator changed their password:
+
+ ```ruby
+ user.send_only_admin_changed_your_password_notification!
+ ```
+
1. Save the changes:
```ruby
user.save!
```
-1. Exit the console, and then try to sign in with your new password.
+1. Exit the console:
+
+ ```ruby
+ exit
+ ```
-NOTE:
-You can also reset passwords by using the [Users API](../api/users.md#user-modification).
+## Reset the root password
-## Password reset does not appear to work
+To reset the root password, follow the steps listed previously.
-If you can't sign on with the new password, it might be because of the [reconfirmation feature](../user/upgrade_email_bypass.md).
+- If the root account name hasn't changed, use the username `root`.
+- If the root account name has changed and you don't know the new username,
+ you might be able to use a Rails console with user ID `1`. In almost all
+ cases, the first user is the default administrator account.
-Try fixing this on the rails console. For example, if your new `root` password isn't working:
+## Troubleshooting
-1. [Start a Rails console](../administration/operations/rails_console.md).
+If the new password doesn't work, it might be [an email confirmation issue](../user/upgrade_email_bypass.md). You can
+attempt to fix this issue in a Rails console. For example, if a new `root` password isn't working:
-1. Find the user and skip reconfirmation, using any of the methods above:
+1. Start a [Rails console](../administration/operations/rails_console.md).
+1. Find the user and skip reconfirmation:
```ruby
user = User.find(1)
user.skip_reconfirmation!
```
-1. Try to sign in again.
-
-## Reset your root password
-
-The previously described steps can also be used to reset the root password.
-
-In normal installations where the username of root account hasn't been changed
-manually, the Rake task can be used with username `root` to reset the root
-password.
-
-If the username was changed to something else and has been forgotten, one
-possible way is to reset the password using Rails console with user ID `1` (in
-almost all the cases, the first user is the default administrator account).
-
-<!-- ## Troubleshooting
-
-Include any troubleshooting steps that you can foresee. If you know beforehand what issues
-one might have when setting this up, or when something is changed, or on upgrading, it's
-important to describe those, too. Think of things that may go wrong and include them here.
-This is important to minimize requests for support, and to avoid doc comments with
-questions that you know someone might ask.
-
-Each scenario can be a third-level heading, e.g. `### Getting error message X`.
-If you have none to add when creating a doc, leave this section in place
-but commented out to help encourage others to add to it in the future. -->
+1. Attempt to sign in again.
diff --git a/doc/update/deprecations.md b/doc/update/deprecations.md
index 2f6468ff9e1..8bf14bc2dce 100644
--- a/doc/update/deprecations.md
+++ b/doc/update/deprecations.md
@@ -127,6 +127,15 @@ In milestone 15.0, we will completely remove `Version` from `PackageType`.
Announced: 2021-11-22
Planned removal: 2022-05-22
+### Deprecate `pipelines` fields in the Package GraphQL types
+
+As part of the work to create a [Package Registry GraphQL API](https://gitlab.com/groups/gitlab-org/-/epics/6318), the Package group deprecated the `pipelines` fields in all Package-related GraphQL types. As of GitLab 14.6, the `pipelines` field is deprecated in [`Package`](https://docs.gitlab.com/ee/api/graphql/reference/index.html#package) and [`PackageDetailsType`](https://docs.gitlab.com/ee/api/graphql/reference/index.html#packagedetailstype) due to scalability and performance concerns.
+
+In milestone 15.0, we will completely remove `pipelines` from `Package` and `PackageDetailsType`. You can follow and contribute to work on a replacement in the epic [GitLab-#7214](https://gitlab.com/groups/gitlab-org/-/epics/7214).
+
+Announced: 2021-12-22
+Planned removal: 2022-05-22
+
### Deprecate legacy approval status names from License Compliance API
We deprecated legacy names for approval status of license policy (blacklisted, approved) in the `managed_licenses` API but they are still used in our API queries and responses. They will be removed in 15.0.
diff --git a/doc/user/application_security/dast/index.md b/doc/user/application_security/dast/index.md
index 23e186e25ec..329e10be239 100644
--- a/doc/user/application_security/dast/index.md
+++ b/doc/user/application_security/dast/index.md
@@ -975,6 +975,11 @@ To view running completed and scheduled on-demand DAST scans for a project, go t
To cancel a pending or running on-demand scan, select **Cancel** (**{cancel}**) in the
on-demand scans list.
+#### Retry an on-demand scan
+
+To retry a scan that failed or succeeded with warnings, select **Retry** (**{retry}**) in the
+on-demand scans list.
+
### Run an on-demand DAST scan
Prerequisites:
diff --git a/doc/user/packages/container_registry/index.md b/doc/user/packages/container_registry/index.md
index c9cdc8643f4..9497dd1625b 100644
--- a/doc/user/packages/container_registry/index.md
+++ b/doc/user/packages/container_registry/index.md
@@ -370,10 +370,17 @@ WARNING:
Deleting images is a destructive action and can't be undone. To restore
a deleted image, you must rebuild and re-upload it.
-NOTE:
-Administrators should review how to
-[garbage collect](../../../administration/packages/container_registry.md#container-registry-garbage-collection)
-the deleted images.
+On self-managed instances, deleting an image doesn't free up storage space - it only marks the image
+as eligible for deletion. To actually delete images and recover storage space, in case they're
+unreferenced, administrators must run [garbage collection](../../../administration/packages/container_registry.md#container-registry-garbage-collection).
+
+On GitLab.com, the latest version of the Container Registry includes an automatic online garbage
+collector. For more information, see [this blog post](https://about.gitlab.com/blog/2021/10/25/gitlab-com-container-registry-update/).
+This is an instance-wide feature, rolling out gradually to a subset of the user base, so some new image repositories created
+from GitLab 14.5 onwards are served by this new version of the Container Registry. In this new
+version of the Container Registry, layers that aren't referenced by any image manifest, and image
+manifests that have no tags and aren't referenced by another manifest (such as multi-architecture
+images), are automatically scheduled for deletion after 24 hours if left unreferenced.
### Delete images from within GitLab
diff --git a/doc/user/project/releases/img/feature_count_v14_6.png b/doc/user/project/releases/img/feature_count_v14_6.png
new file mode 100644
index 00000000000..0b1a0552631
--- /dev/null
+++ b/doc/user/project/releases/img/feature_count_v14_6.png
Binary files differ
diff --git a/doc/user/project/releases/index.md b/doc/user/project/releases/index.md
index 83f0d253e7f..1e00220b172 100644
--- a/doc/user/project/releases/index.md
+++ b/doc/user/project/releases/index.md
@@ -595,6 +595,29 @@ links to a release is not recommended, because artifacts are ephemeral and
are used to pass data in the same pipeline. This means there's a risk that
they could either expire or someone might manually delete them.
+#### Number of new and total features **(FREE SAAS)**
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/235618) in GitLab 13.5.
+
+On [GitLab.com](https://gitlab.com/gitlab-org/gitlab/-/releases), you can view the number of new and total features in the project.
+
+![Feature count](img/feature_count_v14_6.png "Number of features in a release")
+
+The totals are displayed on [shields](https://shields.io/) and are generated per release by
+[a Rake task in the `www-gitlab-com` repo](https://gitlab.com/gitlab-com/www-gitlab-com/-/blob/master/lib/tasks/update_gitlab_project_releases_page.rake).
+
+| Item | Formula |
+| ------ | ------ |
+| `New features` | Total count of release posts across all tiers for a single release in the project. |
+| `Total features` | Total count of release posts in reverse order for all releases in the project. |
+
+The counts are also shown by license tier.
+
+| Item | Formula |
+| ------ | ------ |
+| `New features` | Total count of release posts across a single tier for a single release in the project. |
+| `Total features` | Total count of release posts across a single tier in reverse order for all releases in the project. |
+
## Release evidence
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/26019) in GitLab 12.6.
diff --git a/doc/user/project/wiki/img/content_editor_v14.0.png b/doc/user/project/wiki/img/content_editor_v14.0.png
deleted file mode 100644
index b44a633073d..00000000000
--- a/doc/user/project/wiki/img/content_editor_v14.0.png
+++ /dev/null
Binary files differ
diff --git a/doc/user/project/wiki/img/content_editor_v14.6.png b/doc/user/project/wiki/img/content_editor_v14.6.png
new file mode 100644
index 00000000000..55fca0ace1e
--- /dev/null
+++ b/doc/user/project/wiki/img/content_editor_v14.6.png
Binary files differ
diff --git a/doc/user/project/wiki/img/use_new_editor_button_v14.0.png b/doc/user/project/wiki/img/use_new_editor_button_v14.0.png
deleted file mode 100644
index d9a5cf83302..00000000000
--- a/doc/user/project/wiki/img/use_new_editor_button_v14.0.png
+++ /dev/null
Binary files differ
diff --git a/doc/user/project/wiki/img/use_new_editor_button_v14.6.png b/doc/user/project/wiki/img/use_new_editor_button_v14.6.png
new file mode 100644
index 00000000000..078fed8a1e9
--- /dev/null
+++ b/doc/user/project/wiki/img/use_new_editor_button_v14.6.png
Binary files differ
diff --git a/doc/user/project/wiki/index.md b/doc/user/project/wiki/index.md
index bdef83bd6c4..9f1670d3f4c 100644
--- a/doc/user/project/wiki/index.md
+++ b/doc/user/project/wiki/index.md
@@ -339,27 +339,24 @@ experience in the Wiki. To opt in for the new editor:
1. Create a new wiki page, or edit an existing one.
1. Ensure the wiki page uses the Markdown format. Other formats are not yet supported.
-1. Below the **Format** select box, select **Use the new editor**:
+1. Above the content field, select **Edit rich text**:
- ![Use new editor button image](img/use_new_editor_button_v14.0.png)
+ ![Use new editor button image](img/use_new_editor_button_v14.6.png)
### Use the Content Editor
1. [Create](#create-a-new-wiki-page) a new wiki page, or [edit](#edit-a-wiki-page) an existing one.
1. Select **Markdown** as your format.
-1. Below the **Format** select box, select **Use new editor**.
+1. Above **Content**, select **Edit rich text**.
1. Customize your page's content using the various formatting options available in the content editor.
1. Select **Create page** for a new page, or **Save changes** for an existing page:
- ![Content Editor in Wikis image](img/content_editor_v14.0.png)
+ ![Content Editor in Wikis image](img/content_editor_v14.6.png)
### Switch back to the old editor
1. *If you're editing the page in the content editor,* scroll to **Content**.
-1. Select **Switch me back to the classic editor**.
-1. Select **Switch to classic editor** in the confirmation popup to confirm.
-
-When you switch back to the old editor, any unsaved changes are lost.
+1. Select **Edit source**.
### GitLab Flavored Markdown support
diff --git a/lib/gitlab/database/gitlab_schemas.yml b/lib/gitlab/database/gitlab_schemas.yml
index 2469c5dd44b..f2c1beb3cc9 100644
--- a/lib/gitlab/database/gitlab_schemas.yml
+++ b/lib/gitlab/database/gitlab_schemas.yml
@@ -371,6 +371,7 @@ packages_pypi_metadata: :gitlab_main
packages_rubygems_metadata: :gitlab_main
packages_tags: :gitlab_main
pages_deployments: :gitlab_main
+pages_deployment_states: :gitlab_main
pages_domain_acme_orders: :gitlab_main
pages_domains: :gitlab_main
partitioned_foreign_keys: :gitlab_main
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index 17abab94272..d72dbc44516 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -5481,9 +5481,15 @@ msgstr ""
msgid "Billing|An error occurred while loading billable members list"
msgstr ""
+msgid "Billing|An error occurred while loading pending members list"
+msgstr ""
+
msgid "Billing|An error occurred while removing a billable member"
msgstr ""
+msgid "Billing|Awaiting member signup"
+msgstr ""
+
msgid "Billing|Cannot remove user"
msgstr ""
@@ -24484,6 +24490,9 @@ msgstr ""
msgid "OnDemandScans|The scan could not be canceled."
msgstr ""
+msgid "OnDemandScans|The scan could not be retried."
+msgstr ""
+
msgid "OnDemandScans|There are no finished scans."
msgstr ""
diff --git a/scripts/db_migrate b/scripts/db_migrate
new file mode 100755
index 00000000000..e001843cd50
--- /dev/null
+++ b/scripts/db_migrate
@@ -0,0 +1,11 @@
+#!/bin/bash
+
+root_path="$(cd "$(dirname "$0")/.." || exit ; pwd -P)"
+
+if [[ -d "${root_path}/ee/" ]]; then
+ task="db:migrate:main"
+else
+ task="db:migrate"
+fi
+
+eval "bundle exec rake ${task} ${*}"
diff --git a/spec/features/projects/jobs/user_browses_jobs_spec.rb b/spec/features/projects/jobs/user_browses_jobs_spec.rb
index 8538b894869..a47aab1ec70 100644
--- a/spec/features/projects/jobs/user_browses_jobs_spec.rb
+++ b/spec/features/projects/jobs/user_browses_jobs_spec.rb
@@ -181,7 +181,7 @@ RSpec.describe 'User browses jobs' do
name: 'rspec tests',
stage: 'test')
- create(:ci_job_artifact, :codequality, job: build)
+ create(:ci_job_artifact, :archive, job: build)
end
before do
diff --git a/spec/frontend/environments/confirm_rollback_modal_spec.js b/spec/frontend/environments/confirm_rollback_modal_spec.js
index d62aaec4f69..b699f953945 100644
--- a/spec/frontend/environments/confirm_rollback_modal_spec.js
+++ b/spec/frontend/environments/confirm_rollback_modal_spec.js
@@ -1,6 +1,9 @@
import { GlModal, GlSprintf } from '@gitlab/ui';
import { shallowMount } from '@vue/test-utils';
+import Vue, { nextTick } from 'vue';
+import VueApollo from 'vue-apollo';
import ConfirmRollbackModal from '~/environments/components/confirm_rollback_modal.vue';
+import createMockApollo from 'helpers/mock_apollo_helper';
import eventHub from '~/environments/event_hub';
describe('Confirm Rollback Modal Component', () => {
@@ -17,6 +20,17 @@ describe('Confirm Rollback Modal Component', () => {
modalId: 'test',
};
+ const envWithLastDeploymentGraphql = {
+ name: 'test',
+ lastDeployment: {
+ commit: {
+ shortId: 'abc0123',
+ },
+ 'last?': true,
+ },
+ modalId: 'test',
+ };
+
const envWithoutLastDeployment = {
name: 'test',
modalId: 'test',
@@ -26,7 +40,7 @@ describe('Confirm Rollback Modal Component', () => {
const retryPath = 'test/-/jobs/123/retry';
- const createComponent = (props = {}) => {
+ const createComponent = (props = {}, options = {}) => {
component = shallowMount(ConfirmRollbackModal, {
propsData: {
...props,
@@ -34,6 +48,7 @@ describe('Confirm Rollback Modal Component', () => {
stubs: {
GlSprintf,
},
+ ...options,
});
};
@@ -101,4 +116,121 @@ describe('Confirm Rollback Modal Component', () => {
});
},
);
+
+ describe('graphql', () => {
+ describe.each`
+ hasMultipleCommits | environmentData | retryUrl | primaryPropsAttrs
+ ${true} | ${envWithLastDeploymentGraphql} | ${null} | ${[{ variant: 'danger' }]}
+ ${false} | ${envWithoutLastDeployment} | ${retryPath} | ${[{ variant: 'danger' }, { 'data-method': 'post' }, { href: retryPath }]}
+ `(
+ 'when hasMultipleCommits=$hasMultipleCommits',
+ ({ hasMultipleCommits, environmentData, retryUrl, primaryPropsAttrs }) => {
+ Vue.use(VueApollo);
+
+ let apolloProvider;
+ let rollbackResolver;
+
+ beforeEach(() => {
+ rollbackResolver = jest.fn();
+ apolloProvider = createMockApollo([], {
+ Mutation: { rollbackEnvironment: rollbackResolver },
+ });
+ environment = environmentData;
+ });
+
+ it('should set contain the commit hash and ask for confirmation', () => {
+ createComponent(
+ {
+ environment: {
+ ...environment,
+ lastDeployment: {
+ ...environment.lastDeployment,
+ 'last?': false,
+ },
+ },
+ hasMultipleCommits,
+ retryUrl,
+ graphql: true,
+ },
+ { apolloProvider },
+ );
+ const modal = component.find(GlModal);
+
+ expect(modal.text()).toContain('commit abc0123');
+ expect(modal.text()).toContain('Are you sure you want to continue?');
+ });
+
+ it('should show "Rollback" when isLastDeployment is false', () => {
+ createComponent(
+ {
+ environment: {
+ ...environment,
+ lastDeployment: {
+ ...environment.lastDeployment,
+ 'last?': false,
+ },
+ },
+ hasMultipleCommits,
+ retryUrl,
+ graphql: true,
+ },
+ { apolloProvider },
+ );
+ const modal = component.find(GlModal);
+
+ expect(modal.attributes('title')).toContain('Rollback');
+ expect(modal.attributes('title')).toContain('test');
+ expect(modal.props('actionPrimary').text).toBe('Rollback');
+ expect(modal.props('actionPrimary').attributes).toEqual(primaryPropsAttrs);
+ });
+
+ it('should show "Re-deploy" when isLastDeployment is true', () => {
+ createComponent(
+ {
+ environment: {
+ ...environment,
+ lastDeployment: {
+ ...environment.lastDeployment,
+ 'last?': true,
+ },
+ },
+ hasMultipleCommits,
+ graphql: true,
+ },
+ { apolloProvider },
+ );
+
+ const modal = component.find(GlModal);
+
+ expect(modal.attributes('title')).toContain('Re-deploy');
+ expect(modal.attributes('title')).toContain('test');
+ expect(modal.props('actionPrimary').text).toBe('Re-deploy');
+ });
+
+ it('should commit the "rollback" mutation when "ok" is clicked', async () => {
+ const env = { ...environmentData, isLastDeployment: true };
+
+ createComponent(
+ {
+ environment: env,
+ hasMultipleCommits,
+ graphql: true,
+ },
+ { apolloProvider },
+ );
+
+ const modal = component.find(GlModal);
+ modal.vm.$emit('ok');
+
+ await nextTick();
+ expect(rollbackResolver).toHaveBeenCalledWith(
+ expect.anything(),
+ { environment: env },
+ expect.anything(),
+ expect.anything(),
+ );
+ });
+ },
+ );
+ });
});
diff --git a/spec/frontend/environments/environment_rollback_spec.js b/spec/frontend/environments/environment_rollback_spec.js
index cde675cd9e7..7eff46baaf7 100644
--- a/spec/frontend/environments/environment_rollback_spec.js
+++ b/spec/frontend/environments/environment_rollback_spec.js
@@ -1,7 +1,11 @@
+import Vue from 'vue';
+import VueApollo from 'vue-apollo';
import { GlDropdownItem } from '@gitlab/ui';
import { shallowMount } from '@vue/test-utils';
import RollbackComponent from '~/environments/components/environment_rollback.vue';
import eventHub from '~/environments/event_hub';
+import setEnvironmentToRollback from '~/environments/graphql/mutations/set_environment_to_rollback.mutation.graphql';
+import createMockApollo from 'helpers/mock_apollo_helper';
describe('Rollback Component', () => {
const retryUrl = 'https://gitlab.com/retry';
@@ -50,4 +54,29 @@ describe('Rollback Component', () => {
name: 'test',
});
});
+
+ it('should trigger a graphql mutation when graphql is enabled', () => {
+ Vue.use(VueApollo);
+
+ const apolloProvider = createMockApollo();
+ jest.spyOn(apolloProvider.defaultClient, 'mutate');
+ const environment = {
+ name: 'test',
+ };
+ const wrapper = shallowMount(RollbackComponent, {
+ propsData: {
+ retryUrl,
+ graphql: true,
+ environment,
+ },
+ apolloProvider,
+ });
+ const button = wrapper.find(GlDropdownItem);
+ button.vm.$emit('click');
+
+ expect(apolloProvider.defaultClient.mutate).toHaveBeenCalledWith({
+ mutation: setEnvironmentToRollback,
+ variables: { environment },
+ });
+ });
});
diff --git a/spec/frontend/environments/graphql/mock_data.js b/spec/frontend/environments/graphql/mock_data.js
index e56b6448b7d..e75d3ac0321 100644
--- a/spec/frontend/environments/graphql/mock_data.js
+++ b/spec/frontend/environments/graphql/mock_data.js
@@ -469,6 +469,33 @@ export const folder = {
stopped_count: 0,
};
+export const resolvedEnvironment = {
+ id: 41,
+ globalId: 'gid://gitlab/Environment/41',
+ name: 'review/hello',
+ state: 'available',
+ externalUrl: 'https://example.org',
+ environmentType: 'review',
+ nameWithoutType: 'hello',
+ lastDeployment: null,
+ hasStopAction: false,
+ rolloutStatus: null,
+ environmentPath: '/h5bp/html5-boilerplate/-/environments/41',
+ stopPath: '/h5bp/html5-boilerplate/-/environments/41/stop',
+ cancelAutoStopPath: '/h5bp/html5-boilerplate/-/environments/41/cancel_auto_stop',
+ deletePath: '/api/v4/projects/8/environments/41',
+ folderPath: '/h5bp/html5-boilerplate/-/environments/folders/review',
+ createdAt: '2021-10-04T19:27:00.527Z',
+ updatedAt: '2021-10-04T19:27:00.527Z',
+ canStop: true,
+ logsPath: '/h5bp/html5-boilerplate/-/logs?environment_name=review%2Fhello',
+ logsApiPath: '/h5bp/html5-boilerplate/-/logs/k8s.json?environment_name=review%2Fhello',
+ enableAdvancedLogsQuerying: false,
+ canDelete: false,
+ hasOpenedAlert: false,
+ __typename: 'LocalEnvironment',
+};
+
export const resolvedFolder = {
availableCount: 2,
environments: [
diff --git a/spec/frontend/environments/graphql/resolvers_spec.js b/spec/frontend/environments/graphql/resolvers_spec.js
index 24fd4e45022..a9fcb5bc907 100644
--- a/spec/frontend/environments/graphql/resolvers_spec.js
+++ b/spec/frontend/environments/graphql/resolvers_spec.js
@@ -1,19 +1,31 @@
import MockAdapter from 'axios-mock-adapter';
import axios from '~/lib/utils/axios_utils';
import { resolvers } from '~/environments/graphql/resolvers';
+import environmentToRollback from '~/environments/graphql/queries/environment_to_rollback.query.graphql';
+import createMockApollo from 'helpers/mock_apollo_helper';
import pollIntervalQuery from '~/environments/graphql/queries/poll_interval.query.graphql';
import { TEST_HOST } from 'helpers/test_constants';
-import { environmentsApp, resolvedEnvironmentsApp, folder, resolvedFolder } from './mock_data';
+import {
+ environmentsApp,
+ resolvedEnvironmentsApp,
+ resolvedEnvironment,
+ folder,
+ resolvedFolder,
+} from './mock_data';
const ENDPOINT = `${TEST_HOST}/environments`;
describe('~/frontend/environments/graphql/resolvers', () => {
let mockResolvers;
let mock;
+ let mockApollo;
+ let localState;
beforeEach(() => {
mockResolvers = resolvers(ENDPOINT);
mock = new MockAdapter(axios);
+ mockApollo = createMockApollo();
+ localState = mockApollo.defaultClient.localState;
});
afterEach(() => {
@@ -108,4 +120,19 @@ describe('~/frontend/environments/graphql/resolvers', () => {
);
});
});
+ describe('setEnvironmentToRollback', () => {
+ it('should write the given environment to the cache', () => {
+ localState.client.writeQuery = jest.fn();
+ mockResolvers.Mutation.setEnvironmentToRollback(
+ null,
+ { environment: resolvedEnvironment },
+ localState,
+ );
+
+ expect(localState.client.writeQuery).toHaveBeenCalledWith({
+ query: environmentToRollback,
+ data: { environmentToRollback: resolvedEnvironment },
+ });
+ });
+ });
});
diff --git a/spec/frontend/issues/show/issue_spec.js b/spec/frontend/issues/show/issue_spec.js
index 0de5e7f774f..6d7a31a6c8c 100644
--- a/spec/frontend/issues/show/issue_spec.js
+++ b/spec/frontend/issues/show/issue_spec.js
@@ -17,7 +17,7 @@ const setupHTML = (initialData) => {
};
describe('Issue show index', () => {
- describe('initIssueableApp', () => {
+ describe('initIssuableApp', () => {
it('should initialize app with no potential XSS attack', async () => {
const alertSpy = jest.spyOn(window, 'alert').mockImplementation(() => {});
const parseDataSpy = jest.spyOn(parseData, 'parseIssuableData');
diff --git a/spec/frontend/issues_list/components/issuables_list_app_spec.js b/spec/frontend/issues_list/components/issuables_list_app_spec.js
index 5ef2a2e0525..11854db534e 100644
--- a/spec/frontend/issues_list/components/issuables_list_app_spec.js
+++ b/spec/frontend/issues_list/components/issuables_list_app_spec.js
@@ -13,7 +13,7 @@ import createFlash from '~/flash';
import Issuable from '~/issues_list/components/issuable.vue';
import IssuablesListApp from '~/issues_list/components/issuables_list_app.vue';
import { PAGE_SIZE, PAGE_SIZE_MANUAL, RELATIVE_POSITION } from '~/issues_list/constants';
-import issueablesEventBus from '~/issues_list/eventhub';
+import issuablesEventBus from '~/issues_list/eventhub';
import FilteredSearchBar from '~/vue_shared/components/filtered_search_bar/filtered_search_bar_root.vue';
jest.mock('~/flash');
@@ -185,8 +185,8 @@ describe('Issuables list component', () => {
describe('with bulk editing enabled', () => {
beforeEach(() => {
- issueablesEventBus.$on.mockReset();
- issueablesEventBus.$emit.mockReset();
+ issuablesEventBus.$on.mockReset();
+ issuablesEventBus.$emit.mockReset();
setupApiMock(() => [200, MOCK_ISSUES.slice(0)]);
factory({ canBulkEdit: true });
@@ -239,19 +239,19 @@ describe('Issuables list component', () => {
});
it('broadcasts a message to the bulk edit sidebar when a value is added to selection', () => {
- issueablesEventBus.$emit.mockReset();
+ issuablesEventBus.$emit.mockReset();
const i1 = wrapper.vm.issuables[1];
wrapper.vm.onSelectIssuable({ issuable: i1, selected: true });
return wrapper.vm.$nextTick().then(() => {
- expect(issueablesEventBus.$emit).toHaveBeenCalledTimes(1);
- expect(issueablesEventBus.$emit).toHaveBeenCalledWith('issuables:updateBulkEdit');
+ expect(issuablesEventBus.$emit).toHaveBeenCalledTimes(1);
+ expect(issuablesEventBus.$emit).toHaveBeenCalledWith('issuables:updateBulkEdit');
});
});
it('does not broadcast a message to the bulk edit sidebar when a value is not added to selection', () => {
- issueablesEventBus.$emit.mockReset();
+ issuablesEventBus.$emit.mockReset();
return wrapper.vm
.$nextTick()
@@ -263,19 +263,19 @@ describe('Issuables list component', () => {
})
.then(wrapper.vm.$nextTick)
.then(() => {
- expect(issueablesEventBus.$emit).toHaveBeenCalledTimes(0);
+ expect(issuablesEventBus.$emit).toHaveBeenCalledTimes(0);
});
});
it('listens to a message to toggle bulk editing', () => {
expect(wrapper.vm.isBulkEditing).toBe(false);
- expect(issueablesEventBus.$on.mock.calls[0][0]).toBe('issuables:toggleBulkEdit');
- issueablesEventBus.$on.mock.calls[0][1](true); // Call the message handler
+ expect(issuablesEventBus.$on.mock.calls[0][0]).toBe('issuables:toggleBulkEdit');
+ issuablesEventBus.$on.mock.calls[0][1](true); // Call the message handler
return waitForPromises()
.then(() => {
expect(wrapper.vm.isBulkEditing).toBe(true);
- issueablesEventBus.$on.mock.calls[0][1](false);
+ issuablesEventBus.$on.mock.calls[0][1](false);
})
.then(() => {
expect(wrapper.vm.isBulkEditing).toBe(false);
diff --git a/spec/frontend/jobs/components/table/cells/actions_cell_spec.js b/spec/frontend/jobs/components/table/cells/actions_cell_spec.js
index b70fca8e9e6..6caf36e1461 100644
--- a/spec/frontend/jobs/components/table/cells/actions_cell_spec.js
+++ b/spec/frontend/jobs/components/table/cells/actions_cell_spec.js
@@ -58,6 +58,14 @@ describe('Job actions cell', () => {
wrapper.destroy();
});
+ it('displays the artifacts download button with correct link', () => {
+ createComponent(playableJob);
+
+ expect(findDownloadArtifactsButton().attributes('href')).toBe(
+ playableJob.artifacts.nodes[0].downloadPath,
+ );
+ });
+
it('does not display an artifacts download button', () => {
createComponent(retryableJob);
diff --git a/spec/frontend/jobs/mock_data.js b/spec/frontend/jobs/mock_data.js
index 86be739751b..45d297ba364 100644
--- a/spec/frontend/jobs/mock_data.js
+++ b/spec/frontend/jobs/mock_data.js
@@ -1489,15 +1489,18 @@ export const mockJobsQueryResponse = {
nodes: [
{
downloadPath: '/root/ci-project/-/jobs/2336/artifacts/download?file_type=trace',
+ fileType: 'TRACE',
__typename: 'CiJobArtifact',
},
{
downloadPath:
'/root/ci-project/-/jobs/2336/artifacts/download?file_type=metadata',
+ fileType: 'METADATA',
__typename: 'CiJobArtifact',
},
{
downloadPath: '/root/ci-project/-/jobs/2336/artifacts/download?file_type=archive',
+ fileType: 'ARCHIVE',
__typename: 'CiJobArtifact',
},
],
@@ -1586,7 +1589,16 @@ export const mockJobsQueryEmptyResponse = {
};
export const retryableJob = {
- artifacts: { nodes: [], __typename: 'CiJobArtifactConnection' },
+ artifacts: {
+ nodes: [
+ {
+ downloadPath: '/root/ci-project/-/jobs/847/artifacts/download?file_type=trace',
+ fileType: 'TRACE',
+ __typename: 'CiJobArtifact',
+ },
+ ],
+ __typename: 'CiJobArtifactConnection',
+ },
allowFailure: false,
status: 'SUCCESS',
scheduledAt: null,
@@ -1650,7 +1662,18 @@ export const playableJob = {
artifacts: {
nodes: [
{
- downloadPath: '/root/test-job-artifacts/-/jobs/1982/artifacts/download?file_type=trace',
+ downloadPath: '/root/ci-project/-/jobs/621/artifacts/download?file_type=archive',
+ fileType: 'ARCHIVE',
+ __typename: 'CiJobArtifact',
+ },
+ {
+ downloadPath: '/root/ci-project/-/jobs/621/artifacts/download?file_type=metadata',
+ fileType: 'METADATA',
+ __typename: 'CiJobArtifact',
+ },
+ {
+ downloadPath: '/root/ci-project/-/jobs/621/artifacts/download?file_type=trace',
+ fileType: 'TRACE',
__typename: 'CiJobArtifact',
},
],
diff --git a/spec/models/repository_spec.rb b/spec/models/repository_spec.rb
index d50c60774b4..96cbdb468aa 100644
--- a/spec/models/repository_spec.rb
+++ b/spec/models/repository_spec.rb
@@ -1679,6 +1679,16 @@ RSpec.describe Repository do
expect(blobs.first.name).to eq('foobar')
expect(blobs.size).to eq(1)
end
+
+ context 'when Gitaly returns NoRepository' do
+ before do
+ allow(repository.raw_repository).to receive(:batch_blobs).and_raise(Gitlab::Git::Repository::NoRepository)
+ end
+
+ it 'returns empty array' do
+ expect(repository.blobs_at([%w[master foobar]])).to match_array([])
+ end
+ end
end
describe '#root_ref' do
diff --git a/spec/requests/api/todos_spec.rb b/spec/requests/api/todos_spec.rb
index c6b4f50afae..0944bfb6ba6 100644
--- a/spec/requests/api/todos_spec.rb
+++ b/spec/requests/api/todos_spec.rb
@@ -380,7 +380,7 @@ RSpec.describe API::Todos do
end
end
- describe 'POST :id/issuable_type/:issueable_id/todo' do
+ describe 'POST :id/issuable_type/:issuable_id/todo' do
context 'for an issue' do
let_it_be(:issuable) do
create(:issue, :confidential, project: project_1)