提交 3d5ad15d 编写于 作者: G GitLab Bot

Add latest changes from gitlab-org/gitlab@master

上级 d2801eda
......@@ -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
---
title: Unlock button changed from Icon to String
merge_request: 20307
author:
type: changed
---
title: Enable support for multiple content query in GraphQL Todo API
merge_request: 19576
author:
type: changed
---
title: Fix style reset in job log when empty ANSI sequence is encoutered
merge_request: 20367
author:
type: fixed
......@@ -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).
......
---
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.
......@@ -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):
......
......@@ -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
......
......@@ -15,14 +15,10 @@ module Gitlab
end
def update(ansi_commands)
command = ansi_commands.shift
return unless command
if changes = Gitlab::Ci::Ansi2json::Parser.new(command, ansi_commands).changes
apply_changes(changes)
end
# treat e\[m as \e[0m
ansi_commands = ['0'] if ansi_commands.empty?
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]
......
......@@ -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'
......
......@@ -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'
......
......@@ -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
......
......@@ -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 'just uses the first state' do
todos = resolve(described_class, obj: user, args: { state: [:done, :pending] }, ctx: { current_user: user })
it 'returns the todos for multiple states' do
todos = resolve_todos({ state: [:done, :pending] })
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)
it 'returns the todos for multiple groups' do
group1 = create(:group)
group2 = create(:group)
group3 = create(:group)
group1.add_developer(current_user)
group2.add_developer(current_user)
todos = resolve(described_class, obj: user, args: { author_id: [author2.id, author1.id] }, ctx: { current_user: user })
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)
expect(todos).to contain_exactly(todo4)
todos = resolve_todos({ group_id: [group2.id, group1.id] })
expect(todos).to contain_exactly(todo4, todo5)
end
it 'just uses the first project id' do
project1 = create(:project)
project2 = create(:project)
it 'returns the todos for multiple authors' do
author3 = create(:user)
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)
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(described_class, obj: user, args: { project_id: [project2.id, project1.id] }, ctx: { current_user: user })
todos = resolve_todos({ author_id: [author2.id, author1.id] })
expect(todos).to contain_exactly(todo5)
expect(todos).to contain_exactly(todo1, todo3, todo4)
end
it 'just uses the first group id' do
group1 = create(:group)
group2 = create(:group)
it 'returns the todos for multiple actions' do
create(:todo, user: current_user, state: :pending, action: Todo::DIRECTLY_ADDRESSED, author: author1)
group1.add_developer(user)
group2.add_developer(user)
todos = resolve_todos({ action: [Todo::MENTIONED, Todo::ASSIGNED] })
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)
expect(todos).to contain_exactly(todo1, todo3)
end
todos = resolve(described_class, obj: user, args: { group_id: [group2.id, group1.id] }, ctx: { current_user: user })
it 'returns the todos for multiple projects' do
project1 = create(:project)
project2 = create(:project)
project3 = create(:project)
expect(todos).to contain_exactly(todo5)
end
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)
it 'just uses the first target' do
todos = resolve(described_class, obj: user, args: { type: %w[Issue MergeRequest] }, ctx: { current_user: user })
todos = resolve_todos({ project_id: [project2.id, project1.id] })
# Just todo3 because todo2 is in state "done"
expect(todos).to contain_exactly(todo3)
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
......
......@@ -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'],
......
......@@ -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
......
......@@ -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
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册