From 3d5ad15d2bf62ca70b1628afb64c5476e408781c Mon Sep 17 00:00:00 2001 From: GitLab Bot Date: Tue, 19 Nov 2019 21:06:22 +0000 Subject: [PATCH] Add latest changes from gitlab-org/gitlab@master --- app/graphql/resolvers/todo_resolver.rb | 50 +-------- .../unreleased/28328-lock-button-fix.yml | 5 + ...phql-todo-query-support-multiple-query.yml | 5 + .../unreleased/fix-job-log-style-reset.yml | 5 + doc/ci/environments.md | 5 + doc/ci/environments/environments_dashboard.md | 51 +++++++++ .../img/environments_dashboard_v12_5.png | Bin 0 -> 30989 bytes doc/install/requirements.md | 2 + doc/user/operations_dashboard/index.md | 2 + lib/gitlab/ci/ansi2json/style.rb | 21 ++-- .../ci_variable/add_ci_variable_spec.rb | 3 +- .../create_and_process_pipeline_spec.rb | 3 +- .../4_verify/runner/register_runner_spec.rb | 3 +- spec/graphql/resolvers/todo_resolver_spec.rb | 100 +++++++++-------- spec/lib/gitlab/ci/ansi2json/style_spec.rb | 1 + spec/lib/gitlab/email/handler_spec.rb | 2 +- .../ci/create_pipeline_service/rules_spec.rb | 105 +++++------------- 17 files changed, 182 insertions(+), 181 deletions(-) create mode 100644 changelogs/unreleased/28328-lock-button-fix.yml create mode 100644 changelogs/unreleased/31914-graphql-todo-query-support-multiple-query.yml create mode 100644 changelogs/unreleased/fix-job-log-style-reset.yml create mode 100644 doc/ci/environments/environments_dashboard.md create mode 100644 doc/ci/environments/img/environments_dashboard_v12_5.png diff --git a/app/graphql/resolvers/todo_resolver.rb b/app/graphql/resolvers/todo_resolver.rb index 38a4539f34a..cff65321dc0 100644 --- a/app/graphql/resolvers/todo_resolver.rb +++ b/app/graphql/resolvers/todo_resolver.rb @@ -38,53 +38,15 @@ module Resolvers private - # TODO: Support multiple queries for e.g. state and type on TodosFinder: - # - # https://gitlab.com/gitlab-org/gitlab/merge_requests/18487 - # https://gitlab.com/gitlab-org/gitlab/merge_requests/18518 - # - # As soon as these MR's are merged, we can refactor this to query by - # multiple contents. - # def todo_finder_params(args) { - state: first_state(args), - type: first_type(args), - group_id: first_group_id(args), - author_id: first_author_id(args), - action_id: first_action(args), - project_id: first_project(args) + state: args[:state], + type: args[:type], + group_id: args[:group_id], + author_id: args[:author_id], + action_id: args[:action], + project_id: args[:project_id] } end - - def first_project(args) - first_query_field(args, :project_id) - end - - def first_action(args) - first_query_field(args, :action) - end - - def first_author_id(args) - first_query_field(args, :author_id) - end - - def first_group_id(args) - first_query_field(args, :group_id) - end - - def first_state(args) - first_query_field(args, :state) - end - - def first_type(args) - first_query_field(args, :type) - end - - def first_query_field(query, field) - return unless query.key?(field) - - query[field].first if query[field].respond_to?(:first) - end end end diff --git a/changelogs/unreleased/28328-lock-button-fix.yml b/changelogs/unreleased/28328-lock-button-fix.yml new file mode 100644 index 00000000000..30d8aff06d1 --- /dev/null +++ b/changelogs/unreleased/28328-lock-button-fix.yml @@ -0,0 +1,5 @@ +--- +title: Unlock button changed from Icon to String +merge_request: 20307 +author: +type: changed diff --git a/changelogs/unreleased/31914-graphql-todo-query-support-multiple-query.yml b/changelogs/unreleased/31914-graphql-todo-query-support-multiple-query.yml new file mode 100644 index 00000000000..e028523da79 --- /dev/null +++ b/changelogs/unreleased/31914-graphql-todo-query-support-multiple-query.yml @@ -0,0 +1,5 @@ +--- +title: Enable support for multiple content query in GraphQL Todo API +merge_request: 19576 +author: +type: changed diff --git a/changelogs/unreleased/fix-job-log-style-reset.yml b/changelogs/unreleased/fix-job-log-style-reset.yml new file mode 100644 index 00000000000..eea41af23f6 --- /dev/null +++ b/changelogs/unreleased/fix-job-log-style-reset.yml @@ -0,0 +1,5 @@ +--- +title: Fix style reset in job log when empty ANSI sequence is encoutered +merge_request: 20367 +author: +type: fixed diff --git a/doc/ci/environments.md b/doc/ci/environments.md index 6d620722608..0f978a8f3a9 100644 --- a/doc/ci/environments.md +++ b/doc/ci/environments.md @@ -738,6 +738,11 @@ NOTE: **Note:** The most _specific_ spec takes precedence over the other wildcard matching. In this case, `review/feature-1` spec takes precedence over `review/*` and `*` specs. +### Environments Dashboard **(PREMIUM)** + +See [Environments Dashboard](environments/environments_dashboard.md) for a summary of each +environment's operational health. + ## Limitations In the `environment: name`, you are limited to only the [predefined environment variables](variables/predefined_variables.md). diff --git a/doc/ci/environments/environments_dashboard.md b/doc/ci/environments/environments_dashboard.md new file mode 100644 index 00000000000..f82728cd587 --- /dev/null +++ b/doc/ci/environments/environments_dashboard.md @@ -0,0 +1,51 @@ +--- +type: reference +--- + +# Environments Dashboard **(PREMIUM)** + +> [Introduced](https://gitlab.com/gitlab-org/gitlab/issues/3713) in [GitLab Premium](https://about.gitlab.com/pricing/) 12.5. + +The Environments Dashboard provides a cross-project +environment-based view that lets you see the big picture +of what is going on in each environment. From a single +location, you can track the progress as changes flow +from development to staging, and then to production (or +through any series of custom environment flows you can set up). +With an at-a-glance view of multiple projects, you can instantly +see which pipelines are green and which are red allowing you to +diagnose if there is a block at a particular point, or if there’s +a more systemic problem you need to investigate. + +You can access the dashboard from the top bar by clicking +**More > Environments**. + +![Environments Dashboard with projects](img/environments_dashboard_v12_5.png) + +The Environments Dashboard displays a maximum of 7 projects +and 3 environments per project. + +The listed environments for each project are unique, such as +"production", "staging", etc. Review apps and other grouped +environments are not displayed. + +## Adding a project to the dashboard + +To add a project to the dashboard: + +1. Click the **Add projects** button in the homescreen of the dashboard. +1. Search and add one or more projects using the **Search your projects** field. +1. Click the **Add projects** button. + +Once added, you can see a summary of each project's environment operational +health, including the latest commit, pipeline status, and deployment time. + +The Environments and [Operations](../../user/operations_dashboard/index.md) +dashboards share the same list of projects. When you add or remove a +project from one, GitLab adds or removes the project from the other. + +## Environment dashboards on GitLab.com + +GitLab.com users can add public projects to the Environments +Dashboard for free. If your project is private, the group it belongs +to must have a [GitLab Silver](https://about.gitlab.com/pricing/) plan. diff --git a/doc/ci/environments/img/environments_dashboard_v12_5.png b/doc/ci/environments/img/environments_dashboard_v12_5.png new file mode 100644 index 0000000000000000000000000000000000000000..e83c4fac75b35cc2fab40b855325879d2c97abd1 GIT binary patch literal 30989 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 literal 0 HcmV?d00001 diff --git a/doc/install/requirements.md b/doc/install/requirements.md index ecd6516bd2e..106c7714bfe 100644 --- a/doc/install/requirements.md +++ b/doc/install/requirements.md @@ -128,6 +128,8 @@ CREATE EXTENSION pg_trgm; On some systems you may need to install an additional package (e.g. `postgresql-contrib`) for this extension to become available. +NOTE: **Note:** Support for PostgreSQL 9.6 and 10 will be removed in GitLab 13.0 so that GitLab can benefit from PostgreSQL 11 improvements, such as partitioning. For the schedule on adding support for PostgreSQL 11 and 12, see [the related epic](https://gitlab.com/groups/gitlab-org/-/epics/2184). For the release schedule for GitLab 13.0, see [GitLab's release and maintenance policy](../policy/maintenance.md). + #### Additional requirements for GitLab Geo If you are using [GitLab Geo](../development/geo.md): diff --git a/doc/user/operations_dashboard/index.md b/doc/user/operations_dashboard/index.md index cdb80cca6f7..531422ca077 100644 --- a/doc/user/operations_dashboard/index.md +++ b/doc/user/operations_dashboard/index.md @@ -23,6 +23,8 @@ To add a project to the dashboard: Once added, the dashboard will display the project's number of active alerts, last commit, pipeline status, and when it was last deployed. +The Operations and [Environments](../../ci/environments/environments_dashboard.md) dashboards share the same list of projects. Adding or removing a project from one adds or removes the project from the other. + ![Operations Dashboard with projects](img/index_operations_dashboard_with_projects.png) ## Arranging projects on a dashboard diff --git a/lib/gitlab/ci/ansi2json/style.rb b/lib/gitlab/ci/ansi2json/style.rb index 2739ffdfa5d..77f61178b37 100644 --- a/lib/gitlab/ci/ansi2json/style.rb +++ b/lib/gitlab/ci/ansi2json/style.rb @@ -15,14 +15,10 @@ module Gitlab end def update(ansi_commands) - command = ansi_commands.shift - return unless command + # treat e\[m as \e[0m + ansi_commands = ['0'] if ansi_commands.empty? - if changes = Gitlab::Ci::Ansi2json::Parser.new(command, ansi_commands).changes - apply_changes(changes) - end - - update(ansi_commands) + evaluate_stack_command(ansi_commands) end def set? @@ -50,6 +46,17 @@ module Gitlab private + def evaluate_stack_command(ansi_commands) + command = ansi_commands.shift + return unless command + + if changes = Gitlab::Ci::Ansi2json::Parser.new(command, ansi_commands).changes + apply_changes(changes) + end + + evaluate_stack_command(ansi_commands) + end + def apply_changes(changes) case when changes[:reset] diff --git a/qa/qa/specs/features/browser_ui/4_verify/ci_variable/add_ci_variable_spec.rb b/qa/qa/specs/features/browser_ui/4_verify/ci_variable/add_ci_variable_spec.rb index b2c70547421..c813484347e 100644 --- a/qa/qa/specs/features/browser_ui/4_verify/ci_variable/add_ci_variable_spec.rb +++ b/qa/qa/specs/features/browser_ui/4_verify/ci_variable/add_ci_variable_spec.rb @@ -4,8 +4,7 @@ module QA context 'Verify' do describe 'CI variable support' do it 'user adds a CI variable', :smoke do - Runtime::Browser.visit(:gitlab, Page::Main::Login) - Page::Main::Login.perform(&:sign_in_using_credentials) + Flow::Login.sign_in project = Resource::Project.fabricate_via_api! do |project| project.name = 'project-with-ci-variables' diff --git a/qa/qa/specs/features/browser_ui/4_verify/pipeline/create_and_process_pipeline_spec.rb b/qa/qa/specs/features/browser_ui/4_verify/pipeline/create_and_process_pipeline_spec.rb index 5d91b70082c..d4853a7bcf3 100644 --- a/qa/qa/specs/features/browser_ui/4_verify/pipeline/create_and_process_pipeline_spec.rb +++ b/qa/qa/specs/features/browser_ui/4_verify/pipeline/create_and_process_pipeline_spec.rb @@ -10,8 +10,7 @@ module QA end it 'users creates a pipeline which gets processed' do - Runtime::Browser.visit(:gitlab, Page::Main::Login) - Page::Main::Login.perform(&:sign_in_using_credentials) + Flow::Login.sign_in project = Resource::Project.fabricate! do |project| project.name = 'project-with-pipelines' diff --git a/qa/qa/specs/features/browser_ui/4_verify/runner/register_runner_spec.rb b/qa/qa/specs/features/browser_ui/4_verify/runner/register_runner_spec.rb index 58f129b846d..fb1ee4446a9 100644 --- a/qa/qa/specs/features/browser_ui/4_verify/runner/register_runner_spec.rb +++ b/qa/qa/specs/features/browser_ui/4_verify/runner/register_runner_spec.rb @@ -10,8 +10,7 @@ module QA end it 'user registers a new specific runner' do - Runtime::Browser.visit(:gitlab, Page::Main::Login) - Page::Main::Login.perform(&:sign_in_using_credentials) + Flow::Login.sign_in Resource::Runner.fabricate! do |runner| runner.name = executor diff --git a/spec/graphql/resolvers/todo_resolver_spec.rb b/spec/graphql/resolvers/todo_resolver_spec.rb index fef761d7243..5a09ec40e64 100644 --- a/spec/graphql/resolvers/todo_resolver_spec.rb +++ b/spec/graphql/resolvers/todo_resolver_spec.rb @@ -7,13 +7,12 @@ describe Resolvers::TodoResolver do describe '#resolve' do let_it_be(:current_user) { create(:user) } - let_it_be(:user) { create(:user) } let_it_be(:author1) { create(:user) } let_it_be(:author2) { create(:user) } - let_it_be(:todo1) { create(:todo, user: user, target_type: 'MergeRequest', state: :pending, action: Todo::MENTIONED, author: author1) } - let_it_be(:todo2) { create(:todo, user: user, state: :done, action: Todo::ASSIGNED, author: author2) } - let_it_be(:todo3) { create(:todo, user: user, state: :pending, action: Todo::ASSIGNED, author: author1) } + let_it_be(:todo1) { create(:todo, user: current_user, target_type: 'MergeRequest', state: :pending, action: Todo::MENTIONED, author: author1) } + let_it_be(:todo2) { create(:todo, user: current_user, state: :done, action: Todo::ASSIGNED, author: author2) } + let_it_be(:todo3) { create(:todo, user: current_user, state: :pending, action: Todo::ASSIGNED, author: author1) } it 'calls TodosFinder' do expect_next_instance_of(TodosFinder) do |finder| @@ -25,68 +24,71 @@ describe Resolvers::TodoResolver do context 'when using no filter' do it 'returns expected todos' do - todos = resolve(described_class, obj: user, args: {}, ctx: { current_user: user }) - - expect(todos).to contain_exactly(todo1, todo3) + expect(resolve_todos).to contain_exactly(todo1, todo3) end end context 'when using filters' do - # TODO These can be removed as soon as we support filtering for multiple field contents for todos + it 'returns the todos for multiple states' do + todos = resolve_todos({ state: [:done, :pending] }) - it 'just uses the first state' do - todos = resolve(described_class, obj: user, args: { state: [:done, :pending] }, ctx: { current_user: user }) - - expect(todos).to contain_exactly(todo2) + expect(todos).to contain_exactly(todo1, todo2, todo3) end - it 'just uses the first action' do - todos = resolve(described_class, obj: user, args: { action: [Todo::MENTIONED, Todo::ASSIGNED] }, ctx: { current_user: user }) + it 'returns the todos for multiple types' do + todos = resolve_todos({ type: %w[Issue MergeRequest] }) - expect(todos).to contain_exactly(todo1) + expect(todos).to contain_exactly(todo1, todo3) end - it 'just uses the first author id' do - # We need a pending todo for now because of TodosFinder's state query - todo4 = create(:todo, user: user, state: :pending, action: Todo::ASSIGNED, author: author2) - - todos = resolve(described_class, obj: user, args: { author_id: [author2.id, author1.id] }, ctx: { current_user: user }) - - expect(todos).to contain_exactly(todo4) - end - - it 'just uses the first project id' do - project1 = create(:project) - project2 = create(:project) - - create(:todo, project: project1, user: user, state: :pending, action: Todo::ASSIGNED, author: author1) - todo5 = create(:todo, project: project2, user: user, state: :pending, action: Todo::ASSIGNED, author: author1) - - todos = resolve(described_class, obj: user, args: { project_id: [project2.id, project1.id] }, ctx: { current_user: user }) - - expect(todos).to contain_exactly(todo5) - end - - it 'just uses the first group id' do + it 'returns the todos for multiple groups' do group1 = create(:group) group2 = create(:group) + group3 = create(:group) - group1.add_developer(user) - group2.add_developer(user) + group1.add_developer(current_user) + group2.add_developer(current_user) - create(:todo, group: group1, user: user, state: :pending, action: Todo::ASSIGNED, author: author1) - todo5 = create(:todo, group: group2, user: user, state: :pending, action: Todo::ASSIGNED, author: author1) + todo4 = create(:todo, group: group1, user: current_user, state: :pending, action: Todo::ASSIGNED, author: author1) + todo5 = create(:todo, group: group2, user: current_user, state: :pending, action: Todo::ASSIGNED, author: author1) + create(:todo, group: group3, user: current_user, state: :pending, action: Todo::ASSIGNED, author: author1) - todos = resolve(described_class, obj: user, args: { group_id: [group2.id, group1.id] }, ctx: { current_user: user }) + todos = resolve_todos({ group_id: [group2.id, group1.id] }) - expect(todos).to contain_exactly(todo5) + expect(todos).to contain_exactly(todo4, todo5) end - it 'just uses the first target' do - todos = resolve(described_class, obj: user, args: { type: %w[Issue MergeRequest] }, ctx: { current_user: user }) + it 'returns the todos for multiple authors' do + author3 = create(:user) - # Just todo3 because todo2 is in state "done" - expect(todos).to contain_exactly(todo3) + todo4 = create(:todo, user: current_user, state: :pending, action: Todo::ASSIGNED, author: author2) + create(:todo, user: current_user, state: :pending, action: Todo::ASSIGNED, author: author3) + + todos = resolve_todos({ author_id: [author2.id, author1.id] }) + + expect(todos).to contain_exactly(todo1, todo3, todo4) + end + + it 'returns the todos for multiple actions' do + create(:todo, user: current_user, state: :pending, action: Todo::DIRECTLY_ADDRESSED, author: author1) + + todos = resolve_todos({ action: [Todo::MENTIONED, Todo::ASSIGNED] }) + + expect(todos).to contain_exactly(todo1, todo3) + end + + it 'returns the todos for multiple projects' do + project1 = create(:project) + project2 = create(:project) + project3 = create(:project) + + todo4 = create(:todo, project: project1, user: current_user, state: :pending, action: Todo::ASSIGNED, author: author1) + todo5 = create(:todo, project: project2, user: current_user, state: :pending, action: Todo::ASSIGNED, author: author1) + create(:todo, project: project3, user: current_user, state: :pending, action: Todo::ASSIGNED, author: author1) + + todos = resolve_todos({ project_id: [project2.id, project1.id] }) + + expect(todos).to contain_exactly(todo4, todo5) end end @@ -100,7 +102,9 @@ describe Resolvers::TodoResolver do context 'when provided user is not current user' do it 'returns no todos' do - todos = resolve(described_class, obj: user, args: {}, ctx: { current_user: current_user }) + other_user = create(:user) + + todos = resolve(described_class, obj: other_user, args: {}, ctx: { current_user: current_user }) expect(todos).to be_empty end diff --git a/spec/lib/gitlab/ci/ansi2json/style_spec.rb b/spec/lib/gitlab/ci/ansi2json/style_spec.rb index 88a0ca35859..5110c215415 100644 --- a/spec/lib/gitlab/ci/ansi2json/style_spec.rb +++ b/spec/lib/gitlab/ci/ansi2json/style_spec.rb @@ -143,6 +143,7 @@ describe Gitlab::Ci::Ansi2json::Style do [[], %w[106], 'term-bg-l-cyan', 'sets bg color light cyan'], [[], %w[107], 'term-bg-l-white', 'sets bg color light white'], # reset + [%w[1], %w[], '', 'resets style from format bold'], [%w[1], %w[0], '', 'resets style from format bold'], [%w[1 3], %w[0], '', 'resets style from format bold and italic'], [%w[1 3 term-fg-l-red term-bg-yellow], %w[0], '', 'resets all formats and colors'], diff --git a/spec/lib/gitlab/email/handler_spec.rb b/spec/lib/gitlab/email/handler_spec.rb index d2920b08956..5229b778ccf 100644 --- a/spec/lib/gitlab/email/handler_spec.rb +++ b/spec/lib/gitlab/email/handler_spec.rb @@ -4,7 +4,7 @@ require 'spec_helper' describe Gitlab::Email::Handler do describe '.for' do - it 'picks issue handler if there is not merge request prefix' do + it 'picks issue handler if there is no merge request prefix' do expect(described_class.for('email', 'project+key')).to be_an_instance_of(Gitlab::Email::Handler::CreateIssueHandler) end diff --git a/spec/services/ci/create_pipeline_service/rules_spec.rb b/spec/services/ci/create_pipeline_service/rules_spec.rb index c922266647b..2c93007f8e8 100644 --- a/spec/services/ci/create_pipeline_service/rules_spec.rb +++ b/spec/services/ci/create_pipeline_service/rules_spec.rb @@ -114,48 +114,36 @@ describe Ci::CreatePipelineService do end context 'matching the first rule in the list' do - it 'saves the pipeline' do - expect(pipeline).to be_persisted - end - - it 'sets the pipeline state to pending' do + it 'saves a pending pipeline' do expect(pipeline).to be_pending + expect(pipeline).to be_persisted end end context 'matching the last rule in the list' do let(:ref) { 'refs/heads/feature' } - it 'saves the pipeline' do - expect(pipeline).to be_persisted - end - - it 'sets the pipeline state to pending' do + it 'saves a pending pipeline' do expect(pipeline).to be_pending + expect(pipeline).to be_persisted end end context 'matching the when:never rule' do let(:ref) { 'refs/heads/wip' } - it 'does not save the pipeline' do - expect(pipeline).not_to be_persisted - end - - it 'attaches errors' do + it 'invalidates the pipeline with a workflow rules error' do expect(pipeline.errors[:base]).to include('Pipeline filtered out by workflow rules.') + expect(pipeline).not_to be_persisted end end context 'matching no rules in the list' do let(:ref) { 'refs/heads/fix' } - it 'does not save the pipeline' do - expect(pipeline).not_to be_persisted - end - - it 'attaches errors' do + it 'invalidates the pipeline with a workflow rules error' do expect(pipeline.errors[:base]).to include('Pipeline filtered out by workflow rules.') + expect(pipeline).not_to be_persisted end end end @@ -176,12 +164,9 @@ describe Ci::CreatePipelineService do end context 'matching the first rule in the list' do - it 'saves the pipeline' do - expect(pipeline).to be_persisted - end - - it 'sets the pipeline state to pending' do + it 'saves a pending pipeline' do expect(pipeline).to be_pending + expect(pipeline).to be_persisted end end end @@ -204,24 +189,18 @@ describe Ci::CreatePipelineService do context 'with partial match' do let(:ref) { 'refs/heads/feature' } - it 'saves the pipeline' do - expect(pipeline).to be_persisted - end - - it 'sets the pipeline state to pending' do + it 'saves a pending pipeline' do expect(pipeline).to be_pending + expect(pipeline).to be_persisted end end context 'with complete match' do let(:ref) { 'refs/heads/feature_conflict' } - it 'does not save the pipeline' do - expect(pipeline).not_to be_persisted - end - - it 'attaches errors' do + it 'invalidates the pipeline with a workflow rules error' do expect(pipeline.errors[:base]).to include('Pipeline filtered out by workflow rules.') + expect(pipeline).not_to be_persisted end end end @@ -245,12 +224,9 @@ describe Ci::CreatePipelineService do context 'where workflow passes and the job fails' do let(:ref) { 'refs/heads/master' } - it 'does not save the pipeline' do - expect(pipeline).not_to be_persisted - end - - it 'attaches an error about no job in the pipeline' do + it 'invalidates the pipeline with an empty jobs error' do expect(pipeline.errors[:base]).to include('No stages / jobs for this pipeline.') + expect(pipeline).not_to be_persisted end context 'with workflow:rules shut off' do @@ -258,12 +234,9 @@ describe Ci::CreatePipelineService do stub_feature_flags(workflow_rules: false) end - it 'does not save the pipeline' do - expect(pipeline).not_to be_persisted - end - - it 'attaches an error about no job in the pipeline' do + it 'invalidates the pipeline with an empty jobs error' do expect(pipeline.errors[:base]).to include('No stages / jobs for this pipeline.') + expect(pipeline).not_to be_persisted end end end @@ -271,12 +244,9 @@ describe Ci::CreatePipelineService do context 'where workflow passes and the job passes' do let(:ref) { 'refs/heads/feature' } - it 'saves the pipeline' do - expect(pipeline).to be_persisted - end - - it 'sets the pipeline state to pending' do + it 'saves a pending pipeline' do expect(pipeline).to be_pending + expect(pipeline).to be_persisted end context 'with workflow:rules shut off' do @@ -284,12 +254,9 @@ describe Ci::CreatePipelineService do stub_feature_flags(workflow_rules: false) end - it 'saves the pipeline' do - expect(pipeline).to be_persisted - end - - it 'sets the pipeline state to pending' do + it 'saves a pending pipeline' do expect(pipeline).to be_pending + expect(pipeline).to be_persisted end end end @@ -297,12 +264,9 @@ describe Ci::CreatePipelineService do context 'where workflow fails and the job fails' do let(:ref) { 'refs/heads/fix' } - it 'does not save the pipeline' do - expect(pipeline).not_to be_persisted - end - - it 'attaches an error about workflow rules' do + it 'invalidates the pipeline with a workflow rules error' do expect(pipeline.errors[:base]).to include('Pipeline filtered out by workflow rules.') + expect(pipeline).not_to be_persisted end context 'with workflow:rules shut off' do @@ -310,12 +274,9 @@ describe Ci::CreatePipelineService do stub_feature_flags(workflow_rules: false) end - it 'does not save the pipeline' do - expect(pipeline).not_to be_persisted - end - - it 'attaches an error about job rules' do + it 'invalidates the pipeline with an empty jobs error' do expect(pipeline.errors[:base]).to include('No stages / jobs for this pipeline.') + expect(pipeline).not_to be_persisted end end end @@ -323,12 +284,9 @@ describe Ci::CreatePipelineService do context 'where workflow fails and the job passes' do let(:ref) { 'refs/heads/wip' } - it 'does not save the pipeline' do - expect(pipeline).not_to be_persisted - end - - it 'attaches an error about workflow rules' do + it 'invalidates the pipeline with a workflow rules error' do expect(pipeline.errors[:base]).to include('Pipeline filtered out by workflow rules.') + expect(pipeline).not_to be_persisted end context 'with workflow:rules shut off' do @@ -336,12 +294,9 @@ describe Ci::CreatePipelineService do stub_feature_flags(workflow_rules: false) end - it 'saves the pipeline' do - expect(pipeline).to be_persisted - end - - it 'sets the pipeline state to pending' do + it 'saves a pending pipeline' do expect(pipeline).to be_pending + expect(pipeline).to be_persisted end end end