Skip to content

Commit

Permalink
feat(provider/appengine): enable artifacts as config files (#5888)
Browse files Browse the repository at this point in the history
  • Loading branch information
Scott committed Oct 24, 2018
1 parent c6a5937 commit 0a6d3f9
Show file tree
Hide file tree
Showing 14 changed files with 250 additions and 37 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {
IGitTrigger,
IPipeline,
IStage,
IArtifactAccountPair,
} from '@spinnaker/core';

import {
Expand All @@ -28,6 +29,7 @@ export interface IAppengineServerGroupCommand {
freeFormDetails?: string;
configFilepaths?: string[];
configFiles?: string[];
configArtifacts?: IArtifactAccountPair[];
applicationDirectoryRoot: string;
branch?: string;
repositoryUrl?: string;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,5 +56,45 @@
<span class="glyphicon glyphicon-plus-sign"></span> Add Config File
</button>
</div>
<div ng-repeat="artifact in $ctrl.command.configArtifacts track by $index" class="artifact-configuration-section col-md-12" ng-class="{ 'last-entry': $last }">
<div class="col-md-7 col-md-offset-3">
<expected-artifact-selector-react
expected-artifacts="artifact.delegate.expectedArtifacts"
selected="artifact.delegate.getSelectedExpectedArtifact()"
on-change="artifact.controller.onArtifactChange"
on-request-create="artifact.controller.onRequestCreate"
requesting-new="artifact.delegate.requestingNew"
>
</expected-artifact-selector-react>
<div ng-if="!artifact.delegate.requestingNew">
<artifact-account-selector-react
accounts="artifact.controller.accountsForArtifact"
selected="artifact.delegate.getSelectedAccount()"
on-change="artifact.controller.onAccountChange"
>
</artifact-account-selector-react>
</div>
</div>
<expected-artifact-editor-react ng-if="artifact.delegate.requestingNew"
kinds="artifact.delegate.getSupportedArtifactKinds()"
sources="artifact.delegate.getExpectedArtifactSources()"
accounts="artifact.delegate.getExpectedArtifactAccounts()"
on-save="artifact.controller.onArtifactCreated"
field-columns="7"
field-group-class-name="''"
single-column="true"
>
</expected-artifact-editor-react>
<div class="col-md-1">
<button type="button" class="btn btn-sm btn-default" ng-click="$ctrl.deleteConfigArtifact($index)">
<span class="glyphicon glyphicon-trash"></span> Delete
</button>
</div>
</div>
<div class="col-md-7 col-md-offset-3">
<button class="btn btn-block btn-add-trigger add-new" ng-click="$ctrl.addConfigArtifact()">
<span class="glyphicon glyphicon-plus-sign"></span> Add Config Artifact
</button>
</div>
</div>
</div>
Original file line number Diff line number Diff line change
@@ -1,23 +1,68 @@
import { IController, module } from 'angular';
import { module, IController, IScope } from 'angular';
import { AppengineSourceType } from '../serverGroupCommandBuilder.service';
import {
AccountService,
ExpectedArtifactSelectorViewController,
NgAppengineConfigArtifactDelegate,
IArtifactAccount,
IArtifactAccountPair,
} from '@spinnaker/core';

import './serverGroupWizard.less';

export interface IAppengineConfigFileConfigurerCtrlCommand {
configFiles: string[];
configArtifacts: ConfigArtifact[];
sourceType: string;
}

class AppengineConfigFileConfigurerCtrl implements IController {
public command: { configFiles: string[]; sourceType: string };
private artifactAccounts: IArtifactAccount[] = [];
public command: IAppengineConfigFileConfigurerCtrlCommand;

constructor(public $scope: IScope) {}

public $onInit(): void {
if (!this.command.configFiles) {
this.command.configFiles = [];
}
if (!this.command.configArtifacts) {
this.command.configArtifacts = [];
}
if (!this.$scope.command) {
this.$scope.command = this.command;
}
this.command.configArtifacts = this.command.configArtifacts.map(artifactAccountPair => {
return new ConfigArtifact(this.$scope, artifactAccountPair);
});
AccountService.getArtifactAccounts().then((accounts: IArtifactAccount[]) => {
this.artifactAccounts = accounts;
this.command.configArtifacts.forEach((a: ConfigArtifact) => {
a.delegate.setAccounts(accounts);
a.controller.updateAccounts(a.delegate.getSelectedExpectedArtifact());
});
});
}

public addConfigFile(): void {
this.command.configFiles.push('');
}

public addConfigArtifact(): void {
const artifact = new ConfigArtifact(this.$scope, { id: '', account: '' });
artifact.delegate.setAccounts(this.artifactAccounts);
artifact.controller.updateAccounts(artifact.delegate.getSelectedExpectedArtifact());
this.command.configArtifacts.push(artifact);
}

public deleteConfigFile(index: number): void {
this.command.configFiles.splice(index, 1);
}

public deleteConfigArtifact(index: number): void {
this.command.configArtifacts.splice(index, 1);
}

public mapTabToSpaces(event: any) {
if (event.which === 9) {
event.preventDefault();
Expand All @@ -33,6 +78,25 @@ class AppengineConfigFileConfigurerCtrl implements IController {
}
}

class ConfigArtifact implements IArtifactAccountPair {
public $scope: IScope;
public controller: ExpectedArtifactSelectorViewController;
public delegate: NgAppengineConfigArtifactDelegate;
public id: string;
public account: string;

constructor($scope: IScope, artifact = { id: '', account: '' }) {
const unserializable = { configurable: false, enumerable: false, writable: false };
this.id = artifact.id;
this.account = artifact.account;
Object.defineProperty(this, '$scope', { ...unserializable, value: $scope });
const delegate = new NgAppengineConfigArtifactDelegate(this);
const controller = new ExpectedArtifactSelectorViewController(delegate);
Object.defineProperty(this, 'delegate', { ...unserializable, value: delegate });
Object.defineProperty(this, 'controller', { ...unserializable, value: controller });
}
}

class AppengineConfigFileConfigurerComponent implements ng.IComponentOptions {
public bindings: any = { command: '=' };
public controller: any = AppengineConfigFileConfigurerCtrl;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
.appengine-server-group-wizard {
input[type="checkbox"] {
margin-top: .75rem;
input[type='checkbox'] {
margin-top: 0.75rem;
}

help-field.help-field-absolute {
Expand All @@ -10,4 +10,19 @@
right: 2px;
}
}

.artifact-configuration-section {
border-bottom: 1px solid #eee;
padding: 0 0 4px 0;
margin: 0 0 5px 0;

&.last-entry {
border-bottom: none;
}

.Select,
input {
margin: 0 0 1px;
}
}
}
4 changes: 3 additions & 1 deletion app/scripts/modules/appengine/src/serverGroup/transformer.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { module } from 'angular';

import { IServerGroup } from '@spinnaker/core';
import { IServerGroup, IArtifactAccountPair } from '@spinnaker/core';

import { GitCredentialType, IAppengineGitTrigger, IAppengineJenkinsTrigger } from 'appengine/domain/index';
import { IAppengineServerGroupCommand } from './configure/serverGroupCommandBuilder.service';
Expand All @@ -17,6 +17,7 @@ export class AppengineDeployDescription {
public branch: string;
public configFilepaths: string[];
public configFiles: string[];
public configArtifacts: IArtifactAccountPair[];
public applicationDirectoryRoot: string;
public promote?: boolean;
public stopPreviousVersion?: boolean;
Expand Down Expand Up @@ -55,6 +56,7 @@ export class AppengineDeployDescription {
this.trigger = command.trigger;
this.gitCredentialType = command.gitCredentialType;
this.configFiles = command.configFiles;
this.configArtifacts = command.configArtifacts.filter(a => !!a.id);
this.applicationDirectoryRoot = command.applicationDirectoryRoot;
this.interestingHealthProviderNames = command.interestingHealthProviderNames || [];
this.expectedArtifactId = command.expectedArtifactId;
Expand Down
4 changes: 4 additions & 0 deletions app/scripts/modules/core/src/artifact/IArtifactAccountPair.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export interface IArtifactAccountPair {
id: string;
account: string;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
import { IScope } from 'angular';
import { get } from 'lodash';
import {
ExpectedArtifactService,
Registry,
IExpectedArtifact,
IArtifactAccount,
IArtifactSource,
IExpectedArtifactSelectorViewControllerDelegate,
IStage,
IPipeline,
} from 'core';
import { ExpectedArtifactSelectorViewControllerAngularDelegate } from './ExpectedArtifactSelectorViewControllerAngularDelegate';

export class NgAppengineConfigArtifactDelegate
extends ExpectedArtifactSelectorViewControllerAngularDelegate<IArtifactSource<IStage | IPipeline>>
implements IExpectedArtifactSelectorViewControllerDelegate {
public expectedArtifacts: IExpectedArtifact[];
public requestingNew = false;

private getStage() {
return get(this, 'artifact.$scope.command.viewState.stage', null);
}

private getPipeline() {
return get(this, 'artifact.$scope.command.viewState.pipeline', null);
}

constructor(private artifact: { $scope: IScope; id: string; account: string }) {
super(artifact.$scope);
this.refreshExpectedArtifacts();
this.sources = ExpectedArtifactService.sourcesForPipelineStage(() => this.getPipeline(), this.getStage());
this.kinds = Registry.pipeline.getArtifactKinds().filter(a => a.isMatch);
}

public setAccounts = (accounts: any) => {
this.accounts = [...accounts];
};

public getExpectedArtifacts(): IExpectedArtifact[] {
return ExpectedArtifactService.getExpectedArtifactsAvailableToStage(this.getStage(), this.getPipeline());
}

public getSelectedExpectedArtifact(): IExpectedArtifact {
return this.expectedArtifacts.find(ea => ea.id === this.artifact.id);
}

public getSelectedAccount(): IArtifactAccount {
return this.accounts.find(a => a.name === this.artifact.account);
}

public setSelectedExpectedArtifact(e: IExpectedArtifact): void {
this.artifact.id = e.id;
this.requestingNew = false;
this.scopeApply();
}

public setSelectedArtifactAccount(a: IArtifactAccount): void {
if (a == null) {
this.artifact.account = '';
} else {
this.artifact.account = a.name;
}
this.scopeApply();
}

public createArtifact(): void {
this.requestingNew = true;
this.scopeApply();
}

public refreshExpectedArtifacts(): void {
this.expectedArtifacts = this.getExpectedArtifacts();
}
}
2 changes: 2 additions & 0 deletions app/scripts/modules/core/src/artifact/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,5 @@ export * from './NgManifestArtifactDelegate';
export * from './NgGCEImageArtifactDelegate';
export * from './NgAppEngineDeployArtifactDelegate';
export * from './NgBakeManifestArtifactDelegate';
export * from './IArtifactAccountPair';
export * from './NgAppengineConfigArtifactDelegate';
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ export interface IExpectedArtifactEditorProps {
showIcons?: boolean;
showAccounts?: boolean;
className?: string;
fieldGroupClassName?: string;
fieldColumns: number;
singleColumn: boolean;
}
Expand Down Expand Up @@ -114,7 +115,7 @@ export class ExpectedArtifactEditor extends React.Component<
};

public render() {
const { sources, showIcons, showAccounts, fieldColumns, singleColumn } = this.props;
const { sources, showIcons, showAccounts, fieldColumns, singleColumn, fieldGroupClassName } = this.props;
const { expectedArtifact, source, account } = this.state;
const accounts = this.accountsForExpectedArtifact(expectedArtifact);
const artifact = ExpectedArtifactService.artifactFromExpected(expectedArtifact);
Expand All @@ -123,10 +124,10 @@ export class ExpectedArtifactEditor extends React.Component<
const EditCmp = kind && kind.editCmp;
return (
<>
<StageConfigField label="Artifact Source" fieldColumns={fieldColumns}>
<StageConfigField label="Artifact Source" fieldColumns={fieldColumns} groupClassName={fieldGroupClassName}>
<ExpectedArtifactSourceSelector sources={sources} selected={source} onChange={this.onSourceChange} />
</StageConfigField>
<StageConfigField label="Artifact Kind" fieldColumns={fieldColumns}>
<StageConfigField label="Artifact Kind" fieldColumns={fieldColumns} groupClassName={fieldGroupClassName}>
<ExpectedArtifactKindSelector
kinds={kinds}
selected={kind}
Expand All @@ -135,7 +136,7 @@ export class ExpectedArtifactEditor extends React.Component<
/>
</StageConfigField>
{showAccounts && (
<StageConfigField label="Artifact Account" fieldColumns={fieldColumns}>
<StageConfigField label="Artifact Account" fieldColumns={fieldColumns} groupClassName={fieldGroupClassName}>
<ArtifactAccountSelector accounts={accounts} selected={account} onChange={this.onAccountChange} />
</StageConfigField>
)}
Expand All @@ -146,9 +147,10 @@ export class ExpectedArtifactEditor extends React.Component<
labelColumns={3}
fieldColumns={fieldColumns}
singleColumn={singleColumn}
groupClassName={fieldGroupClassName}
/>
)}
<StageConfigField label="" fieldColumns={fieldColumns}>
<StageConfigField label="" fieldColumns={fieldColumns} groupClassName={fieldGroupClassName}>
<button onClick={this.onSave} className="btn btn-block btn-primary btn-sm">
Confirm
</button>
Expand All @@ -175,5 +177,6 @@ module(EXPECTED_ARTIFACT_EDITOR_COMPONENT_REACT, [
'className',
'fieldColumns',
'singleColumn',
'fieldGroupClassName',
]),
);
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,5 @@ export interface IArtifactEditorProps {
labelColumns: number;
fieldColumns: number;
singleColumn?: boolean;
groupClassName?: string;
}
Loading

0 comments on commit 0a6d3f9

Please sign in to comment.