Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
aacba12c6e
commit
999cc13e0a
61 changed files with 675 additions and 172 deletions
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -1 +1 @@
|
|||
8ede1944ec9793c06dba5011234af7f5c5ec92b7
|
||||
15a1323ae16dffd3ba6b078f6cb81e283a96c72d
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
});
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
mutation SetEnvironmentToRollback($environment: Environment) {
|
||||
setEnvironmentToRollback(environment: $environment) @client
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
query environmentToRollback {
|
||||
environmentToRollback @client {
|
||||
id
|
||||
name
|
||||
lastDeployment
|
||||
}
|
||||
}
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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));
|
||||
},
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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: {
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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: {
|
||||
|
|
|
@ -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');
|
||||
|
|
|
@ -19,6 +19,7 @@ query getJobs(
|
|||
artifacts {
|
||||
nodes {
|
||||
downloadPath
|
||||
fileType
|
||||
}
|
||||
}
|
||||
allowFailure
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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]
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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?)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
|
@ -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
|
38
db/migrate/20211119154221_create_pages_deployment_states.rb
Normal file
38
db/migrate/20211119154221_create_pages_deployment_states.rb
Normal file
|
@ -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
|
|
@ -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
|
1
db/schema_migrations/20211119154221
Normal file
1
db/schema_migrations/20211119154221
Normal file
|
@ -0,0 +1 @@
|
|||
020e17ffd6851fb861a17c1b120ca7cdfa300434d4a9ec923a4edcaa7f951b31
|
1
db/schema_migrations/20211208171402
Normal file
1
db/schema_migrations/20211208171402
Normal file
|
@ -0,0 +1 @@
|
|||
09a9e7fc042aab19bf768a79401f33b6e7408acff303fc0ee68360dfd7605101
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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` |
|
||||
|
|
|
@ -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)) |
|
||||
|
|
|
@ -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). |
|
||||
|
|
|
@ -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).
|
||||
|
|
|
@ -5,72 +5,87 @@ 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:
|
||||
|
||||
```ruby
|
||||
user = User.find_by_username 'exampleuser'
|
||||
```
|
||||
|
||||
- By user ID:
|
||||
|
||||
```ruby
|
||||
user = User.find(123)
|
||||
```
|
||||
|
||||
- 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. Reset the password
|
||||
1. Optional. Notify the user that an administrator changed their password:
|
||||
|
||||
```ruby
|
||||
user.password = 'secret_pass'
|
||||
user.password_confirmation = 'secret_pass'
|
||||
```
|
||||
|
||||
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.send_only_admin_changed_your_password_notification!
|
||||
```
|
||||
```ruby
|
||||
user.send_only_admin_changed_your_password_notification!
|
||||
```
|
||||
|
||||
1. Save the changes:
|
||||
|
||||
|
@ -78,48 +93,32 @@ using user ID and then change password of the user manually.
|
|||
user.save!
|
||||
```
|
||||
|
||||
1. Exit the console, and then try to sign in with your new password.
|
||||
1. Exit the console:
|
||||
|
||||
NOTE:
|
||||
You can also reset passwords by using the [Users API](../api/users.md#user-modification).
|
||||
```ruby
|
||||
exit
|
||||
```
|
||||
|
||||
## Password reset does not appear to work
|
||||
## Reset the root password
|
||||
|
||||
If you can't sign on with the new password, it might be because of the [reconfirmation feature](../user/upgrade_email_bypass.md).
|
||||
To reset the root password, follow the steps listed previously.
|
||||
|
||||
Try fixing this on the rails console. For example, if your new `root` password isn't working:
|
||||
- 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.
|
||||
|
||||
1. [Start a Rails console](../administration/operations/rails_console.md).
|
||||
## Troubleshooting
|
||||
|
||||
1. Find the user and skip reconfirmation, using any of the methods above:
|
||||
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. 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.
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
BIN
doc/user/project/releases/img/feature_count_v14_6.png
Normal file
BIN
doc/user/project/releases/img/feature_count_v14_6.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 24 KiB |
|
@ -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.
|
||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 13 KiB |
BIN
doc/user/project/wiki/img/content_editor_v14.6.png
Normal file
BIN
doc/user/project/wiki/img/content_editor_v14.6.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 15 KiB |
Binary file not shown.
Before Width: | Height: | Size: 16 KiB |
BIN
doc/user/project/wiki/img/use_new_editor_button_v14.6.png
Normal file
BIN
doc/user/project/wiki/img/use_new_editor_button_v14.6.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 11 KiB |
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 ""
|
||||
|
||||
|
|
11
scripts/db_migrate
Executable file
11
scripts/db_migrate
Executable file
|
@ -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} ${*}"
|
|
@ -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
|
||||
|
|
|
@ -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(),
|
||||
);
|
||||
});
|
||||
},
|
||||
);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -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 },
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -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: [
|
||||
|
|
|
@ -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 },
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -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');
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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',
|
||||
},
|
||||
],
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Reference in a new issue