@spinnaker/core 2026.0.2 → 2026.1.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/dist/ci/igor.service.d.ts +0 -1
- package/dist/domain/ITrigger.d.ts +1 -11
- package/dist/index.js +36 -36
- package/dist/index.js.map +1 -1
- package/dist/managed/graphql/client.d.ts +1 -1
- package/dist/managed/graphql/graphql-sdk.d.ts +9 -9
- package/dist/pipeline/config/stages/bakeManifest/ManifestRenderers.d.ts +2 -2
- package/dist/pipeline/config/triggers/Triggers.d.ts +1 -0
- package/dist/pipeline/config/triggers/index.d.ts +0 -1
- package/package.json +3 -3
- package/src/application/search/react-ultimate-pagination.d.ts +1 -1
- package/src/ci/igor.service.ts +0 -1
- package/src/domain/ITrigger.ts +1 -13
- package/src/help/help.contents.ts +1 -9
- package/src/pipeline/config/pipelineConfigView.html +1 -0
- package/src/pipeline/config/stages/bakeManifest/ManifestRenderers.ts +2 -2
- package/src/pipeline/config/stages/createLoadBalancer/createLoadBalancerStage.js +45 -28
- package/src/pipeline/config/stages/createLoadBalancer/createLoadBalancerStage.spec.js +101 -0
- package/src/pipeline/config/triggers/MetadataPageContent.spec.tsx +140 -0
- package/src/pipeline/config/triggers/Triggers.spec.tsx +80 -0
- package/src/pipeline/config/triggers/Triggers.tsx +6 -1
- package/src/pipeline/config/triggers/index.ts +0 -1
- package/src/pipeline/config/triggers/triggers.module.ts +1 -0
- package/src/pipeline/pipeline.module.ts +0 -2
- package/src/presentation/ReactModal.spec.tsx +72 -0
- package/src/presentation/ReactModal.tsx +12 -2
- package/dist/pipeline/config/stages/wercker/WerckerExecutionLabel.d.ts +0 -7
- package/dist/pipeline/config/stages/wercker/modal/addParameter.controller.modal.d.ts +0 -10
- package/dist/pipeline/config/stages/wercker/werckerExecutionDetails.controller.d.ts +0 -18
- package/dist/pipeline/config/stages/wercker/werckerStage.d.ts +0 -51
- package/dist/pipeline/config/stages/wercker/werckerStage.module.d.ts +0 -1
- package/dist/pipeline/config/triggers/wercker/WerckerTrigger.d.ts +0 -13
- package/dist/pipeline/config/triggers/wercker/WerckerTriggerTemplate.d.ts +0 -7
- package/dist/pipeline/config/triggers/wercker/wercker.trigger.d.ts +0 -1
- package/src/pipeline/config/stages/wercker/WerckerExecutionLabel.tsx +0 -32
- package/src/pipeline/config/stages/wercker/modal/addParameter.controller.modal.ts +0 -19
- package/src/pipeline/config/stages/wercker/modal/addParameter.html +0 -48
- package/src/pipeline/config/stages/wercker/werckerExecutionDetails.controller.spec.ts +0 -79
- package/src/pipeline/config/stages/wercker/werckerExecutionDetails.controller.ts +0 -55
- package/src/pipeline/config/stages/wercker/werckerExecutionDetails.html +0 -79
- package/src/pipeline/config/stages/wercker/werckerStage.controller.spec.ts +0 -152
- package/src/pipeline/config/stages/wercker/werckerStage.html +0 -150
- package/src/pipeline/config/stages/wercker/werckerStage.module.ts +0 -18
- package/src/pipeline/config/stages/wercker/werckerStage.ts +0 -232
- package/src/pipeline/config/triggers/wercker/WerckerTrigger.tsx +0 -122
- package/src/pipeline/config/triggers/wercker/WerckerTriggerTemplate.tsx +0 -13
- package/src/pipeline/config/triggers/wercker/wercker.trigger.ts +0 -28
|
@@ -1,152 +0,0 @@
|
|
|
1
|
-
import Spy = jasmine.Spy;
|
|
2
|
-
import type { IControllerService, IQService, IRootScopeService, IScope } from 'angular';
|
|
3
|
-
import { mock } from 'angular';
|
|
4
|
-
|
|
5
|
-
import { IgorService } from '../../../../ci/igor.service';
|
|
6
|
-
import type { IJobConfig, IParameterDefinitionList } from '../../../../domain';
|
|
7
|
-
import { WERCKER_STAGE, WerckerStage } from './werckerStage';
|
|
8
|
-
|
|
9
|
-
describe('Wercker Stage Controller', () => {
|
|
10
|
-
let $scope: IScope, $q: IQService, $ctrl: IControllerService;
|
|
11
|
-
|
|
12
|
-
beforeEach(mock.module(WERCKER_STAGE, require('angular-ui-bootstrap')));
|
|
13
|
-
|
|
14
|
-
beforeEach(
|
|
15
|
-
mock.inject(($controller: IControllerService, $rootScope: IRootScopeService, _$q_: IQService) => {
|
|
16
|
-
$ctrl = $controller;
|
|
17
|
-
$scope = $rootScope.$new();
|
|
18
|
-
$q = _$q_;
|
|
19
|
-
}),
|
|
20
|
-
);
|
|
21
|
-
|
|
22
|
-
const initialize = (stage: any): WerckerStage => {
|
|
23
|
-
return $ctrl(WerckerStage, {
|
|
24
|
-
stage,
|
|
25
|
-
$scope,
|
|
26
|
-
});
|
|
27
|
-
};
|
|
28
|
-
|
|
29
|
-
describe('updateAppsList', () => {
|
|
30
|
-
beforeEach(() => {
|
|
31
|
-
spyOn(IgorService, 'listMasters').and.returnValue($q.when([]));
|
|
32
|
-
});
|
|
33
|
-
|
|
34
|
-
it('does nothing if master is parameterized', () => {
|
|
35
|
-
spyOn(IgorService, 'listJobsForMaster');
|
|
36
|
-
const stage = {
|
|
37
|
-
master: '${parameter.master}',
|
|
38
|
-
};
|
|
39
|
-
const controller = initialize(stage);
|
|
40
|
-
$scope.$digest();
|
|
41
|
-
expect(controller.jobs).toBeUndefined();
|
|
42
|
-
expect(controller.viewState.appsLoaded).toBe(true);
|
|
43
|
-
expect((IgorService.listJobsForMaster as Spy).calls.count()).toBe(0);
|
|
44
|
-
});
|
|
45
|
-
|
|
46
|
-
it('does nothing if job is parameterized', () => {
|
|
47
|
-
spyOn(IgorService, 'listJobsForMaster');
|
|
48
|
-
const stage = {
|
|
49
|
-
master: 'not-parameterized',
|
|
50
|
-
job: '${parameter.job}',
|
|
51
|
-
};
|
|
52
|
-
const controller = initialize(stage);
|
|
53
|
-
$scope.$digest();
|
|
54
|
-
expect(controller.jobs).toBeUndefined();
|
|
55
|
-
expect(controller.viewState.appsLoaded).toBe(true);
|
|
56
|
-
expect((IgorService.listJobsForMaster as Spy).calls.count()).toBe(0);
|
|
57
|
-
});
|
|
58
|
-
|
|
59
|
-
it('gets jobs from igor and adds them to scope', () => {
|
|
60
|
-
const jobs = ['type/org/app/p1', 'type/org/app/p2'];
|
|
61
|
-
spyOn(IgorService, 'listJobsForMaster').and.returnValue($q.when(jobs));
|
|
62
|
-
const stage = {
|
|
63
|
-
master: 'not-parameterized',
|
|
64
|
-
};
|
|
65
|
-
const controller = initialize(stage);
|
|
66
|
-
$scope.$digest();
|
|
67
|
-
expect(controller.jobs).toEqual(jobs);
|
|
68
|
-
expect(controller.viewState.appsLoaded).toBe(true);
|
|
69
|
-
});
|
|
70
|
-
|
|
71
|
-
it('clears job if no longer present when retrieving from igor', () => {
|
|
72
|
-
const jobs = ['type/org/app/a', 'type/org/app/b'];
|
|
73
|
-
spyOn(IgorService, 'listJobsForMaster').and.returnValue($q.when(jobs));
|
|
74
|
-
spyOn(IgorService, 'getJobConfig').and.returnValue($q.when(null));
|
|
75
|
-
const stage = {
|
|
76
|
-
master: 'not-parameterized',
|
|
77
|
-
job: 'type/org/app/c',
|
|
78
|
-
};
|
|
79
|
-
const controller = initialize(stage);
|
|
80
|
-
$scope.$digest();
|
|
81
|
-
expect(controller.jobs).toEqual(jobs);
|
|
82
|
-
expect(controller.viewState.appsLoaded).toBe(true);
|
|
83
|
-
expect(stage.job).toBe('');
|
|
84
|
-
});
|
|
85
|
-
});
|
|
86
|
-
|
|
87
|
-
describe('updateJobConfig', () => {
|
|
88
|
-
beforeEach(() => {
|
|
89
|
-
spyOn(IgorService, 'listMasters').and.returnValue($q.when([]));
|
|
90
|
-
});
|
|
91
|
-
|
|
92
|
-
it('does nothing if master is parameterized', () => {
|
|
93
|
-
spyOn(IgorService, 'listJobsForMaster');
|
|
94
|
-
spyOn(IgorService, 'getJobConfig');
|
|
95
|
-
const stage = {
|
|
96
|
-
master: '${parameter.master}',
|
|
97
|
-
};
|
|
98
|
-
const controller = initialize(stage);
|
|
99
|
-
$scope.$digest();
|
|
100
|
-
expect(controller.jobs).toBeUndefined();
|
|
101
|
-
expect(controller.viewState.appsLoaded).toBe(true);
|
|
102
|
-
expect((IgorService.listJobsForMaster as Spy).calls.count()).toBe(0);
|
|
103
|
-
expect((IgorService.getJobConfig as Spy).calls.count()).toBe(0);
|
|
104
|
-
});
|
|
105
|
-
|
|
106
|
-
it('does nothing if job is parameterized', () => {
|
|
107
|
-
spyOn(IgorService, 'listJobsForMaster');
|
|
108
|
-
spyOn(IgorService, 'getJobConfig');
|
|
109
|
-
const stage = {
|
|
110
|
-
master: 'not-parameterized',
|
|
111
|
-
job: '${parameter.job}',
|
|
112
|
-
};
|
|
113
|
-
const controller = initialize(stage);
|
|
114
|
-
$scope.$digest();
|
|
115
|
-
expect(controller.jobs).toBeUndefined();
|
|
116
|
-
expect(controller.viewState.appsLoaded).toBe(true);
|
|
117
|
-
expect((IgorService.listJobsForMaster as Spy).calls.count()).toBe(0);
|
|
118
|
-
expect((IgorService.getJobConfig as Spy).calls.count()).toBe(0);
|
|
119
|
-
});
|
|
120
|
-
|
|
121
|
-
it('gets job config and adds parameters to scope, setting defaults if present and not overridden', () => {
|
|
122
|
-
const jobs = ['type/org/app/x', 'type/org/app/y'];
|
|
123
|
-
const params: IParameterDefinitionList[] = [
|
|
124
|
-
{ name: 'overridden', defaultValue: 'z' },
|
|
125
|
-
{ name: 'notSet', defaultValue: 'a' },
|
|
126
|
-
{ name: 'noDefault', defaultValue: null },
|
|
127
|
-
];
|
|
128
|
-
const jobConfig = {
|
|
129
|
-
parameterDefinitionList: params,
|
|
130
|
-
} as IJobConfig;
|
|
131
|
-
spyOn(IgorService, 'listJobsForMaster').and.returnValue($q.when(jobs));
|
|
132
|
-
spyOn(IgorService, 'getJobConfig').and.returnValue($q.when(jobConfig));
|
|
133
|
-
const stage = {
|
|
134
|
-
master: 'not-parameterized',
|
|
135
|
-
app: 'org/app',
|
|
136
|
-
job: 'type/org/app/x',
|
|
137
|
-
parameters: {
|
|
138
|
-
overridden: 'f',
|
|
139
|
-
},
|
|
140
|
-
};
|
|
141
|
-
const controller = initialize(stage);
|
|
142
|
-
$scope.$digest();
|
|
143
|
-
expect(controller.jobs).toEqual(jobs);
|
|
144
|
-
expect(controller.viewState.appsLoaded).toBe(true);
|
|
145
|
-
expect(controller.stage.job).toBe('type/org/app/x');
|
|
146
|
-
expect(controller.jobParams).toBe(params);
|
|
147
|
-
expect(controller.useDefaultParameters.overridden).toBeUndefined();
|
|
148
|
-
expect(controller.useDefaultParameters.notSet).toBe(true);
|
|
149
|
-
expect(controller.useDefaultParameters.noDefault).toBeUndefined();
|
|
150
|
-
});
|
|
151
|
-
});
|
|
152
|
-
});
|
|
@@ -1,150 +0,0 @@
|
|
|
1
|
-
<div class="form-horizontal">
|
|
2
|
-
<div class="form-group">
|
|
3
|
-
<label class="col-md-2 col-md-offset-1 sm-label-right">Build Service</label>
|
|
4
|
-
<div class="col-md-6">
|
|
5
|
-
<p class="form-control-static" ng-if="$ctrl.viewState.masterIsParameterized">{{$ctrl.stage.master}}</p>
|
|
6
|
-
<ui-select
|
|
7
|
-
class="form-control input-sm"
|
|
8
|
-
ng-if="!$ctrl.viewState.masterIsParameterized"
|
|
9
|
-
ng-model="$ctrl.stage.master"
|
|
10
|
-
>
|
|
11
|
-
<ui-select-match placeholder="Select a Wercker build service...">{{$select.selected}}</ui-select-match>
|
|
12
|
-
<ui-select-choices repeat="master in $ctrl.masters | filter: $select.search">
|
|
13
|
-
<span ng-bind-html="master | highlight: $select.search"></span>
|
|
14
|
-
</ui-select-choices>
|
|
15
|
-
</ui-select>
|
|
16
|
-
</div>
|
|
17
|
-
<div class="col-md-1 text-center" ng-if="!$ctrl.viewState.masterIsParameterized">
|
|
18
|
-
<a
|
|
19
|
-
href
|
|
20
|
-
ng-click="$ctrl.refreshMasters()"
|
|
21
|
-
tooltip-placement="right"
|
|
22
|
-
uib-tooltip="{{$ctrl.viewState.mastersRefreshing ? 'Masters refreshing.' : 'Refresh masters list' }}"
|
|
23
|
-
>
|
|
24
|
-
<span ng-class="{'fa-spin':$ctrl.viewState.mastersRefreshing}" class="fa fa-sync-alt"></span>
|
|
25
|
-
</a>
|
|
26
|
-
</div>
|
|
27
|
-
</div>
|
|
28
|
-
|
|
29
|
-
<div class="form-group">
|
|
30
|
-
<label class="col-md-2 col-md-offset-1 sm-label-right">Application</label>
|
|
31
|
-
<div class="col-md-6">
|
|
32
|
-
<p class="form-control-static" ng-if="!$ctrl.stage.master">(Select a build service)</p>
|
|
33
|
-
<p
|
|
34
|
-
class="form-control-static"
|
|
35
|
-
ng-if="$ctrl.viewState.masterIsParameterized || $ctrl.viewState.appIsParameterized"
|
|
36
|
-
>
|
|
37
|
-
{{$ctrl.stage.app}}
|
|
38
|
-
</p>
|
|
39
|
-
<div ng-if="$ctrl.stage.master && $ctrl.viewState.appsLoaded">
|
|
40
|
-
<ui-select
|
|
41
|
-
class="form-control input-sm"
|
|
42
|
-
ng-if="!$ctrl.viewState.masterIsParameterized && !$ctrl.viewState.appIsParameterized"
|
|
43
|
-
ng-model="$ctrl.stage.app"
|
|
44
|
-
>
|
|
45
|
-
<ui-select-match placeholder="Select an Application...">{{$select.selected}}</ui-select-match>
|
|
46
|
-
<ui-select-choices repeat="app in $ctrl.apps | filter: $select.search"
|
|
47
|
-
><span ng-bind-html="app | highlight: $select.search"></span
|
|
48
|
-
></ui-select-choices>
|
|
49
|
-
</ui-select>
|
|
50
|
-
</div>
|
|
51
|
-
<div class="horizontal center" ng-if="$ctrl.stage.master && !$ctrl.viewState.appsLoaded">
|
|
52
|
-
<loading-spinner size="'small'"></loading-spinner>
|
|
53
|
-
</div>
|
|
54
|
-
</div>
|
|
55
|
-
<div
|
|
56
|
-
class="col-md-1 text-center"
|
|
57
|
-
ng-if="!$ctrl.viewState.masterIsParameterized && !$ctrl.viewState.appIsParameterized"
|
|
58
|
-
>
|
|
59
|
-
<a
|
|
60
|
-
href
|
|
61
|
-
ng-click="$ctrl.refreshApps()"
|
|
62
|
-
tooltip-placement="right"
|
|
63
|
-
uib-tooltip="{{$ctrl.viewState.appsRefreshing ? 'Applications refreshing.' : 'Refresh application list' }}"
|
|
64
|
-
>
|
|
65
|
-
<span ng-class="{'fa-spin':$ctrl.viewState.appsRefreshing}" class="fa fa-sync-alt"></span>
|
|
66
|
-
</a>
|
|
67
|
-
</div>
|
|
68
|
-
</div>
|
|
69
|
-
|
|
70
|
-
<div class="form-group">
|
|
71
|
-
<label class="col-md-2 col-md-offset-1 sm-label-right">Pipeline</label>
|
|
72
|
-
<div class="col-md-6">
|
|
73
|
-
<p class="form-control-static" ng-if="!$ctrl.stage.master">(Select an Application)</p>
|
|
74
|
-
<p
|
|
75
|
-
class="form-control-static"
|
|
76
|
-
ng-if="$ctrl.viewState.masterIsParameterized || $ctrl.viewState.jobIsParameterized"
|
|
77
|
-
>
|
|
78
|
-
{{stage.job}}
|
|
79
|
-
</p>
|
|
80
|
-
<div ng-if="$ctrl.stage.app && $ctrl.viewState.appsLoaded">
|
|
81
|
-
<ui-select
|
|
82
|
-
class="form-control input-sm"
|
|
83
|
-
ng-if="!$ctrl.viewState.masterIsParameterized && !$ctrl.viewState.jobIsParameterized"
|
|
84
|
-
ng-model="$ctrl.stage.pipeline"
|
|
85
|
-
>
|
|
86
|
-
<ui-select-match placeholder="Select a pipeline...">{{$select.selected}}</ui-select-match>
|
|
87
|
-
<ui-select-choices repeat="pipeline in $ctrl.pipelines | filter: $select.search"
|
|
88
|
-
><span ng-bind-html="pipeline | highlight: $select.search"></span
|
|
89
|
-
></ui-select-choices>
|
|
90
|
-
</ui-select>
|
|
91
|
-
</div>
|
|
92
|
-
<div class="horizontal center" ng-if="$ctrl.stage.app && !$ctrl.viewState.appsLoaded">
|
|
93
|
-
<loading-spinner size="'small'"></loading-spinner>
|
|
94
|
-
</div>
|
|
95
|
-
</div>
|
|
96
|
-
<div
|
|
97
|
-
class="col-md-1 text-center"
|
|
98
|
-
ng-if="!$ctrl.viewState.masterIsParameterized && !$ctrl.viewState.jobIsParameterized"
|
|
99
|
-
>
|
|
100
|
-
<a
|
|
101
|
-
href
|
|
102
|
-
ng-click="$ctrl.refreshJobs()"
|
|
103
|
-
tooltip-placement="right"
|
|
104
|
-
uib-tooltip="{{$ctrl.viewState.appsRefreshing ? 'Jobs refreshing.' : 'Refresh job list' }}"
|
|
105
|
-
>
|
|
106
|
-
<span ng-class="{'fa-spin':$ctrl.viewState.appsRefreshing}" class="fa fa-sync-alt"></span>
|
|
107
|
-
</a>
|
|
108
|
-
</div>
|
|
109
|
-
</div>
|
|
110
|
-
|
|
111
|
-
<stage-config-field label="Wait for results" help-key="wercker.waitForCompletion">
|
|
112
|
-
<input
|
|
113
|
-
type="checkbox"
|
|
114
|
-
class="input-sm"
|
|
115
|
-
name="waitForCompletion"
|
|
116
|
-
ng-model="$ctrl.viewState.waitForCompletion"
|
|
117
|
-
ng-change="$ctrl.waitForCompletionChanged()"
|
|
118
|
-
/>
|
|
119
|
-
</stage-config-field>
|
|
120
|
-
|
|
121
|
-
<div class="form-group">
|
|
122
|
-
<label class="col-md-2 col-md-offset-1 sm-label-right">If build is unstable</label>
|
|
123
|
-
<div class="col-md-9">
|
|
124
|
-
<div class="radio">
|
|
125
|
-
<label>
|
|
126
|
-
<input
|
|
127
|
-
type="radio"
|
|
128
|
-
ng-model="$ctrl.viewState.markUnstableAsSuccessful"
|
|
129
|
-
ng-change="$ctrl.markUnstableChanged()"
|
|
130
|
-
ng-value="false"
|
|
131
|
-
/>
|
|
132
|
-
fail the stage
|
|
133
|
-
<help-field key="pipeline.config.wercker.markUnstableAsSuccessful.false"></help-field>
|
|
134
|
-
</label>
|
|
135
|
-
</div>
|
|
136
|
-
<div class="radio">
|
|
137
|
-
<label>
|
|
138
|
-
<input
|
|
139
|
-
type="radio"
|
|
140
|
-
ng-model="$ctrl.viewState.markUnstableAsSuccessful"
|
|
141
|
-
ng-change="$ctrl.markUnstableChanged()"
|
|
142
|
-
ng-value="true"
|
|
143
|
-
/>
|
|
144
|
-
consider stage successful
|
|
145
|
-
<help-field key="pipeline.config.wercker.markUnstableAsSuccessful.true"></help-field>
|
|
146
|
-
</label>
|
|
147
|
-
</div>
|
|
148
|
-
</div>
|
|
149
|
-
</div>
|
|
150
|
-
</div>
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
import { module } from 'angular';
|
|
2
|
-
|
|
3
|
-
import { STAGE_COMMON_MODULE } from '../common/stage.common.module';
|
|
4
|
-
import { WERCKER_STAGE_ADD_PARAMETER_MODAL_CONTROLLER } from './modal/addParameter.controller.modal';
|
|
5
|
-
import { CORE_PIPELINE_CONFIG_STAGES_STAGE_MODULE } from '../stage.module';
|
|
6
|
-
import { TIME_FORMATTERS } from '../../../../utils/timeFormatters';
|
|
7
|
-
import { WERCKER_EXECUTION_DETAILS_CONTROLLER } from './werckerExecutionDetails.controller';
|
|
8
|
-
import { WERCKER_STAGE } from './werckerStage';
|
|
9
|
-
|
|
10
|
-
export const WERCKER_STAGE_MODULE = 'spinnaker.core.pipeline.stage.wercker';
|
|
11
|
-
module(WERCKER_STAGE_MODULE, [
|
|
12
|
-
WERCKER_STAGE,
|
|
13
|
-
CORE_PIPELINE_CONFIG_STAGES_STAGE_MODULE,
|
|
14
|
-
STAGE_COMMON_MODULE,
|
|
15
|
-
TIME_FORMATTERS,
|
|
16
|
-
WERCKER_EXECUTION_DETAILS_CONTROLLER,
|
|
17
|
-
WERCKER_STAGE_ADD_PARAMETER_MODAL_CONTROLLER,
|
|
18
|
-
]);
|
|
@@ -1,232 +0,0 @@
|
|
|
1
|
-
import type { IController, IScope } from 'angular';
|
|
2
|
-
import { module } from 'angular';
|
|
3
|
-
import type { IModalService } from 'angular-ui-bootstrap';
|
|
4
|
-
|
|
5
|
-
import { WerckerExecutionLabel } from './WerckerExecutionLabel';
|
|
6
|
-
import { BuildServiceType, IgorService } from '../../../../ci/igor.service';
|
|
7
|
-
import type { IJobConfig, IParameterDefinitionList, IStage } from '../../../../domain';
|
|
8
|
-
import { Registry } from '../../../../registry';
|
|
9
|
-
|
|
10
|
-
export interface IWerckerStageViewState {
|
|
11
|
-
mastersLoaded: boolean;
|
|
12
|
-
mastersRefreshing: boolean;
|
|
13
|
-
appsLoaded: boolean;
|
|
14
|
-
appsRefreshing: boolean;
|
|
15
|
-
failureOption?: string;
|
|
16
|
-
markUnstableAsSuccessful?: boolean;
|
|
17
|
-
waitForCompletion?: boolean;
|
|
18
|
-
masterIsParameterized?: boolean;
|
|
19
|
-
jobIsParameterized?: boolean;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
export interface IParameter {
|
|
23
|
-
key: string;
|
|
24
|
-
value: string;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
export class WerckerStage implements IController {
|
|
28
|
-
public viewState: IWerckerStageViewState;
|
|
29
|
-
public useDefaultParameters: any;
|
|
30
|
-
public userSuppliedParameters: any;
|
|
31
|
-
public masters: string[];
|
|
32
|
-
public jobs: string[];
|
|
33
|
-
public jobParams: IParameterDefinitionList[];
|
|
34
|
-
public apps: string[];
|
|
35
|
-
public pipelines: string[];
|
|
36
|
-
public filterLimit = 100;
|
|
37
|
-
private filterThreshold = 500;
|
|
38
|
-
public app: string;
|
|
39
|
-
public pipeline: string;
|
|
40
|
-
public job: string;
|
|
41
|
-
|
|
42
|
-
public static $inject = ['stage', '$scope', '$uibModal'];
|
|
43
|
-
constructor(public stage: any, $scope: IScope, private $uibModal: IModalService) {
|
|
44
|
-
this.stage.failPipeline = this.stage.failPipeline === undefined ? true : this.stage.failPipeline;
|
|
45
|
-
this.stage.continuePipeline = this.stage.continuePipeline === undefined ? false : this.stage.continuePipeline;
|
|
46
|
-
this.viewState = {
|
|
47
|
-
mastersLoaded: false,
|
|
48
|
-
mastersRefreshing: false,
|
|
49
|
-
appsLoaded: false,
|
|
50
|
-
appsRefreshing: false,
|
|
51
|
-
failureOption: 'fail',
|
|
52
|
-
markUnstableAsSuccessful: !!this.stage.markUnstableAsSuccessful,
|
|
53
|
-
waitForCompletion: this.stage.waitForCompletion || this.stage.waitForCompletion === undefined,
|
|
54
|
-
};
|
|
55
|
-
this.useDefaultParameters = {};
|
|
56
|
-
this.userSuppliedParameters = {};
|
|
57
|
-
|
|
58
|
-
this.initializeMasters();
|
|
59
|
-
|
|
60
|
-
$scope.$watch('stage.master', () => this.updateAppsList());
|
|
61
|
-
$scope.$watch('stage.app', () => this.updateJobsList());
|
|
62
|
-
$scope.$watch('stage.pipeline', () => this.updateJob());
|
|
63
|
-
$scope.$watch('stage.job', () => this.updateJobConfig());
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
// Using viewState to avoid marking pipeline as dirty if field is not set
|
|
67
|
-
public markUnstableChanged(): void {
|
|
68
|
-
this.stage.markUnstableAsSuccessful = this.viewState.markUnstableAsSuccessful;
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
public waitForCompletionChanged(): void {
|
|
72
|
-
this.stage.waitForCompletion = this.viewState.waitForCompletion;
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
public refreshMasters(): void {
|
|
76
|
-
this.viewState.mastersRefreshing = true;
|
|
77
|
-
this.initializeMasters();
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
private initializeMasters(): void {
|
|
81
|
-
IgorService.listMasters(BuildServiceType.Wercker).then((masters: string[]) => {
|
|
82
|
-
this.masters = masters;
|
|
83
|
-
this.viewState.mastersLoaded = true;
|
|
84
|
-
this.viewState.mastersRefreshing = false;
|
|
85
|
-
});
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
public refreshApps(): void {
|
|
89
|
-
this.viewState.appsRefreshing = true;
|
|
90
|
-
this.updateAppsList();
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
private updateAppsList(): void {
|
|
94
|
-
const master = this.stage.master;
|
|
95
|
-
const job: string = this.stage.job || '';
|
|
96
|
-
const viewState = this.viewState;
|
|
97
|
-
viewState.masterIsParameterized = master.includes('${');
|
|
98
|
-
viewState.jobIsParameterized = job.includes('${');
|
|
99
|
-
if (viewState.masterIsParameterized || viewState.jobIsParameterized) {
|
|
100
|
-
viewState.appsLoaded = true;
|
|
101
|
-
return;
|
|
102
|
-
}
|
|
103
|
-
if (this.stage && this.stage.master) {
|
|
104
|
-
this.viewState.appsLoaded = false;
|
|
105
|
-
this.apps = [];
|
|
106
|
-
IgorService.listJobsForMaster(this.stage.master).then((jobs) => {
|
|
107
|
-
this.viewState.appsLoaded = true;
|
|
108
|
-
this.viewState.appsRefreshing = false;
|
|
109
|
-
const apps = Object.create({});
|
|
110
|
-
jobs.forEach(function (app) {
|
|
111
|
-
const orgApp = app.substring(app.indexOf('/') + 1, app.lastIndexOf('/'));
|
|
112
|
-
apps[orgApp] = orgApp;
|
|
113
|
-
});
|
|
114
|
-
this.apps = Object.keys(apps);
|
|
115
|
-
this.jobs = jobs;
|
|
116
|
-
if (this.apps.length && !this.apps.includes(this.stage.app)) {
|
|
117
|
-
this.stage.app = '';
|
|
118
|
-
this.stage.pipeline = '';
|
|
119
|
-
this.stage.job = '';
|
|
120
|
-
}
|
|
121
|
-
});
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
public refreshJobs(): void {
|
|
126
|
-
this.viewState.appsRefreshing = true;
|
|
127
|
-
this.updateJobsList();
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
private updateJobsList(): void {
|
|
131
|
-
if (this.stage && this.stage.app) {
|
|
132
|
-
this.pipelines = [];
|
|
133
|
-
this.viewState.appsLoaded = true;
|
|
134
|
-
this.viewState.appsRefreshing = false;
|
|
135
|
-
if (this.jobs) {
|
|
136
|
-
const pipelines = Object.create({});
|
|
137
|
-
const appSelected = this.stage.app;
|
|
138
|
-
this.jobs.forEach(function (app) {
|
|
139
|
-
if (
|
|
140
|
-
!app.startsWith('pipeline') &&
|
|
141
|
-
appSelected === app.substring(app.indexOf('/') + 1, app.lastIndexOf('/'))
|
|
142
|
-
) {
|
|
143
|
-
const pl = app.substring(app.lastIndexOf('/') + 1);
|
|
144
|
-
pipelines[pl] = pl;
|
|
145
|
-
}
|
|
146
|
-
});
|
|
147
|
-
this.pipelines = Object.keys(pipelines);
|
|
148
|
-
}
|
|
149
|
-
if (this.pipelines.length && !this.pipelines.includes(this.stage.pipeline)) {
|
|
150
|
-
this.stage.pipeline = '';
|
|
151
|
-
this.stage.job = '';
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
private updateJob(): void {
|
|
157
|
-
if (this.stage && this.stage.app && this.stage.pipeline) {
|
|
158
|
-
this.stage.job = this.stage.app + '/' + this.stage.pipeline;
|
|
159
|
-
}
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
private updateJobConfig(): void {
|
|
163
|
-
const stage = this.stage;
|
|
164
|
-
const view = this.viewState;
|
|
165
|
-
if (stage && stage.job && stage.master && !view.masterIsParameterized && !view.jobIsParameterized) {
|
|
166
|
-
IgorService.getJobConfig(stage.master, stage.job).then((config: IJobConfig) => {
|
|
167
|
-
config = config || ({} as IJobConfig);
|
|
168
|
-
if (!stage.parameters) {
|
|
169
|
-
stage.parameters = {};
|
|
170
|
-
}
|
|
171
|
-
this.jobParams = config.parameterDefinitionList;
|
|
172
|
-
this.userSuppliedParameters = stage.parameters;
|
|
173
|
-
this.useDefaultParameters = {};
|
|
174
|
-
const params = this.jobParams || ([] as IParameterDefinitionList[]);
|
|
175
|
-
params.forEach((property: any) => {
|
|
176
|
-
if (!(property.name in stage.parameters) && property.defaultValue !== null) {
|
|
177
|
-
this.useDefaultParameters[property.name] = true;
|
|
178
|
-
}
|
|
179
|
-
});
|
|
180
|
-
});
|
|
181
|
-
}
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
public addParameter(): void {
|
|
185
|
-
this.$uibModal
|
|
186
|
-
.open({
|
|
187
|
-
templateUrl: require('./modal/addParameter.html'),
|
|
188
|
-
controller: 'WerckerStageAddParameterCtrl',
|
|
189
|
-
controllerAs: 'ctrl',
|
|
190
|
-
})
|
|
191
|
-
.result.then((parameter: IParameter) => {
|
|
192
|
-
this.stage.parameters[parameter.key] = parameter.value;
|
|
193
|
-
})
|
|
194
|
-
.catch(() => {});
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
public removeParameter(key: string): void {
|
|
198
|
-
delete this.stage.parameters[key];
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
public shouldFilter(): boolean {
|
|
202
|
-
return this.jobs && this.jobs.length >= this.filterThreshold;
|
|
203
|
-
}
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
export const WERCKER_STAGE = 'spinnaker.core.pipeline.stage.werckerStage';
|
|
207
|
-
|
|
208
|
-
module(WERCKER_STAGE, [])
|
|
209
|
-
.config(() => {
|
|
210
|
-
Registry.pipeline.registerStage({
|
|
211
|
-
label: 'Wercker',
|
|
212
|
-
description: 'Runs a Wercker build pipeline',
|
|
213
|
-
key: 'wercker',
|
|
214
|
-
restartable: true,
|
|
215
|
-
controller: 'WerckerStageCtrl',
|
|
216
|
-
controllerAs: '$ctrl',
|
|
217
|
-
templateUrl: require('./werckerStage.html'),
|
|
218
|
-
executionDetailsUrl: require('./werckerExecutionDetails.html'),
|
|
219
|
-
executionLabelComponent: WerckerExecutionLabel,
|
|
220
|
-
extraLabelLines: (stage: IStage) => {
|
|
221
|
-
if (!stage.masterStage.context || !stage.masterStage.context.buildInfo) {
|
|
222
|
-
return 0;
|
|
223
|
-
}
|
|
224
|
-
const lines = stage.masterStage.context.buildInfo.number ? 1 : 0;
|
|
225
|
-
return lines + (stage.masterStage.context.buildInfo.testResults || []).length;
|
|
226
|
-
},
|
|
227
|
-
supportsCustomTimeout: true,
|
|
228
|
-
validators: [{ type: 'requiredField', fieldName: 'job' }],
|
|
229
|
-
strategy: true,
|
|
230
|
-
});
|
|
231
|
-
})
|
|
232
|
-
.controller('WerckerStageCtrl', WerckerStage);
|
|
@@ -1,122 +0,0 @@
|
|
|
1
|
-
import type { FormikProps } from 'formik';
|
|
2
|
-
import { uniq } from 'lodash';
|
|
3
|
-
import React from 'react';
|
|
4
|
-
|
|
5
|
-
import { RefreshableReactSelectInput } from '../RefreshableReactSelectInput';
|
|
6
|
-
import type { Application } from '../../../../application';
|
|
7
|
-
import type { IBaseBuildTriggerConfigProps } from '../baseBuild/BaseBuildTrigger';
|
|
8
|
-
import { BuildServiceType, IgorService } from '../../../../ci/igor.service';
|
|
9
|
-
import type { IWerckerTrigger } from '../../../../domain';
|
|
10
|
-
import { FormikFormField, ReactSelectInput, useLatestPromise } from '../../../../presentation';
|
|
11
|
-
|
|
12
|
-
export interface IWerckerTriggerConfigProps extends IBaseBuildTriggerConfigProps {
|
|
13
|
-
formik: FormikProps<IWerckerTrigger>;
|
|
14
|
-
trigger: IWerckerTrigger;
|
|
15
|
-
application: Application;
|
|
16
|
-
pipelineId: string;
|
|
17
|
-
triggerUpdated: (trigger: IWerckerTrigger) => void;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
// given a job name i.e., "git/organization/repo/job" or "pipeline/organization/repo/jobname"
|
|
21
|
-
// returns { app: 'organization/repo', pipeline: 'job' } or { app: 'organization/repo', pipeline: 'jobname' }
|
|
22
|
-
function getJobParts(job: string) {
|
|
23
|
-
const firstSlash = job.indexOf('/');
|
|
24
|
-
const lastSlash = job.lastIndexOf('/');
|
|
25
|
-
|
|
26
|
-
const app = job.substring(firstSlash + 1, lastSlash);
|
|
27
|
-
const pipeline = job.substring(lastSlash + 1);
|
|
28
|
-
return { app, pipeline };
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
export function WerckerTrigger(werckerTriggerProps: IWerckerTriggerConfigProps) {
|
|
32
|
-
const { formik } = werckerTriggerProps;
|
|
33
|
-
const { app, master, pipeline } = formik.values;
|
|
34
|
-
|
|
35
|
-
const fetchMasters = useLatestPromise(() => IgorService.listMasters(BuildServiceType.Wercker), []);
|
|
36
|
-
|
|
37
|
-
const mastersLoading = fetchMasters.status === 'PENDING';
|
|
38
|
-
const mastersLoaded = fetchMasters.status === 'RESOLVED';
|
|
39
|
-
|
|
40
|
-
const fetchJobs = useLatestPromise(() => {
|
|
41
|
-
return master && IgorService.listJobsForMaster(master).then((x) => x.map(getJobParts));
|
|
42
|
-
}, [master]);
|
|
43
|
-
|
|
44
|
-
const jobs = fetchJobs.result;
|
|
45
|
-
const jobsLoading = fetchJobs.status === 'PENDING';
|
|
46
|
-
const jobsLoaded = fetchJobs.status === 'RESOLVED';
|
|
47
|
-
|
|
48
|
-
const apps = React.useMemo(() => {
|
|
49
|
-
return jobsLoaded ? uniq(jobs.map((job) => job.app)) : [];
|
|
50
|
-
}, [jobsLoaded, jobs]);
|
|
51
|
-
|
|
52
|
-
const pipelines = React.useMemo(() => {
|
|
53
|
-
return jobsLoaded ? jobs.filter((parts) => parts.app === app).map((parts) => parts.pipeline) : [];
|
|
54
|
-
}, [jobsLoaded, app, jobs]);
|
|
55
|
-
|
|
56
|
-
// Clear out app or pipeline if they aren't in the fetched jobs data
|
|
57
|
-
React.useEffect(() => {
|
|
58
|
-
if (jobsLoaded && !!app && !apps.includes(app)) {
|
|
59
|
-
formik.setFieldValue('app', null);
|
|
60
|
-
}
|
|
61
|
-
if (jobsLoaded && !!pipeline && !pipelines.includes(pipeline)) {
|
|
62
|
-
formik.setFieldValue('pipeline', null);
|
|
63
|
-
}
|
|
64
|
-
}, [jobsLoaded, apps, app, pipelines, pipeline]);
|
|
65
|
-
|
|
66
|
-
// Update 'job' field when pipeline or app changes
|
|
67
|
-
React.useEffect(() => {
|
|
68
|
-
const hasJob = !!app && !!pipeline;
|
|
69
|
-
const job = hasJob ? `${app}/${pipeline}` : null;
|
|
70
|
-
formik.setFieldValue('job', job);
|
|
71
|
-
}, [pipeline, app]);
|
|
72
|
-
|
|
73
|
-
return (
|
|
74
|
-
<>
|
|
75
|
-
<FormikFormField
|
|
76
|
-
name="master"
|
|
77
|
-
label="Build Service"
|
|
78
|
-
input={(props) => (
|
|
79
|
-
<RefreshableReactSelectInput
|
|
80
|
-
{...props}
|
|
81
|
-
stringOptions={fetchMasters.result}
|
|
82
|
-
placeholder={'Select a build service...'}
|
|
83
|
-
disabled={!mastersLoaded}
|
|
84
|
-
isLoading={mastersLoading}
|
|
85
|
-
onRefreshClicked={() => fetchMasters.refresh()}
|
|
86
|
-
refreshButtonTooltipText={mastersLoading ? 'Masters refreshing' : 'Refresh masters list'}
|
|
87
|
-
/>
|
|
88
|
-
)}
|
|
89
|
-
/>
|
|
90
|
-
|
|
91
|
-
<FormikFormField
|
|
92
|
-
name="app"
|
|
93
|
-
label="Application"
|
|
94
|
-
input={(props) => (
|
|
95
|
-
<RefreshableReactSelectInput
|
|
96
|
-
{...props}
|
|
97
|
-
stringOptions={apps}
|
|
98
|
-
placeholder={'Select an application...'}
|
|
99
|
-
disabled={!master || !jobsLoaded}
|
|
100
|
-
isLoading={jobsLoading}
|
|
101
|
-
onRefreshClicked={() => fetchJobs.refresh()}
|
|
102
|
-
refreshButtonTooltipText={jobsLoading ? 'Apps refreshing' : 'Refresh app list'}
|
|
103
|
-
/>
|
|
104
|
-
)}
|
|
105
|
-
/>
|
|
106
|
-
|
|
107
|
-
<FormikFormField
|
|
108
|
-
name="pipeline"
|
|
109
|
-
label="Pipeline"
|
|
110
|
-
input={(props) => (
|
|
111
|
-
<ReactSelectInput
|
|
112
|
-
{...props}
|
|
113
|
-
disabled={!master || !jobsLoaded}
|
|
114
|
-
isLoading={jobsLoading}
|
|
115
|
-
stringOptions={pipelines}
|
|
116
|
-
placeholder="Select a pipeline"
|
|
117
|
-
/>
|
|
118
|
-
)}
|
|
119
|
-
/>
|
|
120
|
-
</>
|
|
121
|
-
);
|
|
122
|
-
}
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
|
-
|
|
3
|
-
import { BaseBuildTriggerTemplate } from '../baseBuild/BaseBuildTriggerTemplate';
|
|
4
|
-
import { BuildServiceType } from '../../../../ci';
|
|
5
|
-
import type { ITriggerTemplateComponentProps } from '../../../manualExecution/TriggerTemplate';
|
|
6
|
-
|
|
7
|
-
export class WerckerTriggerTemplate extends React.Component<ITriggerTemplateComponentProps> {
|
|
8
|
-
public static formatLabel = BaseBuildTriggerTemplate.formatLabel;
|
|
9
|
-
|
|
10
|
-
public render() {
|
|
11
|
-
return <BaseBuildTriggerTemplate {...this.props} buildTriggerType={BuildServiceType.Wercker} />;
|
|
12
|
-
}
|
|
13
|
-
}
|