Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
8cd1a72e8f
commit
dd9af4e967
|
@ -1 +1 @@
|
|||
10d5f9bbf09a1405185519e34756925e8cbcc19f
|
||||
ccfab390f7c32dae9d5683662be62d27c80f768f
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
<script>
|
||||
import { GlButton, GlButtonGroup, GlModal, GlModalDirective, GlSprintf } from '@gitlab/ui';
|
||||
import GlCountdown from '~/vue_shared/components/gl_countdown.vue';
|
||||
import { redirectTo } from '~/lib/utils/url_utility';
|
||||
import {
|
||||
ACTIONS_DOWNLOAD_ARTIFACTS,
|
||||
ACTIONS_START_NOW,
|
||||
|
@ -108,11 +109,11 @@ export default {
|
|||
},
|
||||
},
|
||||
methods: {
|
||||
async postJobAction(name, mutation) {
|
||||
async postJobAction(name, mutation, redirect = false) {
|
||||
try {
|
||||
const {
|
||||
data: {
|
||||
[name]: { errors },
|
||||
[name]: { errors, job },
|
||||
},
|
||||
} = await this.$apollo.mutate({
|
||||
mutation,
|
||||
|
@ -121,6 +122,10 @@ export default {
|
|||
if (errors.length > 0) {
|
||||
reportMessageToSentry(this.$options.name, errors.join(', '), {});
|
||||
this.showToastMessage();
|
||||
} else if (redirect) {
|
||||
// Retry and Play actions redirect to job detail view
|
||||
// we don't need to refetch with jobActionPerformed event
|
||||
redirectTo(job.detailedStatus.detailsPath);
|
||||
} else {
|
||||
eventHub.$emit('jobActionPerformed');
|
||||
}
|
||||
|
@ -147,12 +152,12 @@ export default {
|
|||
retryJob() {
|
||||
this.retryBtnDisabled = true;
|
||||
|
||||
this.postJobAction(this.$options.jobRetry, retryJobMutation);
|
||||
this.postJobAction(this.$options.jobRetry, retryJobMutation, true);
|
||||
},
|
||||
playJob() {
|
||||
this.playManualBtnDisabled = true;
|
||||
|
||||
this.postJobAction(this.$options.jobPlay, playJobMutation);
|
||||
this.postJobAction(this.$options.jobPlay, playJobMutation, true);
|
||||
},
|
||||
unscheduleJob() {
|
||||
this.unscheduleBtnDisabled = true;
|
||||
|
|
|
@ -1,3 +1,7 @@
|
|||
fragment Job on CiJob {
|
||||
id
|
||||
detailedStatus {
|
||||
id
|
||||
detailsPath
|
||||
}
|
||||
}
|
||||
|
|
|
@ -713,22 +713,6 @@ pre.light-well {
|
|||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.service-installation {
|
||||
padding: 32px;
|
||||
margin: 32px;
|
||||
border-radius: 3px;
|
||||
background-color: $white;
|
||||
|
||||
h3 {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
hr {
|
||||
margin: 32px 0;
|
||||
border-color: $border-color;
|
||||
}
|
||||
}
|
||||
|
||||
.project-badge {
|
||||
opacity: 0.9;
|
||||
|
||||
|
|
|
@ -5,6 +5,8 @@ module Types
|
|||
class RunnerUpgradeStatusTypeEnum < BaseEnum
|
||||
graphql_name 'CiRunnerUpgradeStatusType'
|
||||
|
||||
value 'UNKNOWN', description: 'Upgrade status is unknown.', value: :unknown
|
||||
|
||||
Gitlab::Ci::RunnerUpgradeCheck::STATUSES.each do |status, description|
|
||||
value status.to_s.upcase, description: description, value: status
|
||||
end
|
||||
|
|
|
@ -336,7 +336,7 @@ module Ci
|
|||
scope :with_only_interruptible_builds, -> do
|
||||
where('NOT EXISTS (?)',
|
||||
Ci::Build.where('ci_builds.commit_id = ci_pipelines.id')
|
||||
.with_status(:running, :success, :failed)
|
||||
.with_status(STARTED_STATUSES)
|
||||
.not_interruptible
|
||||
)
|
||||
end
|
||||
|
|
|
@ -7,16 +7,14 @@ module Ci
|
|||
DEFAULT_STATUS = 'created'
|
||||
BLOCKED_STATUS = %w[manual scheduled].freeze
|
||||
AVAILABLE_STATUSES = %w[created waiting_for_resource preparing pending running success failed canceled skipped manual scheduled].freeze
|
||||
# TODO: replace STARTED_STATUSES with data from BUILD_STARTED_RUNNING_STATUSES in https://gitlab.com/gitlab-org/gitlab/-/issues/273378
|
||||
# see https://gitlab.com/gitlab-org/gitlab/-/merge_requests/82149#note_865508501
|
||||
BUILD_STARTED_RUNNING_STATUSES = %w[running success failed].freeze
|
||||
STARTED_STATUSES = %w[running success failed skipped manual scheduled].freeze
|
||||
STARTED_STATUSES = %w[running success failed].freeze
|
||||
ACTIVE_STATUSES = %w[waiting_for_resource preparing pending running].freeze
|
||||
COMPLETED_STATUSES = %w[success failed canceled skipped].freeze
|
||||
ORDERED_STATUSES = %w[failed preparing pending running waiting_for_resource manual scheduled canceled success skipped created].freeze
|
||||
PASSED_WITH_WARNINGS_STATUSES = %w[failed canceled].to_set.freeze
|
||||
EXCLUDE_IGNORED_STATUSES = %w[manual failed canceled].to_set.freeze
|
||||
CANCELABLE_STATUSES = %w[running waiting_for_resource preparing pending created scheduled].freeze
|
||||
ALIVE_STATUSES = (ACTIVE_STATUSES + ['created']).freeze
|
||||
CANCELABLE_STATUSES = (ALIVE_STATUSES + ['scheduled']).freeze
|
||||
STATUSES_ENUM = { created: 0, pending: 1, running: 2, success: 3,
|
||||
failed: 4, canceled: 5, skipped: 6, manual: 7,
|
||||
scheduled: 8, preparing: 9, waiting_for_resource: 10 }.freeze
|
||||
|
@ -78,8 +76,8 @@ module Ci
|
|||
scope :skipped, -> { with_status(:skipped) }
|
||||
scope :manual, -> { with_status(:manual) }
|
||||
scope :scheduled, -> { with_status(:scheduled) }
|
||||
scope :alive, -> { with_status(:created, :waiting_for_resource, :preparing, :pending, :running) }
|
||||
scope :alive_or_scheduled, -> { with_status(:created, :waiting_for_resource, :preparing, :pending, :running, :scheduled) }
|
||||
scope :alive, -> { with_status(*ALIVE_STATUSES) }
|
||||
scope :alive_or_scheduled, -> { with_status(*klass::CANCELABLE_STATUSES) }
|
||||
scope :created_or_pending, -> { with_status(:created, :pending) }
|
||||
scope :running_or_pending, -> { with_status(:running, :pending) }
|
||||
scope :finished, -> { with_status(:success, :failed, :canceled) }
|
||||
|
@ -98,7 +96,7 @@ module Ci
|
|||
end
|
||||
|
||||
def started?
|
||||
STARTED_STATUSES.include?(status) && started_at
|
||||
STARTED_STATUSES.include?(status) && !!started_at
|
||||
end
|
||||
|
||||
def active?
|
||||
|
|
|
@ -13,7 +13,6 @@ class Integration < ApplicationRecord
|
|||
include IgnorableColumns
|
||||
extend ::Gitlab::Utils::Override
|
||||
|
||||
ignore_column :template, remove_with: '15.0', remove_after: '2022-04-22'
|
||||
ignore_column :type, remove_with: '15.0', remove_after: '2022-04-22'
|
||||
ignore_column :properties, remove_with: '15.1', remove_after: '2022-05-22'
|
||||
|
||||
|
|
|
@ -3,4 +3,5 @@
|
|||
class AwardEmojiEntity < Grape::Entity
|
||||
expose :name
|
||||
expose :user, using: API::Entities::UserSafe
|
||||
expose :url
|
||||
end
|
||||
|
|
|
@ -1,9 +1,3 @@
|
|||
- if @teams_error_message
|
||||
= content_for :flash_message do
|
||||
= render Pajamas::AlertComponent.new(variant: :danger) do
|
||||
.gl-alert-body
|
||||
= @teams_error_message
|
||||
|
||||
%p
|
||||
You aren’t a member of any team on the Mattermost instance at
|
||||
%strong= Gitlab.config.mattermost.host
|
||||
|
|
|
@ -1,10 +1,20 @@
|
|||
- @body_class = 'card-content'
|
||||
- add_to_breadcrumbs _('Integrations'), scoped_integrations_path(project: @project, group: @group)
|
||||
- add_to_breadcrumbs @integration.title, scoped_edit_integration_path(@integration, project: @project, group: @group)
|
||||
- breadcrumb_title _('New')
|
||||
- page_title @integration.title, _('Integrations')
|
||||
- @content_class = 'limit-container-width' unless fluid_layout
|
||||
|
||||
.service-installation
|
||||
.inline.float-right
|
||||
- if @teams_error_message
|
||||
= render Pajamas::AlertComponent.new(variant: :danger) do
|
||||
.gl-alert-body
|
||||
= @teams_error_message
|
||||
|
||||
%h3
|
||||
Install Mattermost Command
|
||||
.gl-float-right
|
||||
= custom_icon('mattermost_logo', size: 48)
|
||||
%h3 Install Mattermost Command
|
||||
- if @teams.empty?
|
||||
= render 'no_teams'
|
||||
- else
|
||||
= render 'team_selection'
|
||||
|
||||
- if @teams.empty?
|
||||
= render 'no_teams'
|
||||
- else
|
||||
= render 'team_selection'
|
||||
|
|
|
@ -47,12 +47,12 @@ module BulkImports
|
|||
end
|
||||
|
||||
if ndjson_pipeline?(pipeline_tracker)
|
||||
status = ExportStatus.new(pipeline_tracker, pipeline_tracker.pipeline_class.relation)
|
||||
export_status = ExportStatus.new(pipeline_tracker, pipeline_tracker.pipeline_class.relation)
|
||||
|
||||
raise(Pipeline::ExpiredError, 'Pipeline timeout') if job_timeout?(pipeline_tracker)
|
||||
raise(Pipeline::FailedError, status.error) if status.failed?
|
||||
raise(Pipeline::FailedError, export_status.error) if export_status.failed?
|
||||
|
||||
return reenqueue(pipeline_tracker) if status.started?
|
||||
return reenqueue(pipeline_tracker) if export_status.started?
|
||||
end
|
||||
|
||||
pipeline_tracker.update!(status_event: 'start', jid: jid)
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
---
|
||||
name: container_registry_migration_phase2_capacity_5
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/85908
|
||||
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/350543
|
||||
milestone: '15.0'
|
||||
type: development
|
||||
group: group::package
|
||||
default_enabled: false
|
|
@ -3,7 +3,10 @@
|
|||
class AddViewForPerTableAutovacuumStatus < Gitlab::Database::Migration[1.0]
|
||||
def up
|
||||
execute <<~SQL
|
||||
CREATE OR REPLACE FUNCTION postgres_pg_stat_activity_autovacuum() RETURNS SETOF pg_catalog.pg_stat_activity AS
|
||||
DROP VIEW IF EXISTS postgres_autovacuum_activity;
|
||||
DROP FUNCTION IF EXISTS postgres_pg_stat_activity_autovacuum;
|
||||
|
||||
CREATE FUNCTION postgres_pg_stat_activity_autovacuum() RETURNS SETOF pg_catalog.pg_stat_activity AS
|
||||
$$
|
||||
SELECT *
|
||||
FROM pg_stat_activity
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class AddMaxSeatsUsedChangedAtToGitlabSubscriptions < Gitlab::Database::Migration[2.0]
|
||||
def change
|
||||
add_column :gitlab_subscriptions, :max_seats_used_changed_at, :datetime_with_timezone
|
||||
end
|
||||
end
|
|
@ -6,7 +6,7 @@ class FixViewForPerTableAutovacuumStatus < Gitlab::Database::Migration[2.0]
|
|||
DROP VIEW IF EXISTS postgres_autovacuum_activity;
|
||||
DROP FUNCTION IF EXISTS postgres_pg_stat_activity_autovacuum;
|
||||
|
||||
CREATE OR REPLACE FUNCTION postgres_pg_stat_activity_autovacuum() RETURNS TABLE(query text, query_start timestamptz) AS
|
||||
CREATE FUNCTION postgres_pg_stat_activity_autovacuum() RETURNS TABLE(query text, query_start timestamptz) AS
|
||||
$$
|
||||
SELECT query, query_start
|
||||
FROM pg_stat_activity
|
||||
|
@ -41,7 +41,7 @@ class FixViewForPerTableAutovacuumStatus < Gitlab::Database::Migration[2.0]
|
|||
DROP VIEW IF EXISTS postgres_autovacuum_activity;
|
||||
DROP FUNCTION IF EXISTS postgres_pg_stat_activity_autovacuum;
|
||||
|
||||
CREATE OR REPLACE FUNCTION postgres_pg_stat_activity_autovacuum() RETURNS SETOF pg_catalog.pg_stat_activity AS
|
||||
CREATE FUNCTION postgres_pg_stat_activity_autovacuum() RETURNS SETOF pg_catalog.pg_stat_activity AS
|
||||
$$
|
||||
SELECT *
|
||||
FROM pg_stat_activity
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
41913029290e231d17f108fadf62e629b8919f5edf8854a4a7ae92e233329af3
|
|
@ -15539,6 +15539,7 @@ CREATE TABLE gitlab_subscriptions (
|
|||
seats_in_use integer DEFAULT 0 NOT NULL,
|
||||
seats_owed integer DEFAULT 0 NOT NULL,
|
||||
trial_extension_type smallint,
|
||||
max_seats_used_changed_at timestamp with time zone,
|
||||
CONSTRAINT check_77fea3f0e7 CHECK ((namespace_id IS NOT NULL))
|
||||
);
|
||||
|
||||
|
|
|
@ -17907,10 +17907,11 @@ Values for sorting runners.
|
|||
|
||||
| Value | Description |
|
||||
| ----- | ----------- |
|
||||
| <a id="cirunnerupgradestatustypeavailable"></a>`AVAILABLE` | An update is available for the runner. |
|
||||
| <a id="cirunnerupgradestatustypeinvalid"></a>`INVALID` | The runner version is invalid. |
|
||||
| <a id="cirunnerupgradestatustypenot_available"></a>`NOT_AVAILABLE` | An update is not available for the runner. |
|
||||
| <a id="cirunnerupgradestatustyperecommended"></a>`RECOMMENDED` | An update is available and recommended for the runner. |
|
||||
| <a id="cirunnerupgradestatustypeavailable"></a>`AVAILABLE` | Upgrade is available for the runner. |
|
||||
| <a id="cirunnerupgradestatustypeinvalid"></a>`INVALID` | Runner version is not valid. |
|
||||
| <a id="cirunnerupgradestatustypenot_available"></a>`NOT_AVAILABLE` | Upgrade is not available for the runner. |
|
||||
| <a id="cirunnerupgradestatustyperecommended"></a>`RECOMMENDED` | Upgrade is available and recommended for the runner. |
|
||||
| <a id="cirunnerupgradestatustypeunknown"></a>`UNKNOWN` | Upgrade status is unknown. |
|
||||
|
||||
### `CodeQualityDegradationSeverity`
|
||||
|
||||
|
|
|
@ -302,6 +302,9 @@ globally or for individual jobs:
|
|||
You can also use variables to configure how many times a runner
|
||||
[attempts certain stages of job execution](#job-stages-attempts).
|
||||
|
||||
When using the Kubernetes executor, you can use variables to
|
||||
[override Kubernetes CPU and memory allocations for requests and limits](https://docs.gitlab.com/runner/executors/kubernetes.html#overwriting-container-resources).
|
||||
|
||||
### Git strategy
|
||||
|
||||
> - Introduced in GitLab 8.9 as an experimental feature.
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
---
|
||||
stage: Monitor
|
||||
group: Respond
|
||||
group: Observability
|
||||
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments
|
||||
---
|
||||
|
||||
|
|
|
@ -52,6 +52,7 @@ module ContainerRegistry
|
|||
#
|
||||
return 25 if Feature.enabled?(:container_registry_migration_phase2_capacity_25)
|
||||
return 10 if Feature.enabled?(:container_registry_migration_phase2_capacity_10)
|
||||
return 5 if Feature.enabled?(:container_registry_migration_phase2_capacity_5)
|
||||
return 2 if Feature.enabled?(:container_registry_migration_phase2_capacity_2)
|
||||
return 1 if Feature.enabled?(:container_registry_migration_phase2_capacity_1)
|
||||
|
||||
|
|
|
@ -6,10 +6,10 @@ module Gitlab
|
|||
include Singleton
|
||||
|
||||
STATUSES = {
|
||||
invalid: 'The runner version is invalid.',
|
||||
not_available: 'An update is not available for the runner.',
|
||||
available: 'An update is available for the runner.',
|
||||
recommended: 'An update is available and recommended for the runner.'
|
||||
invalid: 'Runner version is not valid.',
|
||||
not_available: 'Upgrade is not available for the runner.',
|
||||
available: 'Upgrade is available for the runner.',
|
||||
recommended: 'Upgrade is available and recommended for the runner.'
|
||||
}.freeze
|
||||
|
||||
def initialize
|
||||
|
|
|
@ -1,8 +1,12 @@
|
|||
import { GlModal } from '@gitlab/ui';
|
||||
import { nextTick } from 'vue';
|
||||
import Vue, { nextTick } from 'vue';
|
||||
import VueApollo from 'vue-apollo';
|
||||
import createMockApollo from 'helpers/mock_apollo_helper';
|
||||
import waitForPromises from 'helpers/wait_for_promises';
|
||||
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
|
||||
import { redirectTo } from '~/lib/utils/url_utility';
|
||||
import ActionsCell from '~/jobs/components/table/cells/actions_cell.vue';
|
||||
import eventHub from '~/jobs/components/table/event_hub';
|
||||
import JobPlayMutation from '~/jobs/components/table/graphql/mutations/job_play.mutation.graphql';
|
||||
import JobRetryMutation from '~/jobs/components/table/graphql/mutations/job_retry.mutation.graphql';
|
||||
import JobUnscheduleMutation from '~/jobs/components/table/graphql/mutations/job_unschedule.mutation.graphql';
|
||||
|
@ -15,11 +19,18 @@ import {
|
|||
cannotRetryJob,
|
||||
cannotPlayJob,
|
||||
cannotPlayScheduledJob,
|
||||
retryMutationResponse,
|
||||
playMutationResponse,
|
||||
cancelMutationResponse,
|
||||
unscheduleMutationResponse,
|
||||
} from '../../../mock_data';
|
||||
|
||||
jest.mock('~/lib/utils/url_utility');
|
||||
|
||||
Vue.use(VueApollo);
|
||||
|
||||
describe('Job actions cell', () => {
|
||||
let wrapper;
|
||||
let mutate;
|
||||
|
||||
const findRetryButton = () => wrapper.findByTestId('retry');
|
||||
const findPlayButton = () => wrapper.findByTestId('play');
|
||||
|
@ -31,29 +42,27 @@ describe('Job actions cell', () => {
|
|||
|
||||
const findModal = () => wrapper.findComponent(GlModal);
|
||||
|
||||
const MUTATION_SUCCESS = { data: { JobRetryMutation: { jobId: retryableJob.id } } };
|
||||
const MUTATION_SUCCESS_UNSCHEDULE = {
|
||||
data: { JobUnscheduleMutation: { jobId: scheduledJob.id } },
|
||||
};
|
||||
const MUTATION_SUCCESS_PLAY = { data: { JobPlayMutation: { jobId: playableJob.id } } };
|
||||
const MUTATION_SUCCESS_CANCEL = { data: { JobCancelMutation: { jobId: cancelableJob.id } } };
|
||||
const playMutationHandler = jest.fn().mockResolvedValue(playMutationResponse);
|
||||
const retryMutationHandler = jest.fn().mockResolvedValue(retryMutationResponse);
|
||||
const unscheduleMutationHandler = jest.fn().mockResolvedValue(unscheduleMutationResponse);
|
||||
const cancelMutationHandler = jest.fn().mockResolvedValue(cancelMutationResponse);
|
||||
|
||||
const $toast = {
|
||||
show: jest.fn(),
|
||||
};
|
||||
|
||||
const createComponent = (jobType, mutationType = MUTATION_SUCCESS, props = {}) => {
|
||||
mutate = jest.fn().mockResolvedValue(mutationType);
|
||||
const createMockApolloProvider = (requestHandlers) => {
|
||||
return createMockApollo(requestHandlers);
|
||||
};
|
||||
|
||||
const createComponent = (jobType, requestHandlers, props = {}) => {
|
||||
wrapper = shallowMountExtended(ActionsCell, {
|
||||
propsData: {
|
||||
job: jobType,
|
||||
...props,
|
||||
},
|
||||
apolloProvider: createMockApolloProvider(requestHandlers),
|
||||
mocks: {
|
||||
$apollo: {
|
||||
mutate,
|
||||
},
|
||||
$toast,
|
||||
},
|
||||
});
|
||||
|
@ -101,23 +110,58 @@ describe('Job actions cell', () => {
|
|||
});
|
||||
|
||||
it.each`
|
||||
button | mutationResult | action | jobType | mutationFile
|
||||
${findPlayButton} | ${MUTATION_SUCCESS_PLAY} | ${'play'} | ${playableJob} | ${JobPlayMutation}
|
||||
${findRetryButton} | ${MUTATION_SUCCESS} | ${'retry'} | ${retryableJob} | ${JobRetryMutation}
|
||||
${findCancelButton} | ${MUTATION_SUCCESS_CANCEL} | ${'cancel'} | ${cancelableJob} | ${JobCancelMutation}
|
||||
`('performs the $action mutation', ({ button, mutationResult, jobType, mutationFile }) => {
|
||||
createComponent(jobType, mutationResult);
|
||||
button | action | jobType | mutationFile | handler | jobId
|
||||
${findPlayButton} | ${'play'} | ${playableJob} | ${JobPlayMutation} | ${playMutationHandler} | ${playableJob.id}
|
||||
${findRetryButton} | ${'retry'} | ${retryableJob} | ${JobRetryMutation} | ${retryMutationHandler} | ${retryableJob.id}
|
||||
${findCancelButton} | ${'cancel'} | ${cancelableJob} | ${JobCancelMutation} | ${cancelMutationHandler} | ${cancelableJob.id}
|
||||
`('performs the $action mutation', async ({ button, jobType, mutationFile, handler, jobId }) => {
|
||||
createComponent(jobType, [[mutationFile, handler]]);
|
||||
|
||||
button().vm.$emit('click');
|
||||
|
||||
expect(mutate).toHaveBeenCalledWith({
|
||||
mutation: mutationFile,
|
||||
variables: {
|
||||
id: jobType.id,
|
||||
},
|
||||
});
|
||||
expect(handler).toHaveBeenCalledWith({ id: jobId });
|
||||
});
|
||||
|
||||
it.each`
|
||||
button | action | jobType | mutationFile | handler
|
||||
${findUnscheduleButton} | ${'unschedule'} | ${scheduledJob} | ${JobUnscheduleMutation} | ${unscheduleMutationHandler}
|
||||
${findCancelButton} | ${'cancel'} | ${cancelableJob} | ${JobCancelMutation} | ${cancelMutationHandler}
|
||||
`(
|
||||
'the mutation action $action emits the jobActionPerformed event',
|
||||
async ({ button, jobType, mutationFile, handler }) => {
|
||||
jest.spyOn(eventHub, '$emit').mockImplementation(() => {});
|
||||
|
||||
createComponent(jobType, [[mutationFile, handler]]);
|
||||
|
||||
button().vm.$emit('click');
|
||||
|
||||
await waitForPromises();
|
||||
|
||||
expect(eventHub.$emit).toHaveBeenCalledWith('jobActionPerformed');
|
||||
expect(redirectTo).not.toHaveBeenCalled();
|
||||
},
|
||||
);
|
||||
|
||||
it.each`
|
||||
button | action | jobType | mutationFile | handler | redirectLink
|
||||
${findPlayButton} | ${'play'} | ${playableJob} | ${JobPlayMutation} | ${playMutationHandler} | ${'/root/project/-/jobs/1986'}
|
||||
${findRetryButton} | ${'retry'} | ${retryableJob} | ${JobRetryMutation} | ${retryMutationHandler} | ${'/root/project/-/jobs/1985'}
|
||||
`(
|
||||
'the mutation action $action redirects to the job',
|
||||
async ({ button, jobType, mutationFile, handler, redirectLink }) => {
|
||||
jest.spyOn(eventHub, '$emit').mockImplementation(() => {});
|
||||
|
||||
createComponent(jobType, [[mutationFile, handler]]);
|
||||
|
||||
button().vm.$emit('click');
|
||||
|
||||
await waitForPromises();
|
||||
|
||||
expect(redirectTo).toHaveBeenCalledWith(redirectLink);
|
||||
expect(eventHub.$emit).not.toHaveBeenCalled();
|
||||
},
|
||||
);
|
||||
|
||||
it.each`
|
||||
button | action | jobType
|
||||
${findPlayButton} | ${'play'} | ${playableJob}
|
||||
|
@ -152,20 +196,17 @@ describe('Job actions cell', () => {
|
|||
});
|
||||
|
||||
it('unschedules a job', () => {
|
||||
createComponent(scheduledJob, MUTATION_SUCCESS_UNSCHEDULE);
|
||||
createComponent(scheduledJob, [[JobUnscheduleMutation, unscheduleMutationHandler]]);
|
||||
|
||||
findUnscheduleButton().vm.$emit('click');
|
||||
|
||||
expect(mutate).toHaveBeenCalledWith({
|
||||
mutation: JobUnscheduleMutation,
|
||||
variables: {
|
||||
id: scheduledJob.id,
|
||||
},
|
||||
expect(unscheduleMutationHandler).toHaveBeenCalledWith({
|
||||
id: scheduledJob.id,
|
||||
});
|
||||
});
|
||||
|
||||
it('shows the play job confirmation modal', async () => {
|
||||
createComponent(scheduledJob, MUTATION_SUCCESS);
|
||||
createComponent(scheduledJob);
|
||||
|
||||
findPlayScheduledJobButton().vm.$emit('click');
|
||||
|
||||
|
|
|
@ -1928,3 +1928,75 @@ export const CIJobConnectionExistingCache = {
|
|||
};
|
||||
|
||||
export const mockFailedSearchToken = { type: 'status', value: { data: 'FAILED', operator: '=' } };
|
||||
|
||||
export const retryMutationResponse = {
|
||||
data: {
|
||||
jobRetry: {
|
||||
job: {
|
||||
__typename: 'CiJob',
|
||||
id: '"gid://gitlab/Ci::Build/1985"',
|
||||
detailedStatus: {
|
||||
detailsPath: '/root/project/-/jobs/1985',
|
||||
id: 'pending-1985-1985',
|
||||
__typename: 'DetailedStatus',
|
||||
},
|
||||
},
|
||||
errors: [],
|
||||
__typename: 'JobRetryPayload',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export const playMutationResponse = {
|
||||
data: {
|
||||
jobPlay: {
|
||||
job: {
|
||||
__typename: 'CiJob',
|
||||
id: '"gid://gitlab/Ci::Build/1986"',
|
||||
detailedStatus: {
|
||||
detailsPath: '/root/project/-/jobs/1986',
|
||||
id: 'pending-1986-1986',
|
||||
__typename: 'DetailedStatus',
|
||||
},
|
||||
},
|
||||
errors: [],
|
||||
__typename: 'JobRetryPayload',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export const cancelMutationResponse = {
|
||||
data: {
|
||||
jobCancel: {
|
||||
job: {
|
||||
__typename: 'CiJob',
|
||||
id: '"gid://gitlab/Ci::Build/1987"',
|
||||
detailedStatus: {
|
||||
detailsPath: '/root/project/-/jobs/1987',
|
||||
id: 'pending-1987-1987',
|
||||
__typename: 'DetailedStatus',
|
||||
},
|
||||
},
|
||||
errors: [],
|
||||
__typename: 'JobRetryPayload',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export const unscheduleMutationResponse = {
|
||||
data: {
|
||||
jobUnschedule: {
|
||||
job: {
|
||||
__typename: 'CiJob',
|
||||
id: '"gid://gitlab/Ci::Build/1988"',
|
||||
detailedStatus: {
|
||||
detailsPath: '/root/project/-/jobs/1988',
|
||||
id: 'pending-1988-1988',
|
||||
__typename: 'DetailedStatus',
|
||||
},
|
||||
},
|
||||
errors: [],
|
||||
__typename: 'JobRetryPayload',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
|
|
@ -7,7 +7,7 @@ RSpec.describe Types::Ci::RunnerUpgradeStatusTypeEnum do
|
|||
|
||||
it 'exposes all upgrade status values' do
|
||||
expect(described_class.values.keys).to eq(
|
||||
::Gitlab::Ci::RunnerUpgradeCheck::STATUSES.map { |sym, _| sym.to_s.upcase }
|
||||
['UNKNOWN'] + ::Gitlab::Ci::RunnerUpgradeCheck::STATUSES.map { |sym, _| sym.to_s.upcase }
|
||||
)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -58,23 +58,17 @@ RSpec.describe ContainerRegistry::Migration do
|
|||
describe '.capacity' do
|
||||
subject { described_class.capacity }
|
||||
|
||||
where(:ff_1_enabled, :ff_2_enabled, :ff_10_enabled, :ff_25_enabled, :expected_result) do
|
||||
false | false | false | false | 0
|
||||
true | false | false | false | 1
|
||||
false | true | false | false | 2
|
||||
true | true | false | false | 2
|
||||
false | true | true | false | 10
|
||||
false | true | true | true | 25
|
||||
false | true | false | true | 25
|
||||
true | true | false | true | 25
|
||||
true | true | true | true | 25
|
||||
true | true | true | false | 10
|
||||
true | false | true | false | 10
|
||||
true | false | true | true | 25
|
||||
false | false | true | false | 10
|
||||
false | false | true | true | 25
|
||||
false | false | false | true | 25
|
||||
true | false | false | true | 25
|
||||
where(:ff_1_enabled, :ff_2_enabled, :ff_5_enabled, :ff_10_enabled, :ff_25_enabled, :expected_result) do
|
||||
false | false | false | false | false | 0
|
||||
true | false | false | false | false | 1
|
||||
false | true | false | false | false | 2
|
||||
true | true | false | false | false | 2
|
||||
false | false | true | false | false | 5
|
||||
true | true | true | false | false | 5
|
||||
false | false | false | true | false | 10
|
||||
true | true | true | true | false | 10
|
||||
false | false | false | false | true | 25
|
||||
true | true | true | true | true | 25
|
||||
end
|
||||
|
||||
with_them do
|
||||
|
@ -82,6 +76,7 @@ RSpec.describe ContainerRegistry::Migration do
|
|||
stub_feature_flags(
|
||||
container_registry_migration_phase2_capacity_1: ff_1_enabled,
|
||||
container_registry_migration_phase2_capacity_2: ff_2_enabled,
|
||||
container_registry_migration_phase2_capacity_5: ff_5_enabled,
|
||||
container_registry_migration_phase2_capacity_10: ff_10_enabled,
|
||||
container_registry_migration_phase2_capacity_25: ff_25_enabled
|
||||
)
|
||||
|
|
|
@ -106,7 +106,7 @@ RSpec.describe Gitlab::Ci::Pipeline::Chain::CancelPendingPipelines do
|
|||
create(:ci_build, :interruptible, :running, pipeline: child_pipeline)
|
||||
end
|
||||
|
||||
not_started_statuses = Ci::HasStatus::AVAILABLE_STATUSES - Ci::HasStatus::BUILD_STARTED_RUNNING_STATUSES
|
||||
not_started_statuses = Ci::HasStatus::AVAILABLE_STATUSES - Ci::HasStatus::STARTED_STATUSES
|
||||
context 'when the jobs are cancelable' do
|
||||
cancelable_not_started_statuses = Set.new(not_started_statuses).intersection(Ci::HasStatus::CANCELABLE_STATUSES)
|
||||
cancelable_not_started_statuses.each do |status|
|
||||
|
|
|
@ -142,6 +142,26 @@ RSpec.describe CommitStatus do
|
|||
end
|
||||
end
|
||||
|
||||
describe '.cancelable' do
|
||||
subject { described_class.cancelable }
|
||||
|
||||
%i[running pending waiting_for_resource preparing created scheduled].each do |status|
|
||||
context "when #{status} commit status" do
|
||||
let!(:commit_status) { create(:commit_status, status, pipeline: pipeline) }
|
||||
|
||||
it { is_expected.to contain_exactly(commit_status) }
|
||||
end
|
||||
end
|
||||
|
||||
%i[failed success skipped canceled manual].each do |status|
|
||||
context "when #{status} commit status" do
|
||||
let!(:commit_status) { create(:commit_status, status, pipeline: pipeline) }
|
||||
|
||||
it { is_expected.to be_empty }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#started?' do
|
||||
subject { commit_status.started? }
|
||||
|
||||
|
@ -150,26 +170,28 @@ RSpec.describe CommitStatus do
|
|||
commit_status.started_at = nil
|
||||
end
|
||||
|
||||
it { is_expected.to be_falsey }
|
||||
it { is_expected.to be(false) }
|
||||
end
|
||||
|
||||
%w[running success failed].each do |status|
|
||||
context "if commit status is #{status}" do
|
||||
before do
|
||||
commit_status.status = status
|
||||
end
|
||||
context 'with started_at' do
|
||||
described_class::STARTED_STATUSES.each do |status|
|
||||
context "if commit status is #{status}" do
|
||||
before do
|
||||
commit_status.status = status
|
||||
end
|
||||
|
||||
it { is_expected.to be_truthy }
|
||||
it { is_expected.to eq(true) }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
%w[pending canceled].each do |status|
|
||||
context "if commit status is #{status}" do
|
||||
before do
|
||||
commit_status.status = status
|
||||
(described_class::AVAILABLE_STATUSES - described_class::STARTED_STATUSES).each do |status|
|
||||
context "if commit status is #{status}" do
|
||||
before do
|
||||
commit_status.status = status
|
||||
end
|
||||
|
||||
it { is_expected.to be(false) }
|
||||
end
|
||||
|
||||
it { is_expected.to be_falsey }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -27,10 +27,6 @@ RSpec.describe 'Query.runner(id)' do
|
|||
|
||||
let_it_be(:active_project_runner) { create(:ci_runner, :project) }
|
||||
|
||||
before do
|
||||
allow(Gitlab::Ci::RunnerUpgradeCheck.instance).to receive(:check_runner_upgrade_status)
|
||||
end
|
||||
|
||||
shared_examples 'runner details fetch' do
|
||||
let(:query) do
|
||||
wrap_fields(query_graphql_path(query_path, all_graphql_fields_for('CiRunner')))
|
||||
|
|
|
@ -4,7 +4,7 @@ require 'spec_helper'
|
|||
|
||||
RSpec.describe Ci::JobEntity do
|
||||
let(:user) { create(:user) }
|
||||
let(:job) { create(:ci_build) }
|
||||
let(:job) { create(:ci_build, :running) }
|
||||
let(:project) { job.project }
|
||||
let(:request) { double('request') }
|
||||
|
||||
|
@ -21,6 +21,11 @@ RSpec.describe Ci::JobEntity do
|
|||
|
||||
subject { entity.as_json }
|
||||
|
||||
it 'contains started' do
|
||||
expect(subject).to include(:started)
|
||||
expect(subject[:started]).to eq(true)
|
||||
end
|
||||
|
||||
it 'contains complete to indicate if a pipeline is completed' do
|
||||
expect(subject).to include(:complete)
|
||||
end
|
||||
|
|
|
@ -5,8 +5,11 @@ require 'spec_helper'
|
|||
RSpec.describe DiscussionEntity do
|
||||
include RepoHelpers
|
||||
|
||||
let(:user) { create(:user) }
|
||||
let(:note) { create(:discussion_note_on_merge_request) }
|
||||
let_it_be(:user) { create(:user) }
|
||||
let_it_be(:group) { create(:group) }
|
||||
let_it_be(:project) { create(:project, namespace: group) }
|
||||
|
||||
let(:note) { create(:discussion_note_on_merge_request, project: project) }
|
||||
let(:discussion) { note.discussion }
|
||||
let(:request) { double('request', note_entity: ProjectNoteEntity) }
|
||||
let(:controller) { double('controller') }
|
||||
|
@ -50,10 +53,15 @@ RSpec.describe DiscussionEntity do
|
|||
.to match_schema('entities/note_user_entity')
|
||||
end
|
||||
|
||||
it 'exposes the url for custom award emoji' do
|
||||
custom_emoji = create(:custom_emoji, group: group)
|
||||
create(:award_emoji, awardable: note, name: custom_emoji.name)
|
||||
|
||||
expect(subject[:notes].last[:award_emoji].first.keys).to include(:url)
|
||||
end
|
||||
|
||||
context 'when is LegacyDiffDiscussion' do
|
||||
let(:project) { create(:project) }
|
||||
let(:merge_request) { create(:merge_request, source_project: project) }
|
||||
let(:discussion) { create(:legacy_diff_note_on_merge_request, noteable: merge_request, project: project).to_discussion }
|
||||
let(:discussion) { create(:legacy_diff_note_on_merge_request, noteable: note.noteable, project: project).to_discussion }
|
||||
|
||||
it 'exposes correct attributes' do
|
||||
expect(subject.keys.sort).to include(
|
||||
|
|
Loading…
Reference in New Issue