Commit 4d5b521e authored by Mike Greiling's avatar Mike Greiling

Merge branch 'app-label-warning' into 'master'

[EE] App label warning for deploy boards

See merge request gitlab-org/gitlab-ee!14103
parents 0c1e8060 a8b2fb45
...@@ -9,16 +9,17 @@ ...@@ -9,16 +9,17 @@
* [Mockup](https://gitlab.com/gitlab-org/gitlab-ce/uploads/2f655655c0eadf655d0ae7467b53002a/environments__deploy-graphic.png) * [Mockup](https://gitlab.com/gitlab-org/gitlab-ce/uploads/2f655655c0eadf655d0ae7467b53002a/environments__deploy-graphic.png)
*/ */
import _ from 'underscore'; import _ from 'underscore';
import { n__ } from '~/locale'; import { n__, s__, sprintf } from '~/locale';
import tooltip from '~/vue_shared/directives/tooltip'; import tooltip from '~/vue_shared/directives/tooltip';
import deployBoardSvg from 'ee_empty_states/icons/_deploy_board.svg'; import deployBoardSvg from 'ee_empty_states/icons/_deploy_board.svg';
import { GlLoadingIcon } from '@gitlab/ui'; import { GlLoadingIcon, GlLink } from '@gitlab/ui';
import instanceComponent from './deploy_board_instance_component.vue'; import instanceComponent from './deploy_board_instance_component.vue';
export default { export default {
components: { components: {
instanceComponent, instanceComponent,
GlLoadingIcon, GlLoadingIcon,
GlLink,
}, },
directives: { directives: {
tooltip, tooltip,
...@@ -28,6 +29,11 @@ export default { ...@@ -28,6 +29,11 @@ export default {
type: Object, type: Object,
required: true, required: true,
}, },
deployBoardsHelpPath: {
type: String,
required: false,
default: '',
},
isLoading: { isLoading: {
type: Boolean, type: Boolean,
required: true, required: true,
...@@ -41,13 +47,29 @@ export default { ...@@ -41,13 +47,29 @@ export default {
required: false, required: false,
default: '', default: '',
}, },
hasLegacyAppLabel: {
type: Boolean,
required: false,
default: false,
},
}, },
computed: { computed: {
canRenderDeployBoard() { canRenderDeployBoard() {
return !this.isLoading && !this.isEmpty && !_.isEmpty(this.deployBoardData); return !this.isEmpty && !_.isEmpty(this.deployBoardData);
},
legacyLabelWarningMessage() {
return sprintf(
s__(
'DeployBoard|Matching on the %{appLabel} label has been removed for deploy boards. To see all instances on your board, you must update your chart and redeploy.',
),
{
appLabel: '<code>app</code>',
},
false,
);
}, },
canRenderEmptyState() { canRenderEmptyState() {
return !this.isLoading && this.isEmpty; return this.isEmpty;
}, },
instanceCount() { instanceCount() {
const { instances } = this.deployBoardData; const { instances } = this.deployBoardData;
...@@ -80,9 +102,16 @@ export default { ...@@ -80,9 +102,16 @@ export default {
<template> <template>
<div class="js-deploy-board deploy-board"> <div class="js-deploy-board deploy-board">
<gl-loading-icon v-if="isLoading" /> <gl-loading-icon v-if="isLoading" />
<template v-else>
<div v-if="hasLegacyAppLabel" class="bs-callout bs-callout-warning mb-0 mt-0">
<span v-html="legacyLabelWarningMessage"></span>
<gl-link target="blank" :href="deployBoardsHelpPath">
<strong>{{ __('More Information') }}</strong>
</gl-link>
</div>
<div v-if="canRenderDeployBoard"> <div v-if="canRenderDeployBoard" class="deploy-board-information">
<section class="deploy-board-information"> <section class="deploy-board-status">
<span v-tooltip :title="instanceIsCompletedText"> <span v-tooltip :title="instanceIsCompletedText">
<span class="percentage text-center text-plain">{{ deployBoardData.completion }}%</span> <span class="percentage text-center text-plain">{{ deployBoardData.completion }}%</span>
<span class="text text-center text-secondary">Complete</span> <span class="text text-center text-secondary">Complete</span>
...@@ -122,7 +151,6 @@ export default { ...@@ -122,7 +151,6 @@ export default {
> >
Rollback Rollback
</a> </a>
<a <a
v-if="deployBoardData.abort_url" v-if="deployBoardData.abort_url"
:href="deployBoardData.abort_url" :href="deployBoardData.abort_url"
...@@ -135,17 +163,20 @@ export default { ...@@ -135,17 +163,20 @@ export default {
</section> </section>
</div> </div>
<div v-if="canRenderEmptyState"> <div v-if="canRenderEmptyState" class="deploy-board-empty">
<section class="deploy-board-empty-state-svg" v-html="deployBoardSvg"></section> <section class="deploy-board-empty-state-svg" v-html="deployBoardSvg"></section>
<section class="deploy-board-empty-state-text"> <section class="deploy-board-empty-state-text">
<span class="deploy-board-empty-state-title d-flex">Kubernetes deployment not found</span> <span class="deploy-board-empty-state-title d-flex">Kubernetes deployment not found</span>
<span> <span>
To see deployment progress for your environments, make sure your deployments are in To see deployment progress for your environments, make sure your deployments are in
Kubernetes namespace <code>{{ projectName }}</code> and labeled with Kubernetes namespace <code>{{ projectName }}</code
<code>app=$CI_ENVIRONMENT_SLUG</code>. >, and annotated with
<code>app.gitlab.com/app=$CI_PROJECT_PATH_SLUG</code>
and <code>app.gitlab.com/env=$CI_ENVIRONMENT_SLUG</code>.
</span> </span>
</section> </section>
</div> </div>
</template>
</div> </div>
</template> </template>
...@@ -20,5 +20,10 @@ export default { ...@@ -20,5 +20,10 @@ export default {
type: String, type: String,
required: true, required: true,
}, },
deployBoardsHelpPath: {
type: String,
required: false,
default: '',
},
}, },
}; };
...@@ -24,6 +24,7 @@ export const setDeployBoard = (oldEnvironmentState, environment) => { ...@@ -24,6 +24,7 @@ export const setDeployBoard = (oldEnvironmentState, environment) => {
environment.rollout_status.status === 'found' ? environment.rollout_status : {}, environment.rollout_status.status === 'found' ? environment.rollout_status : {},
isLoadingDeployBoard: environment.rollout_status.status === 'loading', isLoadingDeployBoard: environment.rollout_status.status === 'loading',
isEmptyDeployBoard: environment.rollout_status.status === 'not_found', isEmptyDeployBoard: environment.rollout_status.status === 'not_found',
hasLegacyAppLabel: environment.rollout_status.has_legacy_app_label,
}); });
} }
return parsedEnvironment; return parsedEnvironment;
......
...@@ -2,15 +2,20 @@ ...@@ -2,15 +2,20 @@
* Deploy boards * Deploy boards
*/ */
.deploy-board { .deploy-board {
padding: 10px;
background-color: $gray-light; background-color: $gray-light;
min-height: 20px; min-height: 20px;
> div { > .loading-container,
> .deploy-board-empty,
> .deploy-board-information {
padding: 10px;
}
> .deploy-board-information {
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
.deploy-board-information { .deploy-board-status {
order: 1; order: 1;
display: flex; display: flex;
width: 70px; width: 70px;
......
...@@ -13,7 +13,9 @@ module EE ...@@ -13,7 +13,9 @@ module EE
deployments = filter_by_project_environment(data[:deployments], project.full_path_slug, environment.slug) deployments = filter_by_project_environment(data[:deployments], project.full_path_slug, environment.slug)
pods = filter_by_project_environment(data[:pods], project.full_path_slug, environment.slug) if data[:pods]&.any? pods = filter_by_project_environment(data[:pods], project.full_path_slug, environment.slug) if data[:pods]&.any?
::Gitlab::Kubernetes::RolloutStatus.from_deployments(*deployments, pods: pods) legacy_deployments = filter_by_legacy_label(data[:deployments], project.full_path_slug, environment.slug)
::Gitlab::Kubernetes::RolloutStatus.from_deployments(*deployments, pods: pods, legacy_deployments: legacy_deployments)
end end
result || ::Gitlab::Kubernetes::RolloutStatus.loading result || ::Gitlab::Kubernetes::RolloutStatus.loading
end end
......
...@@ -4,6 +4,7 @@ class RolloutStatusEntity < Grape::Entity ...@@ -4,6 +4,7 @@ class RolloutStatusEntity < Grape::Entity
include RequestAwareEntity include RequestAwareEntity
expose :status, as: :status expose :status, as: :status
expose :has_legacy_app_label?, as: :has_legacy_app_label
expose :instances, if: -> (rollout_status, _) { rollout_status.found? } expose :instances, if: -> (rollout_status, _) { rollout_status.found? }
expose :completion, if: -> (rollout_status, _) { rollout_status.found? } expose :completion, if: -> (rollout_status, _) { rollout_status.found? }
......
---
title: Show warning for deploy boards if legacy app label is used
merge_request: 14103
author:
type: other
...@@ -30,26 +30,31 @@ module Gitlab ...@@ -30,26 +30,31 @@ module Gitlab
@status == :not_found @status == :not_found
end end
def has_legacy_app_label?
legacy_deployments.present?
end
def found? def found?
@status == :found @status == :found
end end
def self.from_deployments(*deployments, pods: {}) def self.from_deployments(*deployments, pods: {}, legacy_deployments: [])
return new([], status: :not_found) if deployments.empty? return new([], status: :not_found, legacy_deployments: legacy_deployments) if deployments.empty?
deployments = deployments.map { |deploy| ::Gitlab::Kubernetes::Deployment.new(deploy, pods: pods) } deployments = deployments.map { |deploy| ::Gitlab::Kubernetes::Deployment.new(deploy, pods: pods) }
deployments.sort_by!(&:order) deployments.sort_by!(&:order)
new(deployments) new(deployments, legacy_deployments: legacy_deployments)
end end
def self.loading def self.loading
new([], status: :loading) new([], status: :loading)
end end
def initialize(deployments, status: :found) def initialize(deployments, status: :found, legacy_deployments: [])
@status = status @status = status
@deployments = deployments @deployments = deployments
@instances = deployments.flat_map(&:instances) @instances = deployments.flat_map(&:instances)
@legacy_deployments = legacy_deployments
@completion = @completion =
if @instances.empty? if @instances.empty?
...@@ -60,6 +65,10 @@ module Gitlab ...@@ -60,6 +65,10 @@ module Gitlab
(finished / @instances.count.to_f * 100).to_i (finished / @instances.count.to_f * 100).to_i
end end
end end
private
attr_reader :legacy_deployments
end end
end end
end end
...@@ -14,6 +14,9 @@ ...@@ -14,6 +14,9 @@
"is_completed": { "is_completed": {
"type": "boolean" "type": "boolean"
}, },
"has_legacy_app_label": {
"type": "boolean"
},
"instances": { "instances": {
"type": "array", "type": "array",
"items": { "items": {
......
...@@ -99,4 +99,29 @@ describe('Deploy Board', () => { ...@@ -99,4 +99,29 @@ describe('Deploy Board', () => {
expect(component.$el.querySelector('.fa-spin')).toBeDefined(); expect(component.$el.querySelector('.fa-spin')).toBeDefined();
}); });
}); });
describe('with hasLegacyAppLabel equal true', () => {
let component;
beforeEach(() => {
component = new DeployBoardComponent({
propsData: {
isLoading: false,
isEmpty: false,
logsPath: environment.log_path,
hasLegacyAppLabel: true,
deployBoardData: {},
},
}).$mount();
});
it('should render legacy label warning message', () => {
const warningMessage = component.$el.querySelector('.bs-callout-warning');
expect(warningMessage).toBeTruthy();
expect(warningMessage.innerText).toContain(
'Matching on the app label has been removed for deploy boards.',
);
});
});
}); });
...@@ -60,6 +60,26 @@ describe('Store', () => { ...@@ -60,6 +60,26 @@ describe('Store', () => {
expect(store.state.environments[0].deployBoardData).toEqual(deployBoardMockData); expect(store.state.environments[0].deployBoardData).toEqual(deployBoardMockData);
}); });
it('should set hasLegacyAppLabel property', () => {
expect(store.state.environments[0].deployBoardData).toEqual(deployBoardMockData);
const environment = {
name: 'foo',
size: 1,
latest: {
id: 1,
},
rollout_status: {
...deployBoardMockData,
status: 'not_found',
has_legacy_app_label: true,
},
};
store.storeEnvironments([environment]);
expect(store.state.environments[0].hasLegacyAppLabel).toBe(true);
});
}); });
describe('canaryCallout', () => { describe('canaryCallout', () => {
......
...@@ -5,7 +5,7 @@ describe Gitlab::Kubernetes::RolloutStatus do ...@@ -5,7 +5,7 @@ describe Gitlab::Kubernetes::RolloutStatus do
let(:track) { nil } let(:track) { nil }
let(:specs) { specs_all_finished } let(:specs) { specs_all_finished }
let(:specs_none) { [] } let(:legacy_deployments) { [] }
let(:pods) do let(:pods) do
create_pods(name: "one", count: 3, track: 'stable') + create_pods(name: "two", count: 3, track: "canary") create_pods(name: "one", count: 3, track: 'stable') + create_pods(name: "two", count: 3, track: "canary")
...@@ -25,7 +25,26 @@ describe Gitlab::Kubernetes::RolloutStatus do ...@@ -25,7 +25,26 @@ describe Gitlab::Kubernetes::RolloutStatus do
] ]
end end
subject(:rollout_status) { described_class.from_deployments(*specs, pods: pods) } subject(:rollout_status) { described_class.from_deployments(*specs, pods: pods, legacy_deployments: legacy_deployments) }
describe '#has_legacy_app_label?' do
let(:specs) { [] }
let(:pods) { [] }
context 'no legacy deployments' do
it { is_expected.not_to be_has_legacy_app_label }
end
context 'with legacy deployment' do
let(:legacy_deployments) do
[
kube_deployment(name: 'legacy')
]
end
it { is_expected.to be_has_legacy_app_label }
end
end
describe '#deployments' do describe '#deployments' do
it 'stores the deployments' do it 'stores the deployments' do
...@@ -125,7 +144,7 @@ describe Gitlab::Kubernetes::RolloutStatus do ...@@ -125,7 +144,7 @@ describe Gitlab::Kubernetes::RolloutStatus do
end end
context 'when list of specs is empty' do context 'when list of specs is empty' do
let(:specs) { specs_none } let(:specs) { [] }
it { is_expected.to be_not_found } it { is_expected.to be_not_found }
end end
...@@ -137,7 +156,7 @@ describe Gitlab::Kubernetes::RolloutStatus do ...@@ -137,7 +156,7 @@ describe Gitlab::Kubernetes::RolloutStatus do
end end
context 'when list of specs is empty' do context 'when list of specs is empty' do
let(:specs) { specs_none } let(:specs) { [] }
it { is_expected.not_to be_found } it { is_expected.not_to be_found }
end end
......
...@@ -43,6 +43,10 @@ describe KubernetesService, models: true, use_clean_rails_memory_store_caching: ...@@ -43,6 +43,10 @@ describe KubernetesService, models: true, use_clean_rails_memory_store_caching:
expect(rollout_status.deployments).to eq([]) expect(rollout_status.deployments).to eq([])
end end
it 'has the has_legacy_app_label flag' do
expect(rollout_status).to be_has_legacy_app_label
end
end end
context 'new deployment based on annotations' do context 'new deployment based on annotations' do
...@@ -62,6 +66,40 @@ describe KubernetesService, models: true, use_clean_rails_memory_store_caching: ...@@ -62,6 +66,40 @@ describe KubernetesService, models: true, use_clean_rails_memory_store_caching:
expect(rollout_status.deployments.map(&:name)).to contain_exactly('matched-deployment') expect(rollout_status.deployments.map(&:name)).to contain_exactly('matched-deployment')
end end
it 'does have the has_legacy_app_label flag' do
expect(rollout_status).to be_has_legacy_app_label
end
end
context 'deployment with app label not matching the environment' do
let(:other_deployment) do
kube_deployment(name: 'other-deployment').tap do |deployment|
deployment['metadata']['annotations'].delete('app.gitlab.com/env')
deployment['metadata']['annotations'].delete('app.gitlab.com/app')
deployment['metadata']['labels']['app'] = 'helm-app-label'
end
end
let(:other_pod) do
kube_pod(name: 'other-pod').tap do |pod|
pod['metadata']['annotations'].delete('app.gitlab.com/env')
pod['metadata']['annotations'].delete('app.gitlab.com/app')
pod['metadata']['labels']['app'] = environment.slug
end
end
before do
stub_reactive_cache(
service,
deployments: [other_deployment],
pods: [other_pod]
)
end
it 'does not have the has_legacy_app_label flag' do
expect(rollout_status).not_to be_has_legacy_app_label
end
end end
end end
......
...@@ -3,19 +3,23 @@ require 'spec_helper' ...@@ -3,19 +3,23 @@ require 'spec_helper'
describe RolloutStatusEntity do describe RolloutStatusEntity do
include KubernetesHelpers include KubernetesHelpers
let(:rollout_status) { kube_deployment_rollout_status }
let(:entity) do let(:entity) do
described_class.new(rollout_status, request: double) described_class.new(rollout_status, request: double)
end end
subject { entity.as_json } subject { entity.as_json }
context 'when kube deployment is valid' do
let(:rollout_status) { kube_deployment_rollout_status }
it "exposes status" do it "exposes status" do
is_expected.to include(:status) is_expected.to include(:status)
end end
it 'exposes has_legacy_app_label' do
is_expected.to include(:has_legacy_app_label)
end
context 'when kube deployment is valid' do
it "exposes deployment data" do it "exposes deployment data" do
is_expected.to include(:instances, :completion, :is_completed) is_expected.to include(:instances, :completion, :is_completed)
end end
......
...@@ -4164,6 +4164,9 @@ msgstr "" ...@@ -4164,6 +4164,9 @@ msgstr ""
msgid "Deploy key was successfully updated." msgid "Deploy key was successfully updated."
msgstr "" msgstr ""
msgid "DeployBoard|Matching on the %{appLabel} label has been removed for deploy boards. To see all instances on your board, you must update your chart and redeploy."
msgstr ""
msgid "DeployKeys|+%{count} others" msgid "DeployKeys|+%{count} others"
msgstr "" msgstr ""
...@@ -8539,6 +8542,9 @@ msgstr "" ...@@ -8539,6 +8542,9 @@ msgstr ""
msgid "More" msgid "More"
msgstr "" msgstr ""
msgid "More Information"
msgstr ""
msgid "More actions" msgid "More actions"
msgstr "" msgstr ""
......
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