Commit 26411d8f authored by GitLab Bot's avatar GitLab Bot

Automatic merge of gitlab-org/gitlab master

parents d59718db cd09e9a6
import $ from 'jquery';
import { deprecatedCreateFlash as flash } from './flash';
import axios from './lib/utils/axios_utils';
import { __ } from './locale';
/**
* In each pipelines table we have a mini pipeline graph for each pipeline.
*
* When we click in a pipeline stage, we need to make an API call to get the
* builds list to render in a dropdown.
*
* The container should be the table element.
*
* The stage icon clicked needs to have the following HTML structure:
* <div class="dropdown">
* <button class="dropdown js-builds-dropdown-button" data-toggle="dropdown"></button>
* <div class="js-builds-dropdown-container dropdown-menu"></div>
* </div>
*/
export default class MiniPipelineGraph {
constructor(opts = {}) {
this.container = opts.container || '';
this.dropdownListSelector = '.js-builds-dropdown-container';
this.getBuildsList = this.getBuildsList.bind(this);
}
/**
* Adds the event listener when the dropdown is opened.
* All dropdown events are fired at the .dropdown-menu's parent element.
*/
bindEvents() {
$(document)
.off('shown.bs.dropdown', this.container)
.on('shown.bs.dropdown', this.container, this.getBuildsList);
}
/**
* When the user right clicks or cmd/ctrl + click in the job name
* the dropdown should not be closed and the link should open in another tab,
* so we stop propagation of the click event inside the dropdown.
*
* Since this component is rendered multiple times per page we need to guarantee we only
* target the click event of this component.
*/
stopDropdownClickPropagation() {
$(document).on(
'click',
`${this.container} .js-builds-dropdown-list a.mini-pipeline-graph-dropdown-item`,
(e) => {
e.stopPropagation();
},
);
}
/**
* For the clicked stage, renders the given data in the dropdown list.
*
* @param {HTMLElement} stageContainer
* @param {Object} data
*/
renderBuildsList(stageContainer, data) {
const dropdownContainer = stageContainer.parentElement.querySelector(
`${this.dropdownListSelector} .js-builds-dropdown-list ul`,
);
dropdownContainer.innerHTML = data;
}
/**
* For the clicked stage, gets the list of builds.
*
* All dropdown events have a relatedTarget property,
* whose value is the toggling anchor element.
*
* @param {Object} e bootstrap dropdown event
* @return {Promise}
*/
getBuildsList(e) {
const button = e.relatedTarget;
const endpoint = button.dataset.stageEndpoint;
this.renderBuildsList(button, '');
this.toggleLoading(button);
axios
.get(endpoint)
.then(({ data }) => {
this.toggleLoading(button);
this.renderBuildsList(button, data.html);
this.stopDropdownClickPropagation();
})
.catch(() => {
this.toggleLoading(button);
if ($(button).parent().hasClass('open')) {
$(button).dropdown('toggle');
}
flash(__('An error occurred while fetching the builds.'), 'alert');
});
}
/**
* Toggles the visibility of the loading icon.
*
* @param {HTMLElement} stageContainer
* @return {type}
*/
toggleLoading(stageContainer) {
stageContainer.parentElement
.querySelector(`${this.dropdownListSelector} .js-builds-dropdown-loading`)
.classList.toggle('hidden');
}
}
......@@ -36,7 +36,7 @@ export default {
};
</script>
<template>
<div data-testid="widget-mini-pipeline-graph">
<div data-testid="pipeline-mini-graph">
<div
v-for="stage in stages"
:key="stage.name"
......
import { fetchCommitMergeRequests } from '~/commit_merge_requests';
import MiniPipelineGraph from '~/mini_pipeline_graph_dropdown';
import { initCommitPipelineMiniGraph } from './init_commit_pipeline_mini_graph';
import { initDetailsButton } from './init_details_button';
import { loadBranches } from './load_branches';
export const initCommitBoxInfo = (containerSelector = '.js-commit-box-info') => {
const containerEl = document.querySelector(containerSelector);
export const initCommitBoxInfo = () => {
// Display commit related branches
loadBranches(containerEl);
loadBranches();
// Related merge requests to this commit
fetchCommitMergeRequests();
// Display pipeline mini graph for this commit
// Feature flag ci_commit_pipeline_mini_graph_vue
if (gon.features.ciCommitPipelineMiniGraphVue) {
initCommitPipelineMiniGraph();
} else {
new MiniPipelineGraph({
container: '.js-commit-pipeline-graph',
}).bindEvents();
}
initCommitPipelineMiniGraph();
initDetailsButton();
};
......@@ -2,7 +2,8 @@ import axios from 'axios';
import { sanitize } from '~/lib/dompurify';
import { __ } from '~/locale';
export const loadBranches = (containerEl) => {
export const loadBranches = (containerSelector = '.js-commit-box-info') => {
const containerEl = document.querySelector(containerSelector);
if (!containerEl) {
return;
}
......
......@@ -54,12 +54,7 @@ export default {
:file-name="fileName"
:editor-options="{ readOnly: true }"
/>
<div
v-else
class="file-content code js-syntax-highlight"
data-qa-selector="file_content"
:class="$options.userColorScheme"
>
<div v-else class="file-content code js-syntax-highlight" :class="$options.userColorScheme">
<div class="line-numbers">
<a
v-for="line in lineNumbers"
......
......@@ -60,3 +60,11 @@ pre {
a[href]::after {
content: none !important;
}
.with-performance-bar .layout-page {
margin-top: 0;
}
.content-wrapper {
margin-top: 0;
}
......@@ -19,11 +19,6 @@ class Projects::CommitController < Projects::ApplicationController
before_action :define_commit_box_vars, only: [:show, :pipelines]
before_action :define_note_vars, only: [:show, :diff_for_path, :diff_files]
before_action :authorize_edit_tree!, only: [:revert, :cherry_pick]
before_action only: [:show, :pipelines] do
push_frontend_feature_flag(:ci_commit_pipeline_mini_graph_vue, @project, default_enabled: :yaml)
end
before_action do
push_frontend_feature_flag(:pick_into_project)
end
......@@ -214,7 +209,6 @@ class Projects::CommitController < Projects::ApplicationController
def define_commit_box_vars
@last_pipeline = @commit.last_pipeline
return unless ::Gitlab::Ci::Features.ci_commit_pipeline_mini_graph_vue_enabled?(@project)
return unless @commit.last_pipeline
@last_pipeline_stages = StageSerializer.new(project: @project, current_user: @current_user).represent(@last_pipeline.stages)
......
......@@ -152,15 +152,6 @@ class Projects::PipelinesController < Projects::ApplicationController
.represent(@stage, details: true, retried: params[:retried])
end
# TODO: This endpoint is used by mini-pipeline-graph
# TODO: This endpoint should be migrated to `stage.json`
def stage_ajax
@stage = pipeline.legacy_stage(params[:stage])
return not_found unless @stage
render json: { html: view_to_html_string('projects/pipelines/_stage') }
end
def retry
pipeline.retry_failed(current_user)
......
......@@ -45,6 +45,8 @@ module Types
description: 'Artifacts generated by the job.'
field :short_sha, type: GraphQL::STRING_TYPE, null: false,
description: 'Short SHA1 ID of the commit.'
field :scheduling_type, GraphQL::STRING_TYPE, null: true,
description: 'Type of pipeline scheduling. Value is `dag` if the pipeline uses the `needs` keyword, and `stage` otherwise.'
def pipeline
Gitlab::Graphql::Loaders::BatchModelLoader.new(::Ci::Pipeline, object.pipeline_id).find
......
......@@ -118,6 +118,10 @@ module Types
field :active, GraphQL::BOOLEAN_TYPE, null: false, method: :active?,
description: 'Indicates if the pipeline is active.'
field :uses_needs, GraphQL::BOOLEAN_TYPE, null: true,
method: :uses_needs?,
description: 'Indicates if the pipeline has jobs with `needs` dependencies.'
def detailed_status
object.detailed_status(current_user)
end
......
......@@ -131,8 +131,6 @@ module Ci
update_project_statistics project_statistics_name: :build_artifacts_size
scope :not_expired, -> { where('expire_at IS NULL OR expire_at > ?', Time.current) }
scope :with_files_stored_locally, -> { where(file_store: ::JobArtifactUploader::Store::LOCAL) }
scope :with_files_stored_remotely, -> { where(file_store: ::JobArtifactUploader::Store::REMOTE) }
scope :for_sha, ->(sha, project_id) { joins(job: :pipeline).where(ci_pipelines: { sha: sha, project_id: project_id }) }
scope :for_job_name, ->(name) { joins(:job).where(ci_builds: { name: name }) }
......
......@@ -446,6 +446,10 @@ module Ci
@auto_devops_pipelines_completed_total ||= Gitlab::Metrics.counter(:auto_devops_pipelines_completed_total, 'Number of completed auto devops pipelines')
end
def uses_needs?
builds.where(scheduling_type: :dag).any?
end
def stages_count
statuses.select(:stage).distinct.count
end
......
......@@ -4,8 +4,10 @@ module Ci
module Artifactable
extend ActiveSupport::Concern
NotSupportedAdapterError = Class.new(StandardError)
include ObjectStorable
STORE_COLUMN = :file_store
NotSupportedAdapterError = Class.new(StandardError)
FILE_FORMAT_ADAPTERS = {
gzip: Gitlab::Ci::Build::Artifacts::Adapters::GzipStream,
raw: Gitlab::Ci::Build::Artifacts::Adapters::RawStream
......@@ -20,6 +22,7 @@ module Ci
scope :expired_before, -> (timestamp) { where(arel_table[:expire_at].lt(timestamp)) }
scope :expired, -> (limit) { expired_before(Time.current).limit(limit) }
scope :project_id_in, ->(ids) { where(project_id: ids) }
end
def each_blob(&blk)
......
......@@ -46,9 +46,7 @@ class MergeRequestPollCachedWidgetEntity < IssuableEntity
end
end
expose :actual_head_pipeline, as: :pipeline, if: -> (mr, _) {
Feature.enabled?(:merge_request_cached_pipeline_serializer, mr.project) && presenter(mr).can_read_pipeline?
} do |merge_request, options|
expose :actual_head_pipeline, as: :pipeline, if: -> (mr, _) { presenter(mr).can_read_pipeline? } do |merge_request, options|
MergeRequests::PipelineEntity.represent(merge_request.actual_head_pipeline, options)
end
......
......@@ -19,12 +19,6 @@ class MergeRequestPollWidgetEntity < Grape::Entity
# User entities
expose :merge_user, using: UserEntity
expose :actual_head_pipeline, as: :pipeline, if: -> (mr, _) {
Feature.disabled?(:merge_request_cached_pipeline_serializer, mr.project) && presenter(mr).can_read_pipeline?
} do |merge_request, options|
MergeRequests::PipelineEntity.represent(merge_request.actual_head_pipeline, options)
end
expose :merge_pipeline, if: ->(mr, _) { mr.merged? && can?(request.current_user, :read_pipeline, mr.target_project)} do |merge_request, options|
MergeRequests::PipelineEntity.represent(merge_request.merge_pipeline, options)
end
......
-# Renders the content of each li in the dropdown
- subject = local_assigns.fetch(:subject)
- status = subject.detailed_status(current_user)
- klass = "ci-status-icon ci-status-icon-#{status.group}"
- tooltip = "#{subject.name} - #{status.status_tooltip}"
- if status.has_details?
= link_to status.details_path, class: 'mini-pipeline-graph-dropdown-item d-flex', data: { toggle: 'tooltip', title: tooltip, container: 'body' } do
%span{ class: klass }= sprite_icon(status.icon)
%span.gl-text-truncate.mw-70p.gl-pl-2= subject.name
- else
.menu-item.mini-pipeline-graph-dropdown-item.d-flex{ data: { toggle: 'tooltip', title: tooltip, container: 'body' } }
%span{ class: klass }= sprite_icon(status.icon)
%span.gl-text-truncate.mw-70p.gl-pl-2= subject.name
- if status.has_action?
= link_to status.action_path, class: "gl-button ci-action-icon-container ci-action-icon-wrapper js-ci-action-icon", method: status.action_method, data: { toggle: 'tooltip', title: status.action_title, container: 'body' } do
= sprite_icon(status.action_icon, css_class: "icon-action-#{status.action_icon}")
......@@ -59,11 +59,8 @@
- if @last_pipeline.stages_count.nonzero?
#{ n_(s_('Pipeline|with stage'), s_('Pipeline|with stages'), @last_pipeline.stages_count) }
.mr-widget-pipeline-graph
- if ::Gitlab::Ci::Features.ci_commit_pipeline_mini_graph_vue_enabled?(@project)
.stage-cell
.js-commit-pipeline-mini-graph{ data: { stages: @last_pipeline_stages.to_json.html_safe } }
- else
= render 'shared/mini_pipeline_graph', pipeline: @last_pipeline, klass: 'js-commit-pipeline-graph'
.stage-cell
.js-commit-pipeline-mini-graph{ data: { stages: @last_pipeline_stages.to_json.html_safe } }
- if @last_pipeline.duration
in
= time_interval_in_words @last_pipeline.duration
......
- grouped_statuses = @stage.statuses.latest_ordered.group_by(&:status)
- Ci::HasStatus::ORDERED_STATUSES.each do |ordered_status|
- grouped_statuses.fetch(ordered_status, []).each do |status|
%li
= render 'ci/status/dropdown_graph_badge', subject: status
.stage-cell
- pipeline.legacy_stages.each do |stage|
- if stage.status
- detailed_status = stage.detailed_status(current_user)
- icon_status = "#{detailed_status.icon}_borderless"
.stage-container.mt-0.ml-1.dropdown{ class: klass }
%button.mini-pipeline-graph-dropdown-toggle.has-tooltip.js-builds-dropdown-button{ class: "ci-status-icon-#{detailed_status.group}", type: 'button', data: { toggle: 'dropdown', title: "#{stage.name}: #{detailed_status.label}", placement: 'top', "stage-endpoint" => stage_ajax_project_pipeline_path(pipeline.project, pipeline, stage: stage.name) } }
= sprite_icon(icon_status)
%ul.dropdown-menu.mini-pipeline-graph-dropdown-menu.js-builds-dropdown-container
%li.js-builds-dropdown-list.scrollable-menu
%ul
%li.js-builds-dropdown-loading.hidden
.loading-container.text-center
%span.spinner{ 'aria-label': _('Loading') }
......@@ -1307,6 +1307,14 @@
:weight: 5
:idempotent:
:tags: []
- :name: pipeline_processing:ci_initial_pipeline_process
:feature_category: :continuous_integration
:has_external_dependencies:
:urgency: :high
:resource_boundary: :unknown
:weight: 5
:idempotent: true
:tags: []
- :name: pipeline_processing:ci_resource_groups_assign_resource_from_resource_group
:feature_category: :continuous_delivery
:has_external_dependencies:
......
# frozen_string_literal: true
module Ci
class InitialPipelineProcessWorker
include ApplicationWorker
include PipelineQueue
queue_namespace :pipeline_processing
feature_category :continuous_integration
urgency :high
loggable_arguments 1
idempotent!
def perform(pipeline_id)
Ci::Pipeline.find_by_id(pipeline_id).try do |pipeline|
Ci::ProcessPipelineService
.new(pipeline)
.execute
end
end
end
end
---
title: Update mini pipeline appearance in commit page to match other mini pipelines
in the application
merge_request: 56510
author:
type: changed
---
title: Move to btn-confirm from btn-success in pipelines quotas page
merge_request: 57861
author: Yogi (@yo)
type: other
---
title: Remove top margin for print layout
merge_request: 57824
author:
type: changed
---
title: Move pipelines calculation from widget.json to cached_widget.json
merge_request: 57822
author:
type: performance
---
title: Exposes schedulingType on CiJobType and adds usesNeeds to PipelineType
merge_request: 57398
author:
type: added
---
name: ci_commit_pipeline_mini_graph_vue
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/55363
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/323356
milestone: '13.10'
name: ci_async_initial_pipeline_processing
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/57589
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/326217
milestone: '13.11'
type: development
group: group::pipeline authoring
default_enabled: true
group: group::continuous integration
default_enabled: false
---
name: merge_request_cached_pipeline_serializer
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/38273
rollout_issue_url:
milestone: '13.5'
type: development
group: group::code review
default_enabled: false
......@@ -12,7 +12,6 @@ resources :pipelines, only: [:index, :new, :create, :show, :destroy] do
member do
get :stage
get :stage_ajax
post :cancel
post :retry
get :builds
......
......@@ -1220,6 +1220,7 @@ An edge in a connection.
| `pipeline` | [`Pipeline`](#pipeline) | Pipeline the job belongs to. |
| `queuedAt` | [`Time`](#time) | When the job was enqueued and marked as pending. |
| `scheduledAt` | [`Time`](#time) | Schedule for the build. |
| `schedulingType` | [`String`](#string) | Type of pipeline scheduling. Value is `dag` if the pipeline uses the `needs` keyword, and `stage` otherwise. |
| `shortSha` | [`String!`](#string) | Short SHA1 ID of the commit. |
| `stage` | [`CiStage`](#cistage) | Stage of the job. |
| `startedAt` | [`Time`](#time) | When the job was started. |
......@@ -4622,6 +4623,7 @@ Information about pagination in a connection.
| `upstream` | [`Pipeline`](#pipeline) | Pipeline that triggered the pipeline. |
| `user` | [`User`](#user) | Pipeline user. |
| `userPermissions` | [`PipelinePermissions!`](#pipelinepermissions) | Permissions for the current user on the resource. |
| `usesNeeds` | [`Boolean`](#boolean) | Indicates if the pipeline has jobs with `needs` dependencies. |
| `warnings` | [`Boolean!`](#boolean) | Indicates if a pipeline has warnings. |
### `PipelineAnalytics`
......
......@@ -15,7 +15,7 @@ points to. Examples for badges can be the [pipeline status](../../ci/pipelines/s
[test coverage](../../ci/pipelines/settings.md#test-coverage-report-badge), or ways to contact the
project maintainers.
![Badges on Project overview page](img/project_overview_badges.png)
![Badges on Project overview page](img/project_overview_badges_v13_10.png)
## Project badges
......
......@@ -23,9 +23,6 @@ module EE
API_FUZZING_REPORT_TYPES = %w[api_fuzzing].freeze
BROWSER_PERFORMANCE_REPORT_FILE_TYPES = %w[browser_performance performance].freeze
scope :project_id_in, ->(ids) { where(project_id: ids) }
scope :with_files_stored_remotely, -> { where(file_store: ::JobArtifactUploader::Store::REMOTE) }
scope :security_reports, -> (file_types: SECURITY_REPORT_FILE_TYPES) do
requested_file_types = *file_types
......
......@@ -9,7 +9,7 @@
= link_to s_('UsageQuota|Buy additional minutes'),
EE::SUBSCRIPTIONS_MORE_MINUTES_URL,
target: '_blank',
class: 'gl-button btn btn-success float-right',
class: 'gl-button btn btn-confirm float-right',
data: { track_event: 'click_buy_ci_minutes', track_label: namespace.actual_plan_name, track_property: 'pipeline_quota_page' }
.row
......
---
title: Remove key parameter check when validating actor in personal access token API
merge_request: 57675
author:
type: fixed
......@@ -31,7 +31,7 @@ module EE
actor.update_last_used_at!
user = actor.user
error_message = validate_actor_key(actor, params[:key_id])
error_message = validate_actor(actor)
return { success: false, message: error_message } if error_message
......
......@@ -3,8 +3,6 @@
require 'spec_helper'
RSpec.describe Ci::CreatePipelineService do
subject(:execute) { service.execute(:push) }
let_it_be(:downstream_project) { create(:project, name: 'project', namespace: create(:namespace, name: 'some')) }
let(:project) { create(:project, :repository) }
let(:user) { project.owner }
......@@ -30,29 +28,34 @@ RSpec.describe Ci::CreatePipelineService do
end
it 'persists pipeline' do
expect(execute).to be_persisted
pipeline = create_pipeline!
expect(pipeline).to be_persisted
end
it 'persists both jobs' do
expect { execute }.to change(Ci::Build, :count).from(0).to(1)
expect { create_pipeline! }.to change(Ci::Build, :count).from(0).to(1)
.and change(Ci::Bridge, :count).from(0).to(1)
end
it 'persists bridge needs' do
job = execute.builds.first
bridge = execute.stages.last.bridges.first
pipeline = create_pipeline!
job = pipeline.builds.first
bridge = pipeline.bridges.first
expect(bridge.needs.first.name).to eq(job.name)
end
it 'persists bridge target project' do
bridge = execute.stages.last.bridges.first
pipeline = create_pipeline!
bridge = pipeline.bridges.first
expect(bridge.downstream_project).to eq downstream_project
end
it "sets scheduling_type of bridge_dag_job as 'dag'" do
bridge = execute.stages.last.bridges.first
pipeline = create_pipeline!
bridge = pipeline.bridges.first
expect(bridge.scheduling_type).to eq('dag')
end
......@@ -71,12 +74,14 @@ RSpec.describe Ci::CreatePipelineService do
end
it 'creates a pipeline with regular_job and bridge_dag_job pending' do
processables = execute.processables
pipeline = create_pipeline!
processables = pipeline.processables
Ci::InitialPipelineProcessWorker.new.perform(pipeline.id)
regular_job = processables.find { |processable| processable.name == 'regular_job' }
bridge_dag_job = processables.find { |processable| processable.name == 'bridge_dag_job' }
expect(execute).to be_persisted
expect(pipeline).to be_persisted
expect(regular_job.status).to eq('pending')
expect(bridge_dag_job.status).to eq('pending')
end
......@@ -110,11 +115,16 @@ RSpec.describe Ci::CreatePipelineService do
end
it 'has dependencies and variables', :aggregate_failures do
job = execute.builds.first
pipeline = create_pipeline!
job = pipeline.builds.first
expect(job).to be_present
expect(job.all_dependencies).to include(dependency)
expect(job.scoped_variables.to_hash).to include(dependency_variable.key => dependency_variable.value)
end
end
def create_pipeline!
service.execute(:push)
end
end
......@@ -31,8 +31,7 @@ RSpec.describe Ci::CreatePipelineService, '#execute' do
it 'enqueues a new pipeline' do
pipeline = create_pipeline!
expect(pipeline).to be_persisted
expect(pipeline).to be_pending
expect(pipeline).to be_created_successfully
end
end
......
......@@ -173,11 +173,6 @@ RSpec.describe Ci::RunDastScanService do
expect(build.yaml_variables).to contain_exactly(*expected_variables)
end
it 'enqueues a build' do
build = pipeline.builds.first
expect(build.queued_at).not_to be_nil
end
context 'when the pipeline fails to save' do
before do
allow_any_instance_of(Ci::Pipeline).to receive(:created_successfully?).and_return(false)
......
......@@ -109,9 +109,7 @@ module API
end
end
def validate_actor_key(actor, key_id)
return 'Could not find a user without a key' unless key_id
def validate_actor(actor)
return 'Could not find the given key' unless actor.key
'Could not find a user for the given key' unless actor.user
......@@ -206,7 +204,7 @@ module API
actor.update_last_used_at!
user = actor.user
error_message = validate_actor_key(actor, params[:key_id])
error_message = validate_actor(actor)
if params[:user_id] && user.nil?
break { success: false, message: 'Could not find the given user' }
......@@ -235,7 +233,7 @@ module API
actor.update_last_used_at!
user = actor.user
error_message = validate_actor_key(actor, params[:key_id])
error_message = validate_actor(actor)
break { success: false, message: 'Deploy keys cannot be used to create personal access tokens' } if actor.key.is_a?(DeployKey)
......@@ -308,7 +306,7 @@ module API
actor.update_last_used_at!
user = actor.user
error_message = validate_actor_key(actor, params[:key_id])
error_message = validate_actor(actor)
if error_message
{ success: false, message: error_message }
......
......@@ -64,10 +64,6 @@ module Gitlab
::Feature.enabled?(:multiple_cache_per_job, default_enabled: :yaml)
end
def self.ci_commit_pipeline_mini_graph_vue_enabled?(project)
::Feature.enabled?(:ci_commit_pipeline_mini_graph_vue, project, default_enabled: :yaml)
end
def self.remove_duplicate_artifact_exposure_paths?(project)
::Feature.enabled?(:remove_duplicate_artifact_exposure_paths, project, default_enabled: :yaml)
end
......
......@@ -8,9 +8,11 @@ module Gitlab
# After pipeline has been successfully created we can start processing it.
class Process < Chain::Base
def perform!
::Ci::ProcessPipelineService
.new(@pipeline)
.execute
if ::Feature.enabled?(:ci_async_initial_pipeline_processing, project, default_enabled: :yaml)
::Ci::InitialPipelineProcessWorker.perform_async(pipeline.id)
else
::Ci::ProcessPipelineService.new(pipeline).execute
end
end
def break?
......
......@@ -3449,9 +3449,6 @@ msgstr ""
msgid "An error occurred while fetching the board lists. Please try again."
msgstr ""
msgid "An error occurred while fetching the builds."
msgstr ""
msgid "An error occurred while fetching the job log."
msgstr ""
......
......@@ -25,10 +25,6 @@ module QA
element :file_title_content
end
base.view 'app/assets/javascripts/vue_shared/components/blob_viewers/simple_viewer.vue' do
element :file_content
end
base.view 'app/assets/javascripts/blob/components/blob_content.vue' do
element :file_content
end
......
# frozen_string_literal: true
module QA
RSpec.describe 'Create', :smoke do
RSpec.describe 'Create' do # convert back to a smoke test once proved to be stable
describe 'Personal snippet creation' do
it 'user creates a personal snippet', testcase: 'https://gitlab.com/gitlab-org/quality/testcases/-/issues/1704' do
Flow::Login.sign_in
......
......@@ -628,44 +628,6 @@ RSpec.describe Projects::PipelinesController do
end
end
describe 'GET stages_ajax.json' do
let(:pipeline) { create(:ci_pipeline, project: project) }
context 'when accessing existing stage' do
before do
create(:ci_build, pipeline: pipeline, stage: 'build')
get_stage_ajax('build')
end
it 'returns html source for stage dropdown' do
expect(response).to have_gitlab_http_status(:ok)
expect(response).to render_template('projects/pipelines/_stage')
expect(json_response).to include('html')
end
end
context 'when accessing unknown stage' do
before do
get_stage_ajax('test')
end
it 'responds with not found' do
expect(response).to have_gitlab_http_status(:not_found)
end
end
def get_stage_ajax(name)
get :stage_ajax, params: {
namespace_id: project.namespace,
project_id: project,
id: pipeline.id,
stage: name
},
format: :json
end
end
describe 'GET status.json' do
let(:pipeline) { create(:ci_pipeline, project: project) }
let(:status) { pipeline.detailed_status(double('user')) }
......@@ -721,7 +683,7 @@ RSpec.describe Projects::PipelinesController do
pipeline = project.ci_pipelines.last
expected_redirect_path = Gitlab::Routing.url_helpers.project_pipeline_path(project, pipeline)
expect(pipeline).to be_pending
expect(pipeline).to be_created
expect(response).to redirect_to(expected_redirect_path)
end
end
......
......@@ -62,7 +62,7 @@ RSpec.describe 'Merge request > User sees pipelines triggered by merge request',
it 'sees branch pipelines and detached merge request pipelines in correct order' do
page.within('.ci-table') do
expect(page).to have_selector('.ci-pending', count: 2)
expect(page).to have_selector('.ci-created', count: 2)
expect(first('[data-testid="pipeline-url-link"]')).to have_content("##{detached_merge_request_pipeline.id}")
end
end
......@@ -154,7 +154,7 @@ RSpec.describe 'Merge request > User sees pipelines triggered by merge request',
context 'when detached merge request pipeline succeeds' do
before do
detached_merge_request_pipeline.succeed!
detached_merge_request_pipeline.reload.succeed!
wait_for_requests
end
......@@ -168,7 +168,7 @@ RSpec.describe 'Merge request > User sees pipelines triggered by merge request',
context 'when branch pipeline succeeds' do
before do
click_link 'Overview'
push_pipeline.succeed!
push_pipeline.reload.succeed!
wait_for_requests
end
......@@ -197,7 +197,7 @@ RSpec.describe 'Merge request > User sees pipelines triggered by merge request',
it 'sees a branch pipeline in pipeline tab' do
page.within('.ci-table') do
expect(page).to have_selector('.ci-pending', count: 1)
expect(page).to have_selector('.ci-created', count: 1)
expect(first('[data-testid="pipeline-url-link"]')).to have_content("##{push_pipeline.id}")
end
end
......@@ -341,7 +341,7 @@ RSpec.describe 'Merge request > User sees pipelines triggered by merge request',
context 'when the previous pipeline failed in the fork project' do
before do
detached_merge_request_pipeline.drop!
detached_merge_request_pipeline.reload.drop!
end
context 'when the parent project enables pipeline must succeed' do
......@@ -376,7 +376,7 @@ RSpec.describe 'Merge request > User sees pipelines triggered by merge request',
context 'when detached merge request pipeline succeeds' do
before do
detached_merge_request_pipeline.succeed!
detached_merge_request_pipeline.reload.succeed!
wait_for_requests
end
......@@ -389,7 +389,7 @@ RSpec.describe 'Merge request > User sees pipelines triggered by merge request',
context 'when branch pipeline succeeds' do
before do
push_pipeline.succeed!
push_pipeline.reload.succeed!
wait_for_requests
end
......
......@@ -23,7 +23,7 @@ RSpec.describe 'Merge request < User sees mini pipeline graph', :js do
end
it 'displays a mini pipeline graph' do
expect(page).to have_selector('.mr-widget-pipeline-graph')
expect(page).to have_selector('[data-testid="pipeline-mini-graph"]')
end
context 'as json' do
......
......@@ -16,46 +16,28 @@ RSpec.describe 'Mini Pipeline Graph in Commit View', :js do
let(:build) { create(:ci_build, pipeline: pipeline, status: :running) }
shared_examples 'shows ci icon and mini pipeline' do
before do
build.run
visit project_commit_path(project, project.commit.id)
end
it 'display icon with status' do
expect(page).to have_selector('.ci-status-icon-running')
end
it 'displays a mini pipeline graph' do
expect(page).to have_selector('.mr-widget-pipeline-graph')
first('.mini-pipeline-graph-dropdown-toggle').click
wait_for_requests
page.within '.js-builds-dropdown-list' do
expect(page).to have_selector('.ci-status-icon-running')
expect(page).to have_content(build.stage)
end
before do
build.run
visit project_commit_path(project, project.commit.id)
end
build.drop
end
it 'display icon with status' do
expect(page).to have_selector('.ci-status-icon-running')
end
context 'when ci_commit_pipeline_mini_graph_vue is disabled' do
before do
stub_feature_flags(ci_commit_pipeline_mini_graph_vue: false)
end
it 'displays a mini pipeline graph' do
expect(page).to have_selector('[data-testid="pipeline-mini-graph"]')
it_behaves_like 'shows ci icon and mini pipeline'
end
first('.mini-pipeline-graph-dropdown-toggle').click
context 'when ci_commit_pipeline_mini_graph_vue is enabled' do
before do
stub_feature_flags(ci_commit_pipeline_mini_graph_vue: true)
wait_for_requests
page.within '.js-builds-dropdown-list' do
expect(page).to have_selector('.ci-status-icon-running')
expect(page).to have_content(build.stage)
end
it_behaves_like 'shows ci icon and mini pipeline'
build.drop
end
end
......@@ -65,7 +47,7 @@ RSpec.describe 'Mini Pipeline Graph in Commit View', :js do
end
it 'does not display a mini pipeline graph' do
expect(page).not_to have_selector('.mr-widget-pipeline-graph')
expect(page).not_to have_selector('[data-testid="pipeline-mini-graph"]')
end
end
end
......@@ -534,7 +534,7 @@ RSpec.describe 'Pipelines', :js do
end
it 'renders a mini pipeline graph' do
expect(page).to have_selector('[data-testid="widget-mini-pipeline-graph"]')
expect(page).to have_selector('[data-testid="pipeline-mini-graph"]')
expect(page).to have_selector(dropdown_selector)
end
......
<div class="js-builds-dropdown-tests dropdown dropdown" data-testid="widget-mini-pipeline-graph">
<button class="js-builds-dropdown-button" data-toggle="dropdown" data-stage-endpoint="foobar">
Dropdown
</button>
<ul class="dropdown-menu mini-pipeline-graph-dropdown-menu js-builds-dropdown-container">
<li class="js-builds-dropdown-list scrollable-menu">
<ul></ul>
</li>
<li class="js-builds-dropdown-loading hidden">
<span class="gl-spinner"></span>
</li>
</ul>
</div>
import MockAdapter from 'axios-mock-adapter';
import $ from 'jquery';
import waitForPromises from 'helpers/wait_for_promises';
import axios from '~/lib/utils/axios_utils';
import MiniPipelineGraph from '~/mini_pipeline_graph_dropdown';
describe('Mini Pipeline Graph Dropdown', () => {
beforeEach(() => {
loadFixtures('static/mini_dropdown_graph.html');
});
describe('When is initialized', () => {
it('should initialize without errors when no options are given', () => {
const miniPipelineGraph = new MiniPipelineGraph();
expect(miniPipelineGraph.dropdownListSelector).toEqual('.js-builds-dropdown-container');
});
it('should set the container as the given prop', () => {
const container = '.foo';
const miniPipelineGraph = new MiniPipelineGraph({ container });
expect(miniPipelineGraph.container).toEqual(container);
});
});
describe('When dropdown is clicked', () => {
let mock;
beforeEach(() => {
mock = new MockAdapter(axios);
});
afterEach(() => {
mock.restore();
});
it('should call getBuildsList', () => {
const getBuildsListSpy = jest
.spyOn(MiniPipelineGraph.prototype, 'getBuildsList')
.mockImplementation(() => {});
new MiniPipelineGraph({ container: '.js-builds-dropdown-tests' }).bindEvents();
document.querySelector('.js-builds-dropdown-button').click();
expect(getBuildsListSpy).toHaveBeenCalled();
});
it('should make a request to the endpoint provided in the html', () => {
const ajaxSpy = jest.spyOn(axios, 'get');
mock.onGet('foobar').reply(200, {
html: '',
});
new MiniPipelineGraph({ container: '.js-builds-dropdown-tests' }).bindEvents();
document.querySelector('.js-builds-dropdown-button').click();
expect(ajaxSpy.mock.calls[0][0]).toEqual('foobar');
});
it('should not close when user uses cmd/ctrl + click', (done) => {
mock.onGet('foobar').reply(200, {
html: `<li>
<a class="mini-pipeline-graph-dropdown-item" href="#">
<span class="ci-status-icon ci-status-icon-failed"></span>
<span>build</span>
</a>
<a class="ci-action-icon-wrapper js-ci-action-icon" href="#"></a>
</li>`,
});
new MiniPipelineGraph({ container: '.js-builds-dropdown-tests' }).bindEvents();
document.querySelector('.js-builds-dropdown-button').click();
waitForPromises()
.then(() => {
document.querySelector('a.mini-pipeline-graph-dropdown-item').click();
})
.then(waitForPromises)
.then(() => {
expect($('.js-builds-dropdown-list').is(':visible')).toEqual(true);
})
.then(done)
.catch(done.fail);
});
it('should close the dropdown when request returns an error', (done) => {
mock.onGet('foobar').networkError();
new MiniPipelineGraph({ container: '.js-builds-dropdown-tests' }).bindEvents();
document.querySelector('.js-builds-dropdown-button').click();
setImmediate(() => {
expect($('.js-builds-dropdown-tests .dropdown').hasClass('open')).toEqual(false);
done();
});
});
});
});
import axios from 'axios';
import MockAdapter from 'axios-mock-adapter';
import { setHTMLFixture } from 'helpers/fixtures';
import waitForPromises from 'helpers/wait_for_promises';
import { loadBranches } from '~/projects/commit_box/info/load_branches';
......@@ -9,32 +10,38 @@ const mockBranchesRes =
describe('~/projects/commit_box/info/load_branches', () => {
let mock;
let el;
const getElInnerHtml = () => document.querySelector('.js-commit-box-info').innerHTML;
beforeEach(() => {
setHTMLFixture(`
<div class="js-commit-box-info" data-commit-path="${mockCommitPath}">
<div class="commit-info branches">
<span class="spinner"/>
</div>
</div>`);
mock = new MockAdapter(axios);
mock.onGet(mockCommitPath).reply(200, mockBranchesRes);
el = document.createElement('div');
el.dataset.commitPath = mockCommitPath;
el.innerHTML = '<div class="commit-info branches"><span class="spinner"/></div>';
});
it('loads and renders branches info', async () => {
loadBranches(el);
loadBranches();
await waitForPromises();
expect(el.innerHTML).toBe(`<div class="commit-info branches">${mockBranchesRes}</div>`);
expect(getElInnerHtml()).toMatchInterpolatedText(
`<div class="commit-info branches">${mockBranchesRes}</div>`,
);
});
it('does not load when no container is provided', async () => {
loadBranches(null);
loadBranches('.js-another-class');
await waitForPromises();
expect(mock.history.get).toHaveLength(0);
});
describe('when braches request returns unsafe content', () => {
describe('when branches request returns unsafe content', () => {
beforeEach(() => {
mock
.onGet(mockCommitPath)
......@@ -42,25 +49,25 @@ describe('~/projects/commit_box/info/load_branches', () => {
});
it('displays sanitized html', async () => {
loadBranches(el);
loadBranches();
await waitForPromises();
expect(el.innerHTML).toBe(
expect(getElInnerHtml()).toMatchInterpolatedText(
'<div class="commit-info branches"><a href="/-/commits/master">master</a></div>',
);
});
});
describe('when braches request fails', () => {
describe('when branches request fails', () => {
beforeEach(() => {
mock.onGet(mockCommitPath).reply(500, 'Error!');
});
it('attempts to load and renders an error', async () => {
loadBranches(el);
loadBranches();
await waitForPromises();
expect(el.innerHTML).toBe(
expect(getElInnerHtml()).toMatchInterpolatedText(
'<div class="commit-info branches">Failed to load branches. Please try again.</div>',
);
});
......
......@@ -4,7 +4,6 @@ exports[`Blob Simple Viewer component rendering matches the snapshot 1`] = `
<div>
<div
class="file-content code js-syntax-highlight"
data-qa-selector="file_content"
>
<div
class="line-numbers"
......
......@@ -20,7 +20,7 @@ RSpec.describe Types::Ci::JobType do
pipeline
queued_at
scheduledAt
scheduledAt
schedulingType
shortSha
stage
started_at
......
......@@ -11,8 +11,8 @@ RSpec.describe Types::Ci::PipelineType do
expected_fields = %w[
id iid sha before_sha status detailed_status config_source duration
coverage created_at updated_at started_at finished_at committed_at
stages user retryable cancelable jobs job source_job downstream
upstream path project active user_permissions warnings commit_path
stages user retryable cancelable jobs source_job job downstream
upstream path project active user_permissions warnings commit_path uses_needs
]
if Gitlab.ee?
......
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe Gitlab::Ci::Pipeline::Chain::Pipeline::Process do
let_it_be(:project) { build(:project) }
let_it_be(:user) { build(:user) }
let_it_be(:pipeline) { build(:ci_pipeline, project: project, id: 42) }
let_it_be(:command) do
Gitlab::Ci::Pipeline::Chain::Command.new(project: project, current_user: user)
end
let(:step) { described_class.new(pipeline, command) }
describe '#perform!' do
subject(:perform) { step.perform! }
it 'schedules a job to process the pipeline' do
expect(Ci::InitialPipelineProcessWorker)
.to receive(:perform_async)
.with(42)
perform
end
context 'with async processing disabled' do
before do
stub_feature_flags(ci_async_initial_pipeline_processing: false)
end
it 'processes pipeline inline' do
expect(::Ci::ProcessPipelineService)
.to receive(:new)
.with(pipeline)
.and_call_original
perform
end
end
end
describe '#break?' do
it { expect(step.break?).to be_falsey }
end
end
......@@ -3782,6 +3782,26 @@ RSpec.describe Ci::Pipeline, :mailer, factory_default: :keep do
end
end
describe '#uses_needs?' do
let_it_be(:pipeline) { create(:ci_pipeline) }
context 'when the scheduling type is `dag`' do
it 'returns true' do
create(:ci_build, pipeline: pipeline, scheduling_type: :dag)
expect(pipeline.uses_needs?).to eq(true)
end
end
context 'when the scheduling type is nil or stage' do
it 'returns false' do
create(:ci_build, pipeline: pipeline, scheduling_type: :stage)
expect(pipeline.uses_needs?).to eq(false)
end
end
end
describe '#total_size' do
let(:pipeline) { create(:ci_pipeline) }
let!(:build_job1) { create(:ci_build, pipeline: pipeline, stage_idx: 0) }
......
......@@ -72,5 +72,33 @@ RSpec.describe Ci::Artifactable do
expect(Ci::JobArtifact.expired(1).order_id_asc).to eq([recently_expired_artifact])
end
end
describe '.with_files_stored_locally' do
it 'returns artifacts stored locally' do
expect(Ci::JobArtifact.with_files_stored_locally).to contain_exactly(recently_expired_artifact, later_expired_artifact, not_expired_artifact)
end
end
describe '.with_files_stored_remotely' do
let(:remote_artifact) { create(:ci_job_artifact, :remote_store) }
before do
stub_artifacts_object_storage
end
it 'returns artifacts stored remotely' do
expect(Ci::JobArtifact.with_files_stored_remotely).to contain_exactly(remote_artifact)
end
end
describe '.project_id_in' do
context 'when artifacts belongs to projects' do
let(:project_ids) { [recently_expired_artifact.project.id, not_expired_artifact.project.id, non_existing_record_id] }
it 'returns artifacts belonging to projects' do
expect(Ci::JobArtifact.project_id_in(project_ids)).to contain_exactly(recently_expired_artifact, not_expired_artifact)
end
end
end
end
end
......@@ -49,8 +49,6 @@ RSpec.describe API::Triggers do
expect(response).to have_gitlab_http_status(:created)
expect(json_response).to include('id' => pipeline.id)
pipeline.builds.reload
expect(pipeline.builds.pending.size).to eq(2)
expect(pipeline.builds.size).to eq(5)
end
......
......@@ -248,14 +248,6 @@ RSpec.describe MergeRequestPollCachedWidgetEntity do
expect(subject[:pipeline]).to eq(pipeline_payload)
end
context 'when merge_request_cached_pipeline_serializer is disabled' do
it 'does not return pipeline' do
stub_feature_flags(merge_request_cached_pipeline_serializer: false)
expect(subject[:pipeline]).to be_nil
end
end
end
context 'when user does not have access to pipelines' do
......
......@@ -226,19 +226,6 @@ RSpec.describe MergeRequestPollWidgetEntity do
expect(subject[:pipeline]).to be_nil
end
context 'when merge_request_cached_pipeline_serializer is disabled' do
it 'returns detailed info about pipeline' do
stub_feature_flags(merge_request_cached_pipeline_serializer: false)
pipeline_payload =
MergeRequests::PipelineEntity
.represent(pipeline, request: req)
.as_json
expect(subject[:pipeline]).to eq(pipeline_payload)
end
end
it 'returns ci_status' do
expect(subject[:ci_status]).to eq('pending')
end
......
......@@ -112,7 +112,7 @@ RSpec.describe Ci::CreateDownstreamPipelineService, '#execute' do
it 'updates bridge status when downstream pipeline gets processed' do
pipeline = service.execute(bridge)
expect(pipeline.reload).to be_pending
expect(pipeline.reload).to be_created
expect(bridge.reload).to be_success
end
......@@ -227,7 +227,7 @@ RSpec.describe Ci::CreateDownstreamPipelineService, '#execute' do
it 'updates bridge status when downstream pipeline gets processed' do
pipeline = service.execute(bridge)
expect(pipeline.reload).to be_pending
expect(pipeline.reload).to be_created
expect(bridge.reload).to be_success
end
......
......@@ -40,6 +40,7 @@ RSpec.describe Ci::CreatePipelineService, '#execute' do
it 'creates bridge job with resource group' do
pipeline = create_pipeline!
Ci::InitialPipelineProcessWorker.new.perform(pipeline.id)
test = pipeline.statuses.find_by(name: 'instrumentation_test')
expect(pipeline).to be_created_successfully
......
......@@ -202,7 +202,7 @@ RSpec.describe Ci::CreatePipelineService do
YAML
end
it 'creates a pipeline with build_a and test_b pending; deploy_b manual' do
it 'creates a pipeline with build_a and test_b pending; deploy_b manual', :sidekiq_inline do
processables = pipeline.processables
build_a = processables.find { |processable| processable.name == 'build_a' }
......
......@@ -91,6 +91,7 @@ RSpec.describe Ci::CreatePipelineService, '#execute' do
it 'creates bridge job with resource group', :aggregate_failures do
pipeline = create_pipeline!
Ci::InitialPipelineProcessWorker.new.perform(pipeline.id)
test = pipeline.statuses.find_by(name: 'instrumentation_test')
expect(pipeline).to be_created_successfully
......
......@@ -230,8 +230,8 @@ RSpec.describe Ci::CreatePipelineService do
end
context 'matching the first rule in the list' do
it 'saves a pending pipeline' do
expect(pipeline).to be_pending
it 'saves a created pipeline' do
expect(pipeline).to be_created
expect(pipeline).to be_persisted
end
end
......@@ -239,8 +239,8 @@ RSpec.describe Ci::CreatePipelineService do
context 'matching the last rule in the list' do
let(:ref) { 'refs/heads/feature' }
it 'saves a pending pipeline' do
expect(pipeline).to be_pending
it 'saves a created pipeline' do
expect(pipeline).to be_created
expect(pipeline).to be_persisted
end
end
......@@ -280,8 +280,8 @@ RSpec.describe Ci::CreatePipelineService do
end
context 'matching the first rule in the list' do
it 'saves a pending pipeline' do
expect(pipeline).to be_pending
it 'saves a created pipeline' do
expect(pipeline).to be_created
expect(pipeline).to be_persisted
end
end
......@@ -305,8 +305,8 @@ RSpec.describe Ci::CreatePipelineService do
context 'with partial match' do
let(:ref) { 'refs/heads/feature' }
it 'saves a pending pipeline' do
expect(pipeline).to be_pending
it 'saves a created pipeline' do
expect(pipeline).to be_created
expect(pipeline).to be_persisted
end
end
......@@ -349,8 +349,8 @@ RSpec.describe Ci::CreatePipelineService do
context 'where workflow passes and the job passes' do
let(:ref) { 'refs/heads/feature' }
it 'saves a pending pipeline' do
expect(pipeline).to be_pending
it 'saves a created pipeline' do
expect(pipeline).to be_created
expect(pipeline).to be_persisted
end
end
......
......@@ -63,7 +63,7 @@ RSpec.describe Ci::CreatePipelineService do
expect(pipeline).to be_push
expect(pipeline).to eq(project.ci_pipelines.last)
expect(pipeline).to have_attributes(user: user)
expect(pipeline).to have_attributes(status: 'pending')
expect(pipeline).to have_attributes(status: 'created')
expect(pipeline.iid).not_to be_nil
expect(pipeline.repository_source?).to be true
expect(pipeline.builds.first).to be_kind_of(Ci::Build)
......@@ -253,7 +253,7 @@ RSpec.describe Ci::CreatePipelineService do
pipeline
pipeline_on_previous_commit
expect(pipeline.reload).to have_attributes(status: 'pending', auto_canceled_by_id: nil)
expect(pipeline.reload).to have_attributes(status: 'created', auto_canceled_by_id: nil)
end
it 'auto cancel pending non-HEAD pipelines', :sidekiq_might_not_need_inline do
......@@ -263,8 +263,8 @@ RSpec.describe Ci::CreatePipelineService do
expect(pipeline_on_previous_commit.reload).to have_attributes(status: 'canceled', auto_canceled_by_id: pipeline.id)
end
it 'cancels running outdated pipelines', :sidekiq_might_not_need_inline do
pipeline_on_previous_commit.run
it 'cancels running outdated pipelines', :sidekiq_inline do
pipeline_on_previous_commit.reload.run
head_pipeline = execute_service
expect(pipeline_on_previous_commit.reload).to have_attributes(status: 'canceled', auto_canceled_by_id: head_pipeline.id)
......@@ -278,13 +278,13 @@ RSpec.describe Ci::CreatePipelineService do
end
it 'does not cancel pipelines from the other branches' do
pending_pipeline = execute_service(
new_pipeline = execute_service(
ref: 'refs/heads/feature',
after: previous_commit_sha_from_ref('feature')
)
pipeline
expect(pending_pipeline.reload).to have_attributes(status: 'pending', auto_canceled_by_id: nil)
expect(new_pipeline.reload).to have_attributes(status: 'created', auto_canceled_by_id: nil)
end
context 'when the interruptible attribute is' do
......@@ -465,12 +465,12 @@ RSpec.describe Ci::CreatePipelineService do
project.update!(auto_cancel_pending_pipelines: 'disabled')
end
it 'does not auto cancel pending non-HEAD pipelines' do
it 'does not auto cancel created non-HEAD pipelines' do
pipeline_on_previous_commit
pipeline
expect(pipeline_on_previous_commit.reload)
.to have_attributes(status: 'pending', auto_canceled_by_id: nil)
.to have_attributes(status: 'created', auto_canceled_by_id: nil)
end
end
......@@ -770,7 +770,7 @@ RSpec.describe Ci::CreatePipelineService do
stub_ci_pipeline_yaml_file(config)
end
it 'does not create a new pipeline' do
it 'does not create a new pipeline', :sidekiq_inline do
result = execute_service
expect(result).to be_persisted
......
......@@ -34,7 +34,7 @@ RSpec.describe Ci::ExternalPullRequests::CreatePipelineService do
expect(subject).to eq(project.ci_pipelines.last)
expect(subject.external_pull_request).to eq(pull_request)
expect(subject.user).to eq(user)
expect(subject.status).to eq('pending')
expect(subject.status).to eq('created')
expect(subject.ref).to eq(pull_request.source_branch)
expect(subject.sha).to eq(pull_request.source_sha)
expect(subject.source_sha).to eq(pull_request.source_sha)
......
# frozen_string_literal: true
RSpec.shared_examples 'actor key validations' do
context 'key id is not provided' do
let(:key_id) { nil }
it 'returns an error message' do
subject
expect(json_response['success']).to be_falsey
expect(json_response['message']).to eq('Could not find a user without a key')
end
end
context 'key does not exist' do
let(:key_id) { non_existing_record_id }
......
......@@ -34,14 +34,6 @@ RSpec.describe 'projects/commit/_commit_box.html.haml' do
expect(rendered).to have_selector('.js-commit-pipeline-mini-graph')
end
it 'shows pipeline stages in haml when feature flag is disabled' do
stub_feature_flags(ci_commit_pipeline_mini_graph_vue: false)
render
expect(rendered).to have_selector('.js-commit-pipeline-graph')
end
end
context 'when there are multiple pipelines for a commit' do
......
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe 'projects/pipelines/_stage' do
let(:project) { create(:project, :repository) }
let(:pipeline) { create(:ci_pipeline, project: project) }
let(:stage) { build(:ci_stage, pipeline: pipeline) }
before do
assign :stage, stage
end
context 'when there are only latest builds present' do
before do
create(:ci_build, name: 'test:build',
stage: stage.name,
pipeline: pipeline)
end
it 'shows the builds in the stage' do
render
expect(rendered).to have_text 'test:build'
end
end
context 'when build belongs to different stage' do
before do
create(:ci_build, name: 'test:build',
stage: 'other:stage',
pipeline: pipeline)
end
it 'does not render build' do
render
expect(rendered).not_to have_text 'test:build'
end
end
context 'when there are retried builds present' do
before do
create(:ci_build, name: 'test:build', stage: stage.name, pipeline: pipeline, retried: true)
create(:ci_build, name: 'test:build', stage: stage.name, pipeline: pipeline)
end
it 'shows only latest builds' do
render
expect(rendered).to have_text 'test:build', count: 1
end
end
context 'when there are multiple builds' do
before do
Ci::HasStatus::AVAILABLE_STATUSES.each do |status|
create_build(status)
end
end
it 'shows them in order' do
render
expect(rendered).to have_text(Ci::HasStatus::ORDERED_STATUSES.join(" "))
end
def create_build(status)
create(:ci_build, name: status, status: status,
pipeline: pipeline, stage: stage.name)
end
end
end
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe Ci::InitialPipelineProcessWorker do
describe '#perform' do
let_it_be(:pipeline) { create(:ci_pipeline, :with_job, status: :created) }
include_examples 'an idempotent worker' do
let(:job_args) { pipeline.id }
it 'marks the pipeline as pending' do
expect(pipeline).to be_created
subject
expect(pipeline.reload).to be_pending
end
end
end
end
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment