Skip to content

Commit

Permalink
fix(artifacts): Exclude unmatchable expected artifact types (#6709)
Browse files Browse the repository at this point in the history
* Exclude front50 artifact account from trigger artifact constraints.
* Exclude front50, docker, and k8s artifact accounts from CF deploy stage configuration.
* Constrain artifact accounts for match artifact by trigger type
* Assign type to ArtifactTypePatterns
  • Loading branch information
jkschneider authored Mar 20, 2019
1 parent 33986e0 commit 03fa0d9
Show file tree
Hide file tree
Showing 17 changed files with 91 additions and 19 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {
StageConfigField,
StageArtifactSelector,
IArtifact,
ArtifactTypePatterns,
} from '@spinnaker/core';

import { CreateServiceInstanceDirectInput } from './CreateServiceInstanceDirectInput';
Expand Down Expand Up @@ -148,6 +149,11 @@ export class CloudfoundryDeployServiceStageConfig extends React.Component<
pipeline={pipeline}
stage={stage}
expectedArtifactId={manifest.artifactId}
excludedArtifactTypePatterns={[
ArtifactTypePatterns.KUBERNETES,
ArtifactTypePatterns.FRONT50_PIPELINE_TEMPLATE,
ArtifactTypePatterns.DOCKER_IMAGE,
]}
artifact={manifest.artifact}
onExpectedArtifactSelected={this.onExpectedArtifactSelected}
onArtifactEdited={this.onArtifactChanged}
Expand Down
11 changes: 10 additions & 1 deletion app/scripts/modules/core/src/artifact/ArtifactTypes.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
export const ArtifactTypePatterns = {
export interface IArtifactTypePatterns {
[typeName: string]: RegExp;
}

export const ArtifactTypePatterns: IArtifactTypePatterns = {
BITBUCKET_FILE: /bitbucket\/file/,
DOCKER_IMAGE: /docker\/image/,
EMBEDDED_BASE64: /embedded\/base64/,
Expand All @@ -15,3 +19,8 @@ export const ArtifactTypePatterns = {
HTTP_FILE: /http\/file/,
FRONT50_PIPELINE_TEMPLATE: /front50\/pipelineTemplate/,
};

export const excludeAllTypesExcept = (...types: RegExp[]) =>
Object.keys(ArtifactTypePatterns)
.map(k => ArtifactTypePatterns[k])
.filter(type => !types.includes(type));
Original file line number Diff line number Diff line change
Expand Up @@ -17,19 +17,22 @@ export interface IExpectedArtifactModalProps extends IModalComponentProps {
expectedArtifact?: IExpectedArtifact;
pipeline: IPipeline;
excludedArtifactTypePatterns?: RegExp[];
excludedDefaultArtifactTypePatterns?: RegExp[];
}

export interface IExpectedArtifactModalState {
taskMonitor: TaskMonitor;
artifactAccounts: IArtifactAccount[];
matchArtifactAccounts: IArtifactAccount[];
defaultArtifactAccounts: IArtifactAccount[];
}

export class ExpectedArtifactModal extends React.Component<IExpectedArtifactModalProps, IExpectedArtifactModalState> {
constructor(props: IExpectedArtifactModalProps) {
super(props);

this.state = {
artifactAccounts: [],
matchArtifactAccounts: [],
defaultArtifactAccounts: [],
taskMonitor: new TaskMonitor({ title: "I'm never used" }),
};
}
Expand All @@ -40,12 +43,21 @@ export class ExpectedArtifactModal extends React.Component<IExpectedArtifactModa
};

public componentDidMount(): void {
const excludedPatterns = this.props.excludedArtifactTypePatterns;
const { excludedArtifactTypePatterns, excludedDefaultArtifactTypePatterns } = this.props;
AccountService.getArtifactAccounts().then(artifactAccounts => {
this.setState({
artifactAccounts: excludedPatterns
matchArtifactAccounts: excludedArtifactTypePatterns
? artifactAccounts.filter(
account => !account.types.some(typ => excludedPatterns.some(typPattern => typPattern.test(typ))),
account =>
!account.types.some(typ => excludedArtifactTypePatterns.some(typPattern => typPattern.test(typ))),
)
: artifactAccounts,
defaultArtifactAccounts: excludedDefaultArtifactTypePatterns
? artifactAccounts.filter(
account =>
!account.types.some(typ =>
excludedDefaultArtifactTypePatterns.some(typPattern => typPattern.test(typ)),
),
)
: artifactAccounts,
});
Expand All @@ -63,7 +75,7 @@ export class ExpectedArtifactModal extends React.Component<IExpectedArtifactModa
};

public render(): React.ReactNode {
const { artifactAccounts } = this.state;
const { matchArtifactAccounts, defaultArtifactAccounts } = this.state;
return (
<WizardModal<IExpectedArtifact>
heading="Expected Artifact"
Expand Down Expand Up @@ -95,7 +107,7 @@ export class ExpectedArtifactModal extends React.Component<IExpectedArtifactModa
<ArtifactEditor
pipeline={this.props.pipeline}
artifact={formik.values.matchArtifact}
artifactAccounts={artifactAccounts}
artifactAccounts={matchArtifactAccounts}
onArtifactEdit={(artifact: IArtifact) => this.editArtifact(formik, 'matchArtifact', artifact)}
isDefault={false}
/>
Expand Down Expand Up @@ -126,7 +138,7 @@ export class ExpectedArtifactModal extends React.Component<IExpectedArtifactModa
<ArtifactEditor
pipeline={this.props.pipeline}
artifact={formik.values.defaultArtifact}
artifactAccounts={artifactAccounts}
artifactAccounts={defaultArtifactAccounts}
onArtifactEdit={(artifact: IArtifact) => this.editArtifact(formik, 'defaultArtifact', artifact)}
isDefault={true}
/>
Expand Down
1 change: 1 addition & 0 deletions app/scripts/modules/core/src/domain/ITrigger.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ export interface ITrigger {
type: string;
expectedArtifactIds?: string[]; // uuid references to ExpectedArtifacts defined in the Pipeline.
runAsUser?: string;
excludedArtifactTypePatterns?: RegExp[];
}

export interface IArtifactoryTrigger extends ITrigger {
Expand Down
1 change: 1 addition & 0 deletions app/scripts/modules/core/src/domain/ITriggerTypeConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,5 @@ export interface IExecutionTriggerStatusComponentProps {
export interface ITriggerTypeConfig extends IStageOrTriggerTypeConfig {
executionStatusComponent?: React.ComponentType<IExecutionTriggerStatusComponentProps>;
executionTriggerLabel?: (trigger: ITrigger) => string;
excludedArtifactTypePatterns?: RegExp[];
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ export const ProducesArtifacts: React.SFC<IProducesArtifactsProps> = props => {
expectedArtifact: artifact,
pipeline: pipeline,
excludedArtifactTypePatterns: excludedArtifactTypePatterns,
excludedDefaultArtifactTypePatterns: excludedArtifactTypePatterns,
}).then((editedArtifact: IExpectedArtifact) => {
const editIndex = produces.findIndex(a => a.id === editedArtifact.id);
const producesAfterEdit = produces.slice(0);
Expand All @@ -39,6 +40,7 @@ export const ProducesArtifacts: React.SFC<IProducesArtifactsProps> = props => {
ExpectedArtifactModal.show({
pipeline: pipeline,
excludedArtifactTypePatterns: excludedArtifactTypePatterns,
excludedDefaultArtifactTypePatterns: excludedArtifactTypePatterns,
}).then((artifact: IExpectedArtifact) => {
const producesAfterNew = produces.slice(0);
producesAfterNew.push(artifact);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import { Registry } from 'core/registry';
import { ArtifactoryTriggerConfig } from './ArtifactoryTriggerConfig';
import { ArtifactTypePatterns, excludeAllTypesExcept } from 'core/artifact';

Registry.pipeline.registerTrigger({
label: 'Artifactory',
description: 'Executes the pipeline on an Artifactory repo update',
key: 'artifactory',
component: ArtifactoryTriggerConfig,
validators: [],
excludedArtifactTypePatterns: excludeAllTypesExcept(ArtifactTypePatterns.MAVEN_FILE),
});
Original file line number Diff line number Diff line change
Expand Up @@ -6,44 +6,63 @@ import Select from 'react-select';
import { react2angular } from 'react2angular';

import { ArtifactTypePatterns, ExpectedArtifactModal, ExpectedArtifactService } from 'core/artifact';
import { IExpectedArtifact, IPipeline } from 'core/domain';
import { IExpectedArtifact, IPipeline, ITrigger } from 'core/domain';
import { Registry } from 'core/registry';

export interface ITriggerArtifactConstraintSelectorProps {
pipeline: IPipeline;
artifactReferer: any; // the object referring to a set of expected artifacts
trigger: ITrigger;
selected?: string[]; // expected artifact ids
onDefineExpectedArtifact: (artifact: IExpectedArtifact) => void;
onChangeSelected: (selected: string[], referer: any) => void;
}

export class TriggerArtifactConstraintSelector extends React.Component<ITriggerArtifactConstraintSelectorProps> {
private defaultExcludedArtifactTypePatterns = [
ArtifactTypePatterns.KUBERNETES,
ArtifactTypePatterns.FRONT50_PIPELINE_TEMPLATE,
];

private excludedArtifactTypes = () => {
const triggerConfig = Registry.pipeline
.getTriggerTypes()
.filter(config => config.key === this.props.trigger.type)
.pop();
return this.defaultExcludedArtifactTypePatterns.concat(
(triggerConfig && triggerConfig.excludedArtifactTypePatterns) || [],
);
};

private handleChange = (index: number, selectedArtifact: IExpectedArtifact) => {
if (selectedArtifact.id === '__create.new.artifact') {
ExpectedArtifactModal.show({
pipeline: this.props.pipeline,
excludedArtifactTypePatterns: [ArtifactTypePatterns.KUBERNETES, ArtifactTypePatterns.FRONT50_PIPELINE_TEMPLATE],
excludedArtifactTypePatterns: this.excludedArtifactTypes(),
excludedDefaultArtifactTypePatterns: this.defaultExcludedArtifactTypePatterns,
}).then(this.props.onDefineExpectedArtifact);
return;
}

const selected = (this.props.selected || []).slice(0);
selected[index] = selectedArtifact.id;
this.props.onChangeSelected(selected, this.props.artifactReferer);
this.props.onChangeSelected(selected, this.props.trigger);
};

private removeExpectedArtifact = (artifact: IExpectedArtifact) => {
const selected = (this.props.selected || []).slice(0);
selected.splice(selected.findIndex(artifactId => artifact.id === artifactId), 1);
this.props.onChangeSelected(selected, this.props.artifactReferer);
this.props.onChangeSelected(selected, this.props.trigger);
};

private editExpectedArtifact = (artifact: IExpectedArtifact) => {
ExpectedArtifactModal.show({
expectedArtifact: artifact,
pipeline: this.props.pipeline,
excludedArtifactTypePatterns: this.excludedArtifactTypes(),
excludedDefaultArtifactTypePatterns: this.defaultExcludedArtifactTypePatterns,
}).then((editedArtifact: IExpectedArtifact) => {
this.props.onDefineExpectedArtifact(editedArtifact);
this.props.onChangeSelected(this.props.selected, this.props.artifactReferer);
this.props.onChangeSelected(this.props.selected, this.props.trigger);
});
};

Expand Down Expand Up @@ -102,7 +121,7 @@ module(TRIGGER_ARTIFACT_CONSTRAINT_SELECTOR_REACT, []).component(
'triggerArtifactConstraintSelectorReact',
react2angular(TriggerArtifactConstraintSelector, [
'pipeline',
'artifactReferer',
'trigger',
'selected',
'onDefineExpectedArtifact',
'onChangeSelected',
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
import { Registry } from 'core/registry';
import { ConcourseTriggerConfig } from './ConcourseTriggerConfig';
import { ArtifactTypePatterns } from 'core/artifact';

Registry.pipeline.registerTrigger({
label: 'Concourse',
description: 'Listens to a Concourse job',
key: 'concourse',
component: ConcourseTriggerConfig,
excludedArtifactTypePatterns: [ArtifactTypePatterns.JENKINS_FILE],
validators: [
{
type: 'requiredField',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

const angular = require('angular');

import { ArtifactTypePatterns } from 'core/artifact';
import { UUIDGenerator } from 'core/utils/uuid.service';
import { Registry } from 'core/registry';
import { ServiceAccountReader } from 'core/serviceAccount/ServiceAccountReader';
Expand All @@ -24,6 +25,7 @@ module.exports = angular
controllerAs: 'vm',
templateUrl: require('./cronTrigger.html'),
executionTriggerLabel: trigger => trigger.cronExpression,
excludedArtifactTypePatterns: [ArtifactTypePatterns.JENKINS_FILE],
validators: [
{
type: 'serviceAccountAccess',
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { IController, IScope, module } from 'angular';
import { has, trim } from 'lodash';

import { ArtifactTypePatterns, excludeAllTypesExcept } from 'core/artifact';
import { SETTINGS } from 'core/config/settings';
import { IGitTrigger } from 'core/domain/ITrigger';
import { Registry } from 'core/registry';
Expand Down Expand Up @@ -76,6 +77,11 @@ module(GIT_TRIGGER, [])
controllerAs: 'vm',
templateUrl: require('./gitTrigger.html'),
executionStatusComponent: GitTriggerExecutionStatus,
excludedArtifactTypePatterns: excludeAllTypesExcept(
ArtifactTypePatterns.GITHUB_FILE,
ArtifactTypePatterns.GITLAB_FILE,
ArtifactTypePatterns.BITBUCKET_FILE,
),
validators: [
{
type: 'serviceAccountAccess',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import _ from 'lodash';
const angular = require('angular');

import { ArtifactTypePatterns } from 'core/artifact';
import { ServiceAccountReader } from 'core/serviceAccount/ServiceAccountReader';
import { ApplicationReader } from 'core/application/service/ApplicationReader';
import { PipelineConfigService } from 'core/pipeline/config/services/PipelineConfigService';
Expand All @@ -23,6 +24,7 @@ module.exports = angular
templateUrl: require('./pipelineTrigger.html'),
manualExecutionComponent: PipelineTriggerTemplate,
executionStatusComponent: ExecutionUserStatus,
excludedArtifactTypePatterns: [ArtifactTypePatterns.JENKINS_FILE],
executionTriggerLabel: () => 'Pipeline',
});
})
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { IController, module } from 'angular';

import { ArtifactTypePatterns } from 'core/artifact';
import { IPubsubSubscription, IPubsubTrigger } from 'core/domain';
import { PubsubSubscriptionReader } from 'core/pubsub';
import { Registry } from 'core/registry';
Expand Down Expand Up @@ -50,6 +51,7 @@ module(PUBSUB_TRIGGER, [])
controller: 'PubsubTriggerCtrl',
controllerAs: 'vm',
templateUrl: require('./pubsubTrigger.html'),
excludedArtifactTypePatterns: [ArtifactTypePatterns.JENKINS_FILE],
validators: [],
});
})
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import { IController, IScope, module } from 'angular';

import { ArtifactTypePatterns } from 'core/artifact';
import { IgorService, BuildServiceType } from 'core/ci/igor.service';
import { Registry } from 'core/registry';
import { ServiceAccountReader } from 'core/serviceAccount/ServiceAccountReader';
import { IBuildTrigger } from 'core/domain/ITrigger';
import { SETTINGS } from 'core/config/settings';

import { SETTINGS } from 'core/config/settings';
import { TravisTriggerTemplate } from './TravisTriggerTemplate';

export interface ITravisTriggerViewState {
Expand Down Expand Up @@ -90,6 +91,7 @@ module(TRAVIS_TRIGGER, [require('../trigger.directive').name])
templateUrl: require('./travisTrigger.html'),
manualExecutionComponent: TravisTriggerTemplate,
providesVersionForBake: true,
excludedArtifactTypePatterns: [ArtifactTypePatterns.JENKINS_FILE],
validators: [
{
type: 'requiredField',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@
<div class="col-md-9 row">
<trigger-artifact-constraint-selector-react
pipeline="pipeline"
artifact-referer="trigger"
trigger="trigger"
selected="trigger.expectedArtifactIds"
on-define-expected-artifact="triggerCtrl.defineExpectedArtifact"
on-change-selected="triggerCtrl.changeExpectedArtifacts"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { IController, module } from 'angular';

import { ArtifactTypePatterns } from 'core/artifact';
import { IWebhookTrigger } from 'core/domain';
import { Registry } from 'core/registry';
import { ServiceAccountReader } from 'core/serviceAccount/ServiceAccountReader';
Expand Down Expand Up @@ -32,6 +33,7 @@ module(WEBHOOK_TRIGGER, [])
controller: 'WebhookTriggerCtrl',
controllerAs: 'ctrl',
templateUrl: require('./webhookTrigger.html'),
excludedArtifactTypePatterns: [ArtifactTypePatterns.JENKINS_FILE],
validators: [
{
type: 'serviceAccountAccess',
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import { IController, IScope, module } from 'angular';

import { ArtifactTypePatterns } from 'core/artifact';
import { IgorService, BuildServiceType } from 'core/ci/igor.service';
import { Registry } from 'core/registry';
import { ServiceAccountReader } from 'core/serviceAccount/ServiceAccountReader';
import { IWerckerTrigger } from 'core/domain/ITrigger';
import { SETTINGS } from 'core/config/settings';

import { SETTINGS } from 'core/config/settings';
import { WerckerTriggerTemplate } from './WerckerTriggerTemplate';

export interface IWerckerTriggerViewState {
Expand Down Expand Up @@ -140,6 +141,7 @@ module(WERCKER_TRIGGER, [require('../trigger.directive').name])
controllerAs: '$ctrl',
templateUrl: require('./werckerTrigger.html'),
manualExecutionComponent: WerckerTriggerTemplate,
excludedArtifactTypePatterns: [ArtifactTypePatterns.JENKINS_FILE],
validators: [
{
type: 'requiredField',
Expand Down

0 comments on commit 03fa0d9

Please sign in to comment.