Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2022-09-29 00:09:11 +00:00
parent fcfe959a5d
commit 0914eb1a9c
32 changed files with 373 additions and 69 deletions

View File

@ -1,9 +1,10 @@
workhorse:verify:
extends: .workhorse:rules:workhorse
image: ${GITLAB_DEPENDENCY_PROXY}golang:1.18
image: ${GITLAB_DEPENDENCY_PROXY}golang:${GO_VERSION}
stage: test
needs: []
script:
- go version
- make -C workhorse # test build
- make -C workhorse verify
@ -12,7 +13,6 @@ workhorse:verify:
image: ${REGISTRY_HOST}/${REGISTRY_GROUP}/gitlab-build-images/debian-${DEBIAN_VERSION}-ruby-${RUBY_VERSION}-golang-${GO_VERSION}:git-2.36
variables:
GITALY_ADDRESS: "tcp://127.0.0.1:8075"
GO_VERSION: "1.18"
stage: test
needs:
- setup-test-env
@ -27,7 +27,7 @@ workhorse:test go:
extends: .workhorse:test
parallel:
matrix:
- GO_VERSION: ["1.17", "1.18"]
- GO_VERSION: ["1.17", "1.18", "1.19"]
script:
- make -C workhorse test-coverage
coverage: '/\d+.\d+%/'

View File

@ -357,7 +357,7 @@ group :development do
gem 'solargraph', '~> 0.46.0', require: false
gem 'letter_opener_web', '~> 2.0.0'
gem 'lookbook', '~> 1.0'
gem 'lookbook', '~> 1.0', '>= 1.0.8'
# Better errors handler
gem 'better_errors', '~> 2.9.1'

View File

@ -14,7 +14,7 @@
{"name":"activestorage","version":"6.1.6.1","platform":"ruby","checksum":"3fbf4c355a69a46e14676004ad8e06245bdce7f96858e72782715218326aafc5"},
{"name":"activesupport","version":"6.1.6.1","platform":"ruby","checksum":"5fc9fd6fe6f755e7523bb3aaf4370fb91a8416b39e3202939fd8bded4fec606d"},
{"name":"acts-as-taggable-on","version":"9.0.0","platform":"ruby","checksum":"5a409be0eae125b7b02c1a7316264b40d4a583584a13d4ea4a6d82acdb351b86"},
{"name":"addressable","version":"2.8.0","platform":"ruby","checksum":"f76d29d2d1f54b6c6a49aec58f9583b08d97e088c227a3fcba92f6c6531d5908"},
{"name":"addressable","version":"2.8.1","platform":"ruby","checksum":"bc724a176ef02118c8a3ed6b5c04c39cf59209607ffcce77b91d0261dbadedfa"},
{"name":"aes_key_wrap","version":"1.1.0","platform":"ruby","checksum":"b935f4756b37375895db45669e79dfcdc0f7901e12d4e08974d5540c8e0776a5"},
{"name":"akismet","version":"3.0.0","platform":"ruby","checksum":"74991b8e3d3257eeea996b47069abb8da2006c84a144255123e8dffd1c86b230"},
{"name":"android_key_attestation","version":"0.3.0","platform":"ruby","checksum":"467eb01a99d2bb48ef9cf24cc13712669d7056cba5a52d009554ff037560570b"},
@ -90,7 +90,7 @@
{"name":"crass","version":"1.0.6","platform":"ruby","checksum":"dc516022a56e7b3b156099abc81b6d2b08ea1ed12676ac7a5657617f012bd45d"},
{"name":"creole","version":"0.5.0","platform":"ruby","checksum":"951701e2d80760f156b1cb2a93471ca97c076289becc067a33b745133ed32c03"},
{"name":"crystalball","version":"0.7.0","platform":"ruby","checksum":"6e729f372a5071daec877adb40c5df4cb25fe21f350635e2a9624373fc151ef2"},
{"name":"css_parser","version":"1.11.0","platform":"ruby","checksum":"568926c3193579446ad3e3f9d761c73e2918ee5b3b7757a1a49ec166c67d6de1"},
{"name":"css_parser","version":"1.12.0","platform":"ruby","checksum":"8b7c04bca32257da0c65bd7b1fa585df5a0fd9f5197ccd78498d5598dd900784"},
{"name":"cvss-suite","version":"3.0.1","platform":"ruby","checksum":"b5ca9e9e94032a42fd0dc28c1e305378b62c949e35ed7111fc4a1d76f68ad3f9"},
{"name":"danger","version":"8.6.1","platform":"ruby","checksum":"d95eb58b41f68d3aaa9bbef697916b6b4d161a38819517c98562531be75cdfd8"},
{"name":"danger-gitlab","version":"8.0.0","platform":"ruby","checksum":"497dd7d0f6513913de651019223d8058cf494df10acbd17de92b175dfa04a3a8"},
@ -309,7 +309,7 @@
{"name":"lockbox","version":"0.6.2","platform":"ruby","checksum":"0136677875c3d6e27cef87cd7bd66610404e2b3cd7f07f1ac8ed34e48f18dc3c"},
{"name":"lograge","version":"0.11.2","platform":"ruby","checksum":"4cbd1554b86f545d795eff15a0c24fd25057d2ac4e1caa5fc186168b3da932ef"},
{"name":"loofah","version":"2.19.0","platform":"ruby","checksum":"302791371f473611e342f9e469e7f2fbf1155bb1b3a978a83ac7df625298feba"},
{"name":"lookbook","version":"1.0.3","platform":"ruby","checksum":"c53e130a37588e32f66be3b9418b1efcb51bef69946b276edd3b4348a71cbcd6"},
{"name":"lookbook","version":"1.0.8","platform":"ruby","checksum":"e4b8789c5ff25c6443394da1d6b62966642c324e19c42d7f4cf3b5da2fe75f77"},
{"name":"lru_redux","version":"1.1.0","platform":"ruby","checksum":"ee71d0ccab164c51de146c27b480a68b3631d5b4297b8ffe8eda1c72de87affb"},
{"name":"lumberjack","version":"1.2.7","platform":"ruby","checksum":"a5c6aae6b4234f1420dbcd80b23e3bca0817bd239440dde097ebe3fa63c63b1f"},
{"name":"mail","version":"2.7.1","platform":"ruby","checksum":"ec2a3d489f7510b90d8eaa3f6abaad7038cf1d663cdf8ee66d0214a0bdf99c03"},
@ -418,7 +418,7 @@
{"name":"pry-byebug","version":"3.9.0","platform":"ruby","checksum":"3bba08f97fea15b89cc299f3b5136e3b85763cd18cf84960eac4fbfbeb2ede24"},
{"name":"pry-rails","version":"0.3.9","platform":"ruby","checksum":"468662575abb6b67f4a9831219f99290d5eae7bf186e64dd810d0a3e4a8cc4b1"},
{"name":"pry-shell","version":"0.5.1","platform":"ruby","checksum":"2b9000e30677acf5d66f55fa53d31934b7c069d9e0f738a0b84eed03a4ab677d"},
{"name":"public_suffix","version":"4.0.7","platform":"ruby","checksum":"8be161e2421f8d45b0098c042c06486789731ea93dc3a896d30554ee38b573b8"},
{"name":"public_suffix","version":"5.0.0","platform":"ruby","checksum":"26ee4fbce33ada25eb117ac71f2c24bf4d8b3414ab6b34f05b4708a3e90f1c6b"},
{"name":"puma","version":"5.6.5","platform":"java","checksum":"29d78fc2bc070b9db285a3334a890c3e0ece9bb369388065f0f340ccb1e57faf"},
{"name":"puma","version":"5.6.5","platform":"ruby","checksum":"661029d15a115e9f6c0641a69c830ffd9f1b9ac63fcd0791d94ccd900e03f863"},
{"name":"puma_worker_killer","version":"0.3.1","platform":"ruby","checksum":"9c5534d296b5e92d1ad4a578f2daf2aa71563003c84f7263f0a8dfd22b5c614a"},

View File

@ -155,8 +155,8 @@ GEM
zeitwerk (~> 2.3)
acts-as-taggable-on (9.0.0)
activerecord (>= 6.0, < 7.1)
addressable (2.8.0)
public_suffix (>= 2.0.2, < 5.0)
addressable (2.8.1)
public_suffix (>= 2.0.2, < 6.0)
aes_key_wrap (1.1.0)
akismet (3.0.0)
android_key_attestation (0.3.0)
@ -301,7 +301,7 @@ GEM
creole (0.5.0)
crystalball (0.7.0)
git
css_parser (1.11.0)
css_parser (1.12.0)
addressable
cvss-suite (3.0.1)
danger (8.6.1)
@ -830,7 +830,7 @@ GEM
loofah (2.19.0)
crass (~> 1.0.2)
nokogiri (>= 1.5.9)
lookbook (1.0.3)
lookbook (1.0.8)
actioncable
css_parser
htmlbeautifier (~> 1.3)
@ -1048,7 +1048,7 @@ GEM
pry (~> 0.13.0)
tty-markdown
tty-prompt
public_suffix (4.0.7)
public_suffix (5.0.0)
puma (5.6.5)
nio4r (~> 2.0)
puma_worker_killer (0.3.1)
@ -1671,7 +1671,7 @@ DEPENDENCIES
lockbox (~> 0.6.2)
lograge (~> 0.5)
loofah (~> 2.19.0)
lookbook (~> 1.0)
lookbook (~> 1.0, >= 1.0.8)
lru_redux
mail (= 2.7.1)
mail-smtp_pool (~> 0.1.0)!
@ -1817,4 +1817,4 @@ DEPENDENCIES
yajl-ruby (~> 1.4.3)
BUNDLED WITH
2.3.15
2.3.22

View File

@ -1,3 +1,8 @@
import initPipelineSchedulesFormApp from '~/pipeline_schedules/mount_pipeline_schedules_form_app';
import initForm from '../shared/init_form';
initForm();
if (gon.features?.pipelineSchedulesVue) {
initPipelineSchedulesFormApp('#pipeline-schedules-form-edit');
} else {
initForm();
}

View File

@ -1,9 +1,10 @@
import Vue from 'vue';
import { BV_SHOW_MODAL } from '~/lib/utils/constants';
import initPipelineSchedulesApp from '~/pipeline_schedules/mount_pipeline_schedules_app';
import PipelineSchedulesTakeOwnershipModal from '~/pipeline_schedules/components/take_ownership_modal.vue';
import PipelineSchedulesCallout from '../shared/components/pipeline_schedules_callout.vue';
function initPipelineSchedules() {
function initPipelineSchedulesCallout() {
const el = document.getElementById('pipeline-schedules-callout');
if (!el) {
@ -15,6 +16,7 @@ function initPipelineSchedules() {
// eslint-disable-next-line no-new
new Vue({
el,
name: 'PipelineSchedulesCalloutRoot',
provide: {
docsUrl,
illustrationUrl,
@ -25,6 +27,8 @@ function initPipelineSchedules() {
});
}
// TODO: move take ownership feature into new Vue app
// located in directory app/assets/javascripts/pipeline_schedules/components
function initTakeownershipModal() {
const modalId = 'pipeline-take-ownership-modal';
const buttonSelector = 'js-take-ownership-button';
@ -63,5 +67,10 @@ function initTakeownershipModal() {
});
}
initPipelineSchedules();
initTakeownershipModal();
initPipelineSchedulesCallout();
if (gon.features?.pipelineSchedulesVue) {
initPipelineSchedulesApp();
} else {
initTakeownershipModal();
}

View File

@ -1,3 +1,8 @@
import initPipelineSchedulesFormApp from '~/pipeline_schedules/mount_pipeline_schedules_form_app';
import initForm from '../shared/init_form';
initForm();
if (gon.features?.pipelineSchedulesVue) {
initPipelineSchedulesFormApp('#pipeline-schedules-form-new');
} else {
initForm();
}

View File

@ -0,0 +1,20 @@
<script>
import PipelineSchedulesTable from './table/pipeline_schedules_table.vue';
export default {
components: {
PipelineSchedulesTable,
},
inject: {
fullPath: {
default: '',
},
},
};
</script>
<template>
<div>
<pipeline-schedules-table />
</div>
</template>

View File

@ -0,0 +1,18 @@
<script>
import { GlForm } from '@gitlab/ui';
export default {
components: {
GlForm,
},
inject: {
fullPath: {
default: '',
},
},
};
</script>
<template>
<gl-form />
</template>

View File

@ -0,0 +1,13 @@
<script>
import { GlTableLite } from '@gitlab/ui';
export default {
components: {
GlTableLite,
},
};
</script>
<template>
<gl-table-lite />
</template>

View File

@ -0,0 +1,32 @@
import Vue from 'vue';
import VueApollo from 'vue-apollo';
import createDefaultClient from '~/lib/graphql';
import PipelineSchedules from './components/pipeline_schedules.vue';
Vue.use(VueApollo);
const apolloProvider = new VueApollo({
defaultClient: createDefaultClient(),
});
export default () => {
const containerEl = document.querySelector('#pipeline-schedules-app');
if (!containerEl) {
return false;
}
const { fullPath } = containerEl.dataset;
return new Vue({
el: containerEl,
name: 'PipelineSchedulesRoot',
apolloProvider,
provide: {
fullPath,
},
render(createElement) {
return createElement(PipelineSchedules);
},
});
};

View File

@ -0,0 +1,32 @@
import Vue from 'vue';
import VueApollo from 'vue-apollo';
import createDefaultClient from '~/lib/graphql';
import PipelineSchedulesForm from './components/pipeline_schedules_form.vue';
Vue.use(VueApollo);
const apolloProvider = new VueApollo({
defaultClient: createDefaultClient(),
});
export default (selector) => {
const containerEl = document.querySelector(selector);
if (!containerEl) {
return false;
}
const { fullPath } = containerEl.dataset;
return new Vue({
el: containerEl,
name: 'PipelineSchedulesFormRoot',
apolloProvider,
provide: {
fullPath,
},
render(createElement) {
return createElement(PipelineSchedulesForm);
},
});
};

View File

@ -10,6 +10,7 @@ class Projects::PipelineSchedulesController < Projects::ApplicationController
before_action :authorize_update_pipeline_schedule!, only: [:edit, :update]
before_action :authorize_take_ownership_pipeline_schedule!, only: [:take_ownership]
before_action :authorize_admin_pipeline_schedule!, only: [:destroy]
before_action :push_schedule_feature_flag, only: [:index, :new, :edit]
feature_category :continuous_integration
urgency :low
@ -115,4 +116,8 @@ class Projects::PipelineSchedulesController < Projects::ApplicationController
def authorize_admin_pipeline_schedule!
return access_denied! unless can?(current_user, :admin_pipeline_schedule, schedule)
end
def push_schedule_feature_flag
push_frontend_feature_flag(:pipeline_schedules_vue, @project)
end
end

View File

@ -5,8 +5,6 @@ module Integrations
extend ActiveSupport::Concern
included do
# TODO: Once we rename the tables we can't rely on `table_name` anymore.
# https://gitlab.com/gitlab-org/gitlab/-/issues/331953
belongs_to :integration, inverse_of: self.table_name.to_sym, foreign_key: :integration_id
validates :integration, presence: true

View File

@ -7,4 +7,7 @@
= _("Edit Pipeline Schedule")
%hr
= render "form"
- if Feature.enabled?(:pipeline_schedules_vue, @project)
#pipeline-schedules-form-edit{ data: { full_path: @project.full_path } }
- else
= render "form"

View File

@ -3,21 +3,25 @@
- add_page_specific_style 'page_bundles/pipeline_schedules'
#pipeline-schedules-callout{ data: { docs_url: help_page_path('ci/pipelines/schedules'), illustration_url: image_path('illustrations/pipeline_schedule_callout.svg') } }
.top-area
- schedule_path_proc = ->(scope) { pipeline_schedules_path(@project, scope: scope) }
= render "tabs", schedule_path_proc: schedule_path_proc, all_schedules: @all_schedules, scope: @scope
- if can?(current_user, :create_pipeline_schedule, @project)
.nav-controls
= link_to new_project_pipeline_schedule_path(@project), class: 'btn gl-button btn-confirm' do
%span= _('New schedule')
- if @schedules.present?
%ul.content-list
= render partial: "table"
- if Feature.enabled?(:pipeline_schedules_vue, @project)
#pipeline-schedules-app{ data: { full_path: @project.full_path } }
- else
= render Pajamas::CardComponent.new(card_options: { class: 'bg-light gl-mt-3 gl-text-center' }) do |c|
- c.body do
= _("No schedules")
.top-area
- schedule_path_proc = ->(scope) { pipeline_schedules_path(@project, scope: scope) }
= render "tabs", schedule_path_proc: schedule_path_proc, all_schedules: @all_schedules, scope: @scope
#pipeline-take-ownership-modal
- if can?(current_user, :create_pipeline_schedule, @project)
.nav-controls
= link_to new_project_pipeline_schedule_path(@project), class: 'btn gl-button btn-confirm' do
%span= _('New schedule')
- if @schedules.present?
%ul.content-list
= render partial: "table"
- else
= render Pajamas::CardComponent.new(card_options: { class: 'bg-light gl-mt-3 gl-text-center' }) do |c|
- c.body do
= _("No schedules")
#pipeline-take-ownership-modal

View File

@ -8,4 +8,7 @@
%h1.page-title.gl-font-size-h-display
= _("Schedule a new pipeline")
= render "form"
- if Feature.enabled?(:pipeline_schedules_vue, @project)
#pipeline-schedules-form-new{ data: { full_path: @project.full_path } }
- else
= render "form"

View File

@ -0,0 +1,8 @@
---
name: pipeline_schedules_vue
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/99155
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/375139
milestone: '15.5'
type: development
group: group::pipeline execution
default_enabled: false

View File

@ -0,0 +1,17 @@
# frozen_string_literal: true
class RemoveIndexForRequestedNonInvitedAwaitingMembers < Gitlab::Database::Migration[2.0]
INDEX_NAME = 'index_members_on_non_requested_non_invited_and_state_awaiting'
disable_ddl_transaction!
def up
remove_concurrent_index_by_name :members, INDEX_NAME
end
def down
clause = '((requested_at IS NULL) AND (invite_token IS NULL) AND (access_level > 5) AND (state = 1))'
add_concurrent_index :members, :source_id, where: clause, name: INDEX_NAME
end
end

View File

@ -0,0 +1 @@
e1106d4b77704a1ac4c185e0a6b500966dc61f46569de55650875aa6a89b7f9d

View File

@ -29229,8 +29229,6 @@ CREATE INDEX index_members_on_member_namespace_id ON members USING btree (member
CREATE INDEX index_members_on_member_role_id ON members USING btree (member_role_id);
CREATE INDEX index_members_on_non_requested_non_invited_and_state_awaiting ON members USING btree (source_id) WHERE ((requested_at IS NULL) AND (invite_token IS NULL) AND (access_level > 5) AND (state = 1));
CREATE INDEX index_members_on_requested_at ON members USING btree (requested_at);
CREATE INDEX index_members_on_source_id_and_source_type ON members USING btree (source_id, source_type);

View File

@ -135,40 +135,70 @@ API endpoints have the same abstraction level as controllers.
Everything that resides in `app/services`.
Services should consider inheriting from:
Service classes represent operations that coordinates changes between models
(such as entities and value objects). Changes impact the state of the application.
- `BaseContainerService` for services scoped by container (project or group)
- `BaseProjectService` for services scoped to projects
- `BaseGroupService` for services scoped to groups
1. When an object makes no changes to the state of the application, then it's not a service.
It may be a [finder](#finders) or a value object.
1. When there is no operation, there is no need to execute a service. The class would
probably be better designed as an entity, a value object, or a policy.
or, create a new base class and update the list above.
When implementing a service class, consider:
Legacy classes inherited from `BaseService` for historical reasons.
1. A service class initializer should contain in its arguments:
1. A [model](#models) instance that is being acted upon. Should be first positional
argument of the initializer. The argument name of the argument is left to the
developer's discretion, such as: `issue`, `project`, `merge_request`.
1. When service represents an action initiated by a user or executed in the
context of a user, the initializer must have the `current_user:` keyword argument.
Services with `current_user:` argument run high-level business logic.
1. When service does not have a user context and it's not directly initiated
by a user (like background service or side-effects), the `current_user:`
argument is not needed. This describes low-level domain logic or instance-wide logic.
1. For all additional data required by a service, the explicit keyword arguments are recommended.
When a service requires too long of a list of arguments, consider splitting them into:
- `params`: A hash with model properties that will be assigned directly.
- `options`: A hash with extra parameters (which need to be processed,
and are not model properties). The `options` hash should be stored in an instance variable.
In Service classes the use of `execute` and `#execute` is preferred over `call` and `#call`.
```ruby
# merge_request: A model instance that is being acted upon.
# assignee: new MR assignee that will be assigned to the MR
# after the service is executed.
def initialize(merge_request, assignee:)
@merge_request = merge_request
@assignee = assignee
end
```
Model properties should be passed to the constructor in a `params` hash, and will be assigned directly.
```ruby
# issue: A model instance that is being acted upon.
# current_user: Current user.
# params: Model properties.
# options: Configuration for this service. Can be any of the following:
# - notify: Whether to send a notification to the current user.
# - cc: Email address to copy when sending a notification.
def initialize(issue:, current_user:, params: {}, options: {})
@issue = issue
@current_user = current_user
@params = params
@options = options
end
```
To pass extra parameters (which need to be processed, and are not model properties),
include an `options` hash in the constructor and store it in an instance variable:
1. It implements a single public instance method `#execute`, which invokes service class behavior:
- The `#execute` method takes no arguments. All required data is passed into initializer.
- Optional. If needed, the `#execute` method returns its result via [`ServiceResponse`](#serviceresponse).
```ruby
# container: Project, or Group
# current_user: Current user
# params: Model properties from the controller, already allowlisted with strong parameters
# options: Configuration for this service, can be any of the following:
# notify: Whether to send a notifcation to the current user
# cc: Email address to copy when sending a notification
def initialize(container:, current_user: nil, params: {}, options: {})
super(container, current_user, params)
@options = options
end
```
Several base classes implement the service classes convention. You may consider inheriting from:
View the [initial discussion](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/90008#note_988744060)
and [further discussion](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/90853#note_1053425083).
- `BaseContainerService` for services scoped by container (project or group).
- `BaseProjectService` for services scoped to projects.
- `BaseGroupService` for services scoped to groups.
Classes that are not service objects should be [created elsewhere](directory_structure.md#use-namespaces-to-define-bounded-contexts), such as in `lib`.
Classes that are not service objects should be
[created elsewhere](directory_structure.md#use-namespaces-to-define-bounded-contexts),
such as in `lib`.
#### ServiceResponse

View File

@ -10,6 +10,9 @@ disqus_identifier: 'https://docs.gitlab.com/ee/gitlab-basics/add-merge-request.h
There are many different ways to create a merge request.
NOTE:
Use [branch naming patterns](../repository/branches/index.md#naming) to streamline merge request creation.
## From the merge request list
You can create a merge request from the list of merge requests.

View File

@ -13,9 +13,10 @@ other.
After pushing your changes to a new branch, you can:
- Create a [merge request](../../merge_requests/index.md)
- Perform inline code review
- [Discuss](../../../discussions/index.md) your implementation with your team
- Create a [merge request](../../merge_requests/index.md). You can streamline this process
by following [branch naming patterns](#naming).
- Perform inline code review.
- [Discuss](../../../discussions/index.md) your implementation with your team.
- Preview changes submitted to a new branch with [Review Apps](../../../../ci/review_apps/index.md).
You can also request [approval](../../merge_requests/approvals/index.md)
@ -42,6 +43,18 @@ See also:
- [GitLab Flow](../../../../topics/gitlab_flow.md) documentation.
- [Getting started with Git](../../../../topics/git/index.md) and GitLab.
## Naming
Prefix a branch name with an issue number to streamline merge request creation.
When you create a merge request for a branch with a name beginning with an issue
number, GitLab:
- Marks the issue as related. If your project is configured with a
[default closing pattern](../../issues/managing_issues.md#default-closing-pattern),
merging this merge request [also closes](../../issues/managing_issues.md#closing-issues-automatically)
the related issue.
- Copies label and milestone metadata from the issue.
## Compare
To compare branches in a repository:

View File

@ -115,6 +115,9 @@ the target branch. Select **Create directory** to finish.
There are multiple ways to create a branch from the GitLab web interface.
NOTE:
Use [branch naming patterns](branches/index.md#naming) to streamline merge request creation.
### Create a new branch from an issue
> The **Create merge request** button [changed](https://gitlab.com/gitlab-org/gitlab/-/issues/349566) to open the merge request creation form in GitLab 14.8.

View File

@ -11,6 +11,10 @@ RSpec.describe 'Pipeline Schedules', :js do
let(:scope) { nil }
let!(:user) { create(:user) }
before do
stub_feature_flags(pipeline_schedules_vue: false)
end
context 'logged in as the pipeline schedule owner' do
before do
project.add_developer(user)

View File

@ -735,6 +735,8 @@ RSpec.describe 'Pipeline', :js do
end
it 'displays the PipelineSchedule in an inactive state' do
stub_feature_flags(pipeline_schedules_vue: false)
visit project_pipeline_schedules_path(project)
page.click_link('Inactive')

View File

@ -860,6 +860,8 @@ RSpec.describe 'Pipeline', :js do
end
it 'displays the PipelineSchedule in an inactive state' do
stub_feature_flags(pipeline_schedules_vue: false)
visit project_pipeline_schedules_path(project)
page.click_link('Inactive')

View File

@ -17,6 +17,7 @@ RSpec.describe Projects::PipelineSchedulesController, '(JavaScript fixtures)', t
before do
sign_in(user)
stub_feature_flags(pipeline_schedules_vue: false)
end
it 'pipeline_schedules/edit.html' do

View File

@ -0,0 +1,25 @@
import { shallowMount } from '@vue/test-utils';
import { GlForm } from '@gitlab/ui';
import PipelineSchedulesForm from '~/pipeline_schedules/components/pipeline_schedules_form.vue';
describe('Pipeline schedules form', () => {
let wrapper;
const createComponent = () => {
wrapper = shallowMount(PipelineSchedulesForm);
};
const findForm = () => wrapper.findComponent(GlForm);
beforeEach(() => {
createComponent();
});
afterEach(() => {
wrapper.destroy();
});
it('displays form', () => {
expect(findForm().exists()).toBe(true);
});
});

View File

@ -0,0 +1,25 @@
import { shallowMount } from '@vue/test-utils';
import PipelineSchedules from '~/pipeline_schedules/components/pipeline_schedules.vue';
import PipelineSchedulesTable from '~/pipeline_schedules/components/table/pipeline_schedules_table.vue';
describe('Pipeline schedules app', () => {
let wrapper;
const createComponent = () => {
wrapper = shallowMount(PipelineSchedules);
};
const findTable = () => wrapper.findComponent(PipelineSchedulesTable);
beforeEach(() => {
createComponent();
});
afterEach(() => {
wrapper.destroy();
});
it('displays table', () => {
expect(findTable().exists()).toBe(true);
});
});

View File

@ -0,0 +1,25 @@
import { shallowMount } from '@vue/test-utils';
import { GlTableLite } from '@gitlab/ui';
import PipelineSchedulesTable from '~/pipeline_schedules/components/table/pipeline_schedules_table.vue';
describe('Pipeline schedules table', () => {
let wrapper;
const createComponent = () => {
wrapper = shallowMount(PipelineSchedulesTable);
};
const findTable = () => wrapper.findComponent(GlTableLite);
beforeEach(() => {
createComponent();
});
afterEach(() => {
wrapper.destroy();
});
it('displays table', () => {
expect(findTable().exists()).toBe(true);
});
});