@spinnaker/core 0.24.1 → 0.26.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +43 -0
- package/dist/application/config/defaultTagFilter/DefaultTagFilterConfig.d.ts +27 -0
- package/dist/application/config/defaultTagFilter/defaultTagFilterConfig.component.d.ts +1 -0
- package/dist/config/settings.d.ts +1 -0
- package/dist/domain/IArtifact.d.ts +2 -0
- package/dist/domain/ITrigger.d.ts +5 -0
- package/dist/index.js +36 -36
- package/dist/index.js.map +1 -1
- package/dist/manifest/ManifestYaml.d.ts +10 -4
- package/dist/pipeline/config/stages/bakeManifest/ManifestRenderers.d.ts +2 -0
- package/dist/pipeline/config/stages/bakeManifest/helmfile/BakeHelmfileConfigForm.d.ts +18 -0
- package/dist/pipeline/config/stages/bakeManifest/utils/getBakedArtifacts.d.ts +4 -0
- package/dist/pipeline/config/stages/bakeManifest/utils/getContentReference.d.ts +1 -0
- package/dist/pipeline/config/triggers/artifacts/ArtifactService.d.ts +3 -0
- package/dist/pipeline/config/triggers/cdevents/CDEventsTrigger.d.ts +7 -0
- package/dist/pipeline/config/triggers/cdevents/cdevents.trigger.d.ts +1 -0
- package/dist/pipeline/config/triggers/index.d.ts +1 -0
- package/dist/pipeline/executions/Executions.d.ts +1 -0
- package/dist/pipeline/index.d.ts +2 -0
- package/dist/presentation/forms/inputs/NumberConcurrencyInput.d.ts +7 -0
- package/package.json +2 -2
- package/src/application/config/applicationConfig.controller.js +26 -0
- package/src/application/config/applicationConfig.view.html +9 -0
- package/src/application/config/defaultTagFilter/DefaultTagFilterConfig.spec.tsx +75 -0
- package/src/application/config/defaultTagFilter/DefaultTagFilterConfig.tsx +161 -0
- package/src/application/config/defaultTagFilter/defaultTagFilterConfig.component.ts +15 -0
- package/src/application/config/defaultTagFilter/defaultTagFilterConfig.less +8 -0
- package/src/artifact/ArtifactIconService.ts +1 -0
- package/src/artifact/ArtifactTypes.ts +1 -0
- package/src/config/settings.ts +1 -0
- package/src/domain/IArtifact.ts +3 -0
- package/src/domain/ITrigger.ts +4 -0
- package/src/help/help.contents.ts +10 -0
- package/src/manifest/ManifestYaml.tsx +29 -7
- package/src/pipeline/config/stages/bakeManifest/BakeManifestConfig.tsx +4 -1
- package/src/pipeline/config/stages/bakeManifest/BakeManifestDetailsTab.tsx +24 -12
- package/src/pipeline/config/stages/bakeManifest/BakeManifestStageForm.tsx +9 -2
- package/src/pipeline/config/stages/bakeManifest/ManifestRenderers.ts +2 -0
- package/src/pipeline/config/stages/bakeManifest/helmfile/BakeHelmfileConfigForm.spec.tsx +132 -0
- package/src/pipeline/config/stages/bakeManifest/helmfile/BakeHelmfileConfigForm.tsx +271 -0
- package/src/pipeline/config/stages/bakeManifest/utils/getBakedArtifacts.ts +13 -0
- package/src/pipeline/config/stages/bakeManifest/utils/getContentReference.ts +3 -0
- package/src/pipeline/config/triggers/artifacts/ArtifactService.ts +4 -0
- package/src/pipeline/config/triggers/cdevents/CDEventsTrigger.tsx +48 -0
- package/src/pipeline/config/triggers/cdevents/cdevents.trigger.ts +19 -0
- package/src/pipeline/config/triggers/index.ts +1 -0
- package/src/pipeline/create/CreatePipelineModal.tsx +1 -1
- package/src/pipeline/details/StageFailureMessage.tsx +10 -24
- package/src/pipeline/executions/Executions.tsx +13 -0
- package/src/pipeline/index.ts +2 -0
- package/src/pipeline/status/ExecutionCancellationReason.tsx +1 -1
- package/src/presentation/forms/inputs/NumberConcurrencyInput.tsx +29 -0
|
@@ -1,7 +1,13 @@
|
|
|
1
1
|
/// <reference types="react" />
|
|
2
|
-
|
|
2
|
+
declare type IManifestYamlProps = {
|
|
3
3
|
linkName: string;
|
|
4
|
-
manifestText: string;
|
|
5
4
|
modalTitle: string;
|
|
6
|
-
}
|
|
7
|
-
|
|
5
|
+
} & ({
|
|
6
|
+
manifestText: string;
|
|
7
|
+
manifestUri?: never;
|
|
8
|
+
} | {
|
|
9
|
+
manifestText?: never;
|
|
10
|
+
manifestUri: string;
|
|
11
|
+
});
|
|
12
|
+
export declare function ManifestYaml({ linkName, modalTitle, manifestText, manifestUri }: IManifestYamlProps): JSX.Element;
|
|
13
|
+
export {};
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
export declare enum ManifestRenderers {
|
|
2
2
|
HELM2 = "HELM2",
|
|
3
3
|
HELM3 = "HELM3",
|
|
4
|
+
HELMFILE = "HELMFILE",
|
|
4
5
|
KUSTOMIZE = "KUSTOMIZE",
|
|
5
6
|
KUSTOMIZE4 = "KUSTOMIZE4"
|
|
6
7
|
}
|
|
7
8
|
export declare const HELM_RENDERERS: Readonly<ManifestRenderers[]>;
|
|
9
|
+
export declare const HELMFILE_RENDERER: Readonly<ManifestRenderers>;
|
|
8
10
|
export declare const KUSTOMIZE_RENDERERS: Readonly<ManifestRenderers[]>;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import type { IFormikStageConfigInjectedProps } from '../../FormikStageConfig';
|
|
3
|
+
export interface IBakeHelmfileConfigFormState {
|
|
4
|
+
gitRepoArtifactAccountNames: string[];
|
|
5
|
+
}
|
|
6
|
+
export declare class BakeHelmfileConfigForm extends React.Component<IFormikStageConfigInjectedProps, IBakeHelmfileConfigFormState> {
|
|
7
|
+
constructor(props: IFormikStageConfigInjectedProps);
|
|
8
|
+
private static readonly excludedArtifactTypes;
|
|
9
|
+
componentDidMount(): void;
|
|
10
|
+
private onTemplateArtifactEdited;
|
|
11
|
+
private onTemplateArtifactSelected;
|
|
12
|
+
private addInputArtifact;
|
|
13
|
+
private removeInputArtifact;
|
|
14
|
+
private getInputArtifact;
|
|
15
|
+
private outputNameChange;
|
|
16
|
+
private overrideChanged;
|
|
17
|
+
render(): JSX.Element;
|
|
18
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const getContentReference: (uri: string) => string;
|
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
export declare class ArtifactService {
|
|
2
2
|
static getArtifactNames(type: string, accountName: string): PromiseLike<string[]>;
|
|
3
3
|
static getArtifactVersions(type: string, accountName: string, artifactName: string): PromiseLike<string[]>;
|
|
4
|
+
static getArtifactByContentReference(contentRef: string): PromiseLike<{
|
|
5
|
+
reference: string;
|
|
6
|
+
}>;
|
|
4
7
|
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/// <reference types="react" />
|
|
2
|
+
import type { FormikProps } from 'formik';
|
|
3
|
+
import type { ICDEventsTrigger } from '../../../../domain';
|
|
4
|
+
export interface ICDEventsTriggerProps {
|
|
5
|
+
formik: FormikProps<ICDEventsTrigger>;
|
|
6
|
+
}
|
|
7
|
+
export declare function CDEventsTrigger(cdeventsTriggerProps: ICDEventsTriggerProps): JSX.Element;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -24,6 +24,7 @@ export declare class Executions extends React.Component<IExecutionsProps, IExecu
|
|
|
24
24
|
private filterCountOptions;
|
|
25
25
|
constructor(props: IExecutionsProps);
|
|
26
26
|
private setReloadingForFilters;
|
|
27
|
+
private loadDefaultFilters;
|
|
27
28
|
private clearFilters;
|
|
28
29
|
private forceUpdateExecutionGroups;
|
|
29
30
|
private updateExecutionGroups;
|
package/dist/pipeline/index.d.ts
CHANGED
|
@@ -23,3 +23,5 @@ export * from './manualExecution/TriggerTemplate';
|
|
|
23
23
|
export * from './service/ExecutionsTransformer';
|
|
24
24
|
export * from './service/execution.service';
|
|
25
25
|
export * from './status/ArtifactList';
|
|
26
|
+
export * from './config/stages/bakeManifest/utils/getBakedArtifacts';
|
|
27
|
+
export * from './config/stages/bakeManifest/utils/getContentReference';
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import type { IFormInputProps, OmitControlledInputPropsFrom } from './interface';
|
|
3
|
+
interface INumberInputProps extends IFormInputProps, OmitControlledInputPropsFrom<React.InputHTMLAttributes<any>> {
|
|
4
|
+
inputClassName?: string;
|
|
5
|
+
}
|
|
6
|
+
export declare function NumberConcurrencyInput(props: INumberInputProps): JSX.Element;
|
|
7
|
+
export {};
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@spinnaker/core",
|
|
3
3
|
"license": "Apache-2.0",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.26.0",
|
|
5
5
|
"module": "dist/index.js",
|
|
6
6
|
"typings": "dist/index.d.ts",
|
|
7
7
|
"scripts": {
|
|
@@ -120,5 +120,5 @@
|
|
|
120
120
|
"shx": "0.3.3",
|
|
121
121
|
"typescript": "4.3.5"
|
|
122
122
|
},
|
|
123
|
-
"gitHead": "
|
|
123
|
+
"gitHead": "581f9d4358d0c90a385df0119a7ae0a41b81c1cb"
|
|
124
124
|
}
|
|
@@ -8,6 +8,7 @@ import { CORE_APPLICATION_CONFIG_APPLICATIONSNAPSHOTSECTION_COMPONENT } from './
|
|
|
8
8
|
import { CHAOS_MONKEY_CONFIG_COMPONENT } from '../../chaosMonkey/chaosMonkeyConfig.component';
|
|
9
9
|
import { SETTINGS } from '../../config/settings';
|
|
10
10
|
import { APPLICATION_DATA_SOURCE_EDITOR } from './dataSources/applicationDataSourceEditor.component';
|
|
11
|
+
import { DEFAULT_TAG_FILTER_CONFIG } from './defaultTagFilter/defaultTagFilterConfig.component';
|
|
11
12
|
import { DELETE_APPLICATION_SECTION } from './deleteApplicationSection.module';
|
|
12
13
|
import { CORE_APPLICATION_CONFIG_LINKS_APPLICATIONLINKS_COMPONENT } from './links/applicationLinks.component';
|
|
13
14
|
import { ApplicationWriter } from '../service/ApplicationWriter';
|
|
@@ -25,6 +26,7 @@ module(CORE_APPLICATION_CONFIG_APPLICATIONCONFIG_CONTROLLER, [
|
|
|
25
26
|
CHAOS_MONKEY_CONFIG_COMPONENT,
|
|
26
27
|
TRAFFIC_GUARD_CONFIG_COMPONENT,
|
|
27
28
|
CORE_APPLICATION_CONFIG_LINKS_APPLICATIONLINKS_COMPONENT,
|
|
29
|
+
DEFAULT_TAG_FILTER_CONFIG,
|
|
28
30
|
]).controller('ApplicationConfigController', [
|
|
29
31
|
'$state',
|
|
30
32
|
'app',
|
|
@@ -63,6 +65,30 @@ module(CORE_APPLICATION_CONFIG_APPLICATIONCONFIG_CONTROLLER, [
|
|
|
63
65
|
});
|
|
64
66
|
};
|
|
65
67
|
|
|
68
|
+
this.defaultTagFilterProps = {
|
|
69
|
+
isSaving: false,
|
|
70
|
+
saveError: false,
|
|
71
|
+
};
|
|
72
|
+
this.updateDefaultTagFilterConfigs = (tagConfigs /* IDefaultTagFilterConfig[] */) => {
|
|
73
|
+
const applicationAttributes = cloneDeep(this.application.attributes);
|
|
74
|
+
applicationAttributes.defaultFilteredTags = tagConfigs;
|
|
75
|
+
$scope.$applyAsync(() => {
|
|
76
|
+
this.defaultTagFilterProps.isSaving = true;
|
|
77
|
+
this.defaultTagFilterProps.saveError = false;
|
|
78
|
+
});
|
|
79
|
+
ApplicationWriter.updateApplication(applicationAttributes)
|
|
80
|
+
.then(() => {
|
|
81
|
+
$scope.$applyAsync(() => {
|
|
82
|
+
this.defaultTagFilterProps.isSaving = false;
|
|
83
|
+
this.application.attributes = applicationAttributes;
|
|
84
|
+
});
|
|
85
|
+
})
|
|
86
|
+
.catch(() => {
|
|
87
|
+
this.defaultTagFilterProps.isSaving = false;
|
|
88
|
+
this.defaultTagFilterProps.saveError = true;
|
|
89
|
+
});
|
|
90
|
+
};
|
|
91
|
+
|
|
66
92
|
this.notifications = [];
|
|
67
93
|
this.updateNotifications = (notifications) => {
|
|
68
94
|
$scope.$applyAsync(() => {
|
|
@@ -54,6 +54,15 @@
|
|
|
54
54
|
>
|
|
55
55
|
</custom-banner-config>
|
|
56
56
|
</page-section>
|
|
57
|
+
<page-section key="default-filters" label="Default Filters">
|
|
58
|
+
<default-tag-filter-config
|
|
59
|
+
default-tag-filter-configs="config.application.attributes.defaultFilteredTags"
|
|
60
|
+
is-saving="config.defaultTagFilterProps.isSaving"
|
|
61
|
+
save-error="config.defaultTagFilterProps.saveError"
|
|
62
|
+
update-default-tag-filter-configs="config.updateDefaultTagFilterConfigs"
|
|
63
|
+
>
|
|
64
|
+
</default-tag-filter-config>
|
|
65
|
+
</page-section>
|
|
57
66
|
<page-section key="delete" label="Delete Application">
|
|
58
67
|
<delete-application-section application="config.application"></delete-application-section>
|
|
59
68
|
</page-section>
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { shallow } from 'enzyme';
|
|
2
|
+
import React from 'react';
|
|
3
|
+
|
|
4
|
+
import type { IDefaultTagFilterConfig } from './DefaultTagFilterConfig';
|
|
5
|
+
import { DefaultTagFilterConfig } from './DefaultTagFilterConfig';
|
|
6
|
+
import { noop } from '../../../utils';
|
|
7
|
+
|
|
8
|
+
describe('<DefaultTagFilterConfig />', () => {
|
|
9
|
+
let tagConfigs: IDefaultTagFilterConfig[];
|
|
10
|
+
let wrapper: any;
|
|
11
|
+
|
|
12
|
+
beforeEach(() => {
|
|
13
|
+
tagConfigs = getTestDefaultFilterTagConfigs();
|
|
14
|
+
wrapper = shallow(
|
|
15
|
+
<DefaultTagFilterConfig
|
|
16
|
+
defaultTagFilterConfigs={tagConfigs}
|
|
17
|
+
isSaving={false}
|
|
18
|
+
saveError={false}
|
|
19
|
+
updateDefaultTagFilterConfigs={noop}
|
|
20
|
+
/>,
|
|
21
|
+
);
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
describe('view', () => {
|
|
25
|
+
it('renders a row for each banner config', () => {
|
|
26
|
+
expect(wrapper.find('.default-filter-config-row').length).toEqual(tagConfigs.length);
|
|
27
|
+
});
|
|
28
|
+
it('renders an "add" button', () => {
|
|
29
|
+
expect(wrapper.find('.add-new').length).toEqual(1);
|
|
30
|
+
});
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
describe('functionality', () => {
|
|
34
|
+
it('update default tag filter config', () => {
|
|
35
|
+
expect(wrapper.state('defaultTagFilterConfigsEditing')).toEqual(tagConfigs);
|
|
36
|
+
wrapper
|
|
37
|
+
.find('textarea')
|
|
38
|
+
.at(1)
|
|
39
|
+
.simulate('change', { target: { value: 'hello' } });
|
|
40
|
+
const updatedConfigs = [
|
|
41
|
+
{
|
|
42
|
+
...tagConfigs[0],
|
|
43
|
+
tagValue: 'hello',
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
...tagConfigs[1],
|
|
47
|
+
},
|
|
48
|
+
];
|
|
49
|
+
expect(wrapper.state('defaultTagFilterConfigsEditing')).toEqual(updatedConfigs);
|
|
50
|
+
});
|
|
51
|
+
it('add default filter tag config', () => {
|
|
52
|
+
expect(wrapper.state('defaultTagFilterConfigsEditing').length).toEqual(2);
|
|
53
|
+
wrapper.find('.add-new').simulate('click');
|
|
54
|
+
expect(wrapper.state('defaultTagFilterConfigsEditing').length).toEqual(3);
|
|
55
|
+
});
|
|
56
|
+
it('remove default filter tag config', () => {
|
|
57
|
+
expect(wrapper.state('defaultTagFilterConfigsEditing').length).toEqual(2);
|
|
58
|
+
wrapper.find('.default-filter-config-remove').at(1).simulate('click');
|
|
59
|
+
expect(wrapper.state('defaultTagFilterConfigsEditing').length).toEqual(1);
|
|
60
|
+
});
|
|
61
|
+
});
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
export function getTestDefaultFilterTagConfigs(): IDefaultTagFilterConfig[] {
|
|
65
|
+
return [
|
|
66
|
+
{
|
|
67
|
+
tagName: 'Pipeline Type',
|
|
68
|
+
tagValue: 'Deployment Pipelines',
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
tagName: 'Pipeline Type',
|
|
72
|
+
tagValue: 'Repair Pipelines',
|
|
73
|
+
},
|
|
74
|
+
];
|
|
75
|
+
}
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
import { isEqual } from 'lodash';
|
|
2
|
+
import React from 'react';
|
|
3
|
+
|
|
4
|
+
import { ConfigSectionFooter } from '../footer/ConfigSectionFooter';
|
|
5
|
+
import { noop } from '../../../utils';
|
|
6
|
+
|
|
7
|
+
import './defaultTagFilterConfig.less';
|
|
8
|
+
|
|
9
|
+
export interface IDefaultTagFilterConfig {
|
|
10
|
+
tagName: string;
|
|
11
|
+
tagValue: string;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export interface IDefaultTagFilterProps {
|
|
15
|
+
defaultTagFilterConfigs: IDefaultTagFilterConfig[];
|
|
16
|
+
isSaving: boolean;
|
|
17
|
+
saveError: boolean;
|
|
18
|
+
updateDefaultTagFilterConfigs: (defaultTagFilterConfigs: IDefaultTagFilterConfig[]) => void;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export interface IDefaultTagFilterState {
|
|
22
|
+
defaultTagFilterConfigsEditing: IDefaultTagFilterConfig[];
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export class DefaultTagFilterConfig extends React.Component<IDefaultTagFilterProps, IDefaultTagFilterState> {
|
|
26
|
+
public static defaultProps: Partial<IDefaultTagFilterProps> = {
|
|
27
|
+
defaultTagFilterConfigs: [],
|
|
28
|
+
isSaving: false,
|
|
29
|
+
saveError: false,
|
|
30
|
+
updateDefaultTagFilterConfigs: noop,
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
constructor(props: IDefaultTagFilterProps) {
|
|
34
|
+
super(props);
|
|
35
|
+
this.state = {
|
|
36
|
+
defaultTagFilterConfigsEditing: props.defaultTagFilterConfigs,
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
private onTagNameChange = (idx: number, text: string) => {
|
|
41
|
+
this.setState({
|
|
42
|
+
defaultTagFilterConfigsEditing: this.state.defaultTagFilterConfigsEditing.map((config, i) => {
|
|
43
|
+
if (i === idx) {
|
|
44
|
+
return {
|
|
45
|
+
...config,
|
|
46
|
+
tagName: text,
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
return config;
|
|
50
|
+
}),
|
|
51
|
+
});
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
private onTagValueChange = (idx: number, text: string) => {
|
|
55
|
+
this.setState({
|
|
56
|
+
defaultTagFilterConfigsEditing: this.state.defaultTagFilterConfigsEditing.map((config, i) => {
|
|
57
|
+
if (i === idx) {
|
|
58
|
+
return {
|
|
59
|
+
...config,
|
|
60
|
+
tagValue: text,
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
return config;
|
|
64
|
+
}),
|
|
65
|
+
});
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
private addFilterTag = (): void => {
|
|
69
|
+
this.setState({
|
|
70
|
+
defaultTagFilterConfigsEditing: this.state.defaultTagFilterConfigsEditing.concat([
|
|
71
|
+
{
|
|
72
|
+
tagName: 'Name of the tag (E.g. Pipeline Type)',
|
|
73
|
+
tagValue: 'Value of the tag (E.g. Default Pipelines)',
|
|
74
|
+
} as IDefaultTagFilterConfig,
|
|
75
|
+
]),
|
|
76
|
+
});
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
private removeFilterTag = (idx: number): void => {
|
|
80
|
+
this.setState({
|
|
81
|
+
defaultTagFilterConfigsEditing: this.state.defaultTagFilterConfigsEditing.filter((_config, i) => i !== idx),
|
|
82
|
+
});
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
private isDirty = (): boolean => {
|
|
86
|
+
return !isEqual(this.props.defaultTagFilterConfigs, this.state.defaultTagFilterConfigsEditing);
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
private onRevertClicked = (): void => {
|
|
90
|
+
this.setState({
|
|
91
|
+
defaultTagFilterConfigsEditing: this.props.defaultTagFilterConfigs,
|
|
92
|
+
});
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
private onSaveClicked = (): void => {
|
|
96
|
+
this.props.updateDefaultTagFilterConfigs(this.state.defaultTagFilterConfigsEditing);
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
public render() {
|
|
100
|
+
return (
|
|
101
|
+
<div className="default-filter-config-container">
|
|
102
|
+
<div className="default-filter-config-description">
|
|
103
|
+
Default Tag filters allow you to specify which tags are immediately filtered to when the pipeline execution
|
|
104
|
+
page is loaded in.
|
|
105
|
+
</div>
|
|
106
|
+
<div className="col-md-10 col-md-offset-1">
|
|
107
|
+
<table className="table table-condensed">
|
|
108
|
+
<thead>
|
|
109
|
+
<tr>
|
|
110
|
+
<th>Tag Name</th>
|
|
111
|
+
<th>Tag Value</th>
|
|
112
|
+
</tr>
|
|
113
|
+
</thead>
|
|
114
|
+
<tbody>
|
|
115
|
+
{this.state.defaultTagFilterConfigsEditing.map((defaultTagFilter, idx) => (
|
|
116
|
+
<tr key={idx} className="default-filter-config-row">
|
|
117
|
+
<td>
|
|
118
|
+
<textarea
|
|
119
|
+
className="form-control input-sm"
|
|
120
|
+
onChange={(e: React.ChangeEvent<HTMLTextAreaElement>) =>
|
|
121
|
+
this.onTagNameChange(idx, e.target.value)
|
|
122
|
+
}
|
|
123
|
+
value={defaultTagFilter.tagName}
|
|
124
|
+
/>
|
|
125
|
+
</td>
|
|
126
|
+
<td>
|
|
127
|
+
<textarea
|
|
128
|
+
className="form-control input-sm"
|
|
129
|
+
onChange={(e: React.ChangeEvent<HTMLTextAreaElement>) =>
|
|
130
|
+
this.onTagValueChange(idx, e.target.value)
|
|
131
|
+
}
|
|
132
|
+
value={defaultTagFilter.tagValue}
|
|
133
|
+
/>
|
|
134
|
+
</td>
|
|
135
|
+
<td>
|
|
136
|
+
<button className="link default-filter-config-remove" onClick={() => this.removeFilterTag(idx)}>
|
|
137
|
+
<span className="glyphicon glyphicon-trash" />
|
|
138
|
+
</button>
|
|
139
|
+
</td>
|
|
140
|
+
</tr>
|
|
141
|
+
))}
|
|
142
|
+
</tbody>
|
|
143
|
+
</table>
|
|
144
|
+
</div>
|
|
145
|
+
<div className="col-md-10 col-md-offset-1">
|
|
146
|
+
<button className="btn btn-block add-new" onClick={this.addFilterTag}>
|
|
147
|
+
<span className="glyphicon glyphicon-plus-sign" /> Add Default Filter
|
|
148
|
+
</button>
|
|
149
|
+
</div>
|
|
150
|
+
<ConfigSectionFooter
|
|
151
|
+
isDirty={this.isDirty()}
|
|
152
|
+
isValid={true}
|
|
153
|
+
isSaving={this.props.isSaving}
|
|
154
|
+
saveError={false}
|
|
155
|
+
onRevertClicked={this.onRevertClicked}
|
|
156
|
+
onSaveClicked={this.onSaveClicked}
|
|
157
|
+
/>
|
|
158
|
+
</div>
|
|
159
|
+
);
|
|
160
|
+
}
|
|
161
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { module } from 'angular';
|
|
2
|
+
import { react2angular } from 'react2angular';
|
|
3
|
+
import { DefaultTagFilterConfig } from './DefaultTagFilterConfig';
|
|
4
|
+
import { withErrorBoundary } from '../../../presentation/SpinErrorBoundary';
|
|
5
|
+
|
|
6
|
+
export const DEFAULT_TAG_FILTER_CONFIG = 'spinnaker.micros.application.defaultTagFilterConfig.component';
|
|
7
|
+
module(DEFAULT_TAG_FILTER_CONFIG, []).component(
|
|
8
|
+
'defaultTagFilterConfig',
|
|
9
|
+
react2angular(withErrorBoundary(DefaultTagFilterConfig, 'defaultTagFilterConfig'), [
|
|
10
|
+
'defaultTagFilterConfigs',
|
|
11
|
+
'isSaving',
|
|
12
|
+
'saveError',
|
|
13
|
+
'updateDefaultTagFilterConfigs',
|
|
14
|
+
]),
|
|
15
|
+
);
|
|
@@ -44,6 +44,7 @@ ArtifactIconService.registerType(ArtifactTypePatterns.CUSTOM_OBJECT, unknownArti
|
|
|
44
44
|
ArtifactIconService.registerType(ArtifactTypePatterns.DOCKER_IMAGE, dockerIcon);
|
|
45
45
|
ArtifactIconService.registerType(ArtifactTypePatterns.KUBERNETES, kubernetesIcon);
|
|
46
46
|
ArtifactIconService.registerType(ArtifactTypePatterns.EMBEDDED_BASE64, embeddedBase64Icon);
|
|
47
|
+
ArtifactIconService.registerType(ArtifactTypePatterns.REMOTE_BASE64, embeddedBase64Icon);
|
|
47
48
|
ArtifactIconService.registerType(ArtifactTypePatterns.GCS_OBJECT, gcsObjectIcon);
|
|
48
49
|
ArtifactIconService.registerType(ArtifactTypePatterns.GITHUB_FILE, gitHubFileIcon);
|
|
49
50
|
ArtifactIconService.registerType(ArtifactTypePatterns.GIT_REPO, gitRepoIcon);
|
|
@@ -7,6 +7,7 @@ export const ArtifactTypePatterns: IArtifactTypePatterns = {
|
|
|
7
7
|
CUSTOM_OBJECT: /custom\/object/,
|
|
8
8
|
DOCKER_IMAGE: /docker\/image/,
|
|
9
9
|
EMBEDDED_BASE64: /embedded\/base64/,
|
|
10
|
+
REMOTE_BASE64: /remote\/base64/,
|
|
10
11
|
GCS_OBJECT: /gcs\/object/,
|
|
11
12
|
GITHUB_FILE: /github\/file/,
|
|
12
13
|
GIT_REPO: /git\/repo/,
|
package/src/config/settings.ts
CHANGED
|
@@ -34,6 +34,7 @@ export interface IFeatures {
|
|
|
34
34
|
executionMarkerInformationModal?: boolean;
|
|
35
35
|
fiatEnabled?: boolean;
|
|
36
36
|
iapRefresherEnabled?: boolean;
|
|
37
|
+
lambdaAdditionalStages?: boolean;
|
|
37
38
|
managedDelivery?: boolean;
|
|
38
39
|
mdGitIntegration?: boolean;
|
|
39
40
|
managedServiceAccounts?: boolean;
|
package/src/domain/IArtifact.ts
CHANGED
package/src/domain/ITrigger.ts
CHANGED
|
@@ -91,6 +91,10 @@ export interface IWebhookTrigger extends ITrigger {
|
|
|
91
91
|
payloadConstraints: { [key: string]: string };
|
|
92
92
|
}
|
|
93
93
|
|
|
94
|
+
export interface ICDEventsTrigger extends IWebhookTrigger {
|
|
95
|
+
attributeConstraints: { [key: string]: string };
|
|
96
|
+
}
|
|
97
|
+
|
|
94
98
|
export interface IWerckerTrigger extends IBuildTrigger {
|
|
95
99
|
app: string;
|
|
96
100
|
pipeline: string;
|
|
@@ -178,6 +178,11 @@ const helpContents: { [key: string]: string } = {
|
|
|
178
178
|
<p>When provided, only a webhook with a payload containing at least the specified key/value pairs will be allowed to trigger this pipeline. For example, if you wanted to lock down the systems/users that can trigger this pipeline via this webhook, you could require the key "secret" and value "something-secret" as a constraint.</p>
|
|
179
179
|
<p>The constraint values may be supplied as regex.</p>
|
|
180
180
|
`,
|
|
181
|
+
'pipeline.config.trigger.cdevents.attributeConstraints': `
|
|
182
|
+
<p>CDEvents messages will have mandatory headers id, source, specversion, type accompanying the payload called <b>attributes</b>.</p>
|
|
183
|
+
<p>When provided, only a CDEvents message with attributes containing at least the specified key/value pairs will be allowed to trigger this pipeline.</p>
|
|
184
|
+
<p>The constraint value is a java regex string.</p>
|
|
185
|
+
`,
|
|
181
186
|
'pipeline.config.trigger.pubsub.attributeConstraints': `
|
|
182
187
|
<p>Pubsub messages can have system-specific metadata accompanying the payload called <b>attributes</b>.</p>
|
|
183
188
|
<p>When provided, only a pubsub message with attributes containing at least the specified key/value pairs will be allowed to trigger this pipeline.</p>
|
|
@@ -307,6 +312,11 @@ const helpContents: { [key: string]: string } = {
|
|
|
307
312
|
'pipeline.config.bake.manifest.kustomize.filePath': `
|
|
308
313
|
<p>This is the relative path to the kustomization.yaml file within your Git repo.</p>
|
|
309
314
|
<p>e.g.: <b>examples/wordpress/mysql/kustomization.yaml</b></p>`,
|
|
315
|
+
'pipeline.config.bake.manifest.helmfile.filePath': `
|
|
316
|
+
<p>This is the relative path to the directory containing the helmfile.yaml file within your Git repo.</p>
|
|
317
|
+
<p>e.g.: <b>chart/helmfile.yml</b></p>`,
|
|
318
|
+
'pipeline.config.bake.manifest.helmfile.name':
|
|
319
|
+
'<p> Name is used to set the expected artifact in the Produces Artifact section. </p>',
|
|
310
320
|
'pipeline.config.bake.cf.manifest.name':
|
|
311
321
|
'<p> Name should be the same as the expected artifact in the Produces Artifact section. </p>',
|
|
312
322
|
'pipeline.config.bake.cf.manifest.templateArtifact': `
|
|
@@ -1,26 +1,48 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import { Modal } from 'react-bootstrap';
|
|
3
|
+
import { ArtifactService } from '../pipeline/config/triggers/artifacts/ArtifactService';
|
|
4
|
+
import { decodeUnicodeBase64 } from '../utils';
|
|
3
5
|
|
|
4
|
-
|
|
6
|
+
type IManifestYamlProps = {
|
|
5
7
|
linkName: string;
|
|
6
|
-
manifestText: string;
|
|
7
8
|
modalTitle: string;
|
|
8
|
-
}
|
|
9
|
+
} & ({ manifestText: string; manifestUri?: never } | { manifestText?: never; manifestUri: string });
|
|
9
10
|
|
|
10
|
-
export function ManifestYaml(
|
|
11
|
+
export function ManifestYaml({ linkName, modalTitle, manifestText, manifestUri }: IManifestYamlProps) {
|
|
11
12
|
const [modalVisible, setModalVisible] = React.useState<boolean>(false);
|
|
12
13
|
const toggle = () => setModalVisible(!modalVisible);
|
|
14
|
+
const [fetchedManifestText, setFetchedManifestText] = React.useState<string>('Loading...');
|
|
15
|
+
const [error, setError] = React.useState<string | null>(null);
|
|
16
|
+
|
|
17
|
+
React.useEffect(() => {
|
|
18
|
+
if (manifestUri) {
|
|
19
|
+
ArtifactService.getArtifactByContentReference(manifestUri)
|
|
20
|
+
.then((manifest) => setFetchedManifestText(decodeUnicodeBase64(manifest.reference)))
|
|
21
|
+
.catch((e) => setError(`Error: ${typeof e !== 'string' ? e.data?.message ?? JSON.stringify(e) : e}`));
|
|
22
|
+
}
|
|
23
|
+
}, []);
|
|
24
|
+
|
|
13
25
|
return (
|
|
14
26
|
<>
|
|
15
27
|
<a key="modal-link" onClick={toggle} className="clickable">
|
|
16
|
-
{
|
|
28
|
+
{linkName}
|
|
17
29
|
</a>
|
|
18
30
|
<Modal key="modal" show={modalVisible} onHide={toggle}>
|
|
19
31
|
<Modal.Header closeButton={true}>
|
|
20
|
-
<h3>{
|
|
32
|
+
<h3>{modalTitle}</h3>
|
|
21
33
|
</Modal.Header>
|
|
22
34
|
<Modal.Body>
|
|
23
|
-
|
|
35
|
+
{error ? (
|
|
36
|
+
<div className="alert alert-warning">
|
|
37
|
+
<p>{error}</p>
|
|
38
|
+
</div>
|
|
39
|
+
) : null}
|
|
40
|
+
<textarea
|
|
41
|
+
readOnly={true}
|
|
42
|
+
rows={15}
|
|
43
|
+
className="code"
|
|
44
|
+
value={manifestUri ? fetchedManifestText : manifestText}
|
|
45
|
+
/>
|
|
24
46
|
</Modal.Body>
|
|
25
47
|
<Modal.Footer>
|
|
26
48
|
<button className="btn btn-primary" onClick={toggle}>
|
|
@@ -4,7 +4,7 @@ import React from 'react';
|
|
|
4
4
|
|
|
5
5
|
import { BakeManifestStageForm, validateProducedArtifacts } from './BakeManifestStageForm';
|
|
6
6
|
import { FormikStageConfig } from '../FormikStageConfig';
|
|
7
|
-
import { HELM_RENDERERS } from './ManifestRenderers';
|
|
7
|
+
import { HELM_RENDERERS, HELMFILE_RENDERER } from './ManifestRenderers';
|
|
8
8
|
import type { IStageConfigProps } from '../common';
|
|
9
9
|
import type { IExpectedArtifact, IStage } from '../../../../domain';
|
|
10
10
|
import { FormValidator } from '../../../../presentation';
|
|
@@ -46,6 +46,9 @@ export function validateBakeManifestStage(stage: IStage): FormikErrors<IStage> {
|
|
|
46
46
|
if (HELM_RENDERERS.includes(stage.templateRenderer)) {
|
|
47
47
|
formValidator.field('outputName', 'Name').required();
|
|
48
48
|
}
|
|
49
|
+
if (HELMFILE_RENDERER === stage.templateRenderer) {
|
|
50
|
+
formValidator.field('outputName', 'Name').required();
|
|
51
|
+
}
|
|
49
52
|
|
|
50
53
|
return formValidator.validateForm();
|
|
51
54
|
}
|