Skip to content

Commit afe8538

Browse files
committed
feat(deployment): add a few things to enable auto-deployments
- add ability to auto-deploy with critical errors - add ability to fast-forward to latest feed version in deployment - add ability to pin versions in deployments
1 parent 7b234ee commit afe8538

File tree

14 files changed

+672
-208
lines changed

14 files changed

+672
-208
lines changed

__tests__/test-utils/mock-data/manager.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ export function makeMockDeployment (
5555
osmExtractUrl: null,
5656
otpCommit: null,
5757
otpVersion: null,
58+
pinnedfeedVersionIds: [],
5859
projectId: project.id,
5960
projectBounds: {east: 0, west: 0, north: 0, south: 0},
6061
routerId: null,
@@ -70,6 +71,8 @@ export const mockProject = {
7071
autoFetchHour: 0,
7172
autoFetchMinute: 0,
7273
autoDeploy: false,
74+
autoDeployTypes: [],
75+
autoDeployWithCriticalErrors: false,
7376
bounds: null,
7477
buildConfig: {
7578
fares: null,

i18n/english.yml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,12 @@ components:
141141
title: Deployments
142142
DeploymentsPanel:
143143
autoDeploy:
144+
deployWithErrors:
145+
checklabel: Deploy even if some feed versions have critical errors
146+
help: >
147+
If this is unchecked, an auto-deployment will halt if any of the feed
148+
versions in the deployment have at least one critical error
149+
title: Critical Errors Handling
144150
help: >
145151
A deployment will automatically be kicked off (assuming there are no
146152
critical errors) whenever one of the above-defined events occurs.

lib/manager/actions/__tests__/__snapshots__/projects.js.snap

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ Object {
66
"all": Array [
77
Object {
88
"autoDeploy": false,
9+
"autoDeployTypes": Array [],
10+
"autoDeployWithCriticalErrors": false,
911
"autoFetchFeeds": true,
1012
"autoFetchHour": 0,
1113
"autoFetchMinute": 0,
@@ -110,6 +112,7 @@ Object {
110112
"osmExtractUrl": null,
111113
"otpCommit": null,
112114
"otpVersion": null,
115+
"pinnedfeedVersionIds": Array [],
113116
"projectBounds": Object {
114117
"east": 0,
115118
"north": 0,

lib/manager/actions/deployments.js

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,23 @@ export function createDeploymentFromFeedSource (feedSource: Feed) {
209209
}
210210
}
211211

212+
export function togglePinFeedVersion (
213+
deployment: Deployment,
214+
version: SummarizedFeedVersion
215+
) {
216+
return function (dispatch: dispatchFn, getState: getStateFn) {
217+
let pinnedfeedVersionIds
218+
if (deployment.pinnedfeedVersionIds.indexOf(version.id) > -1) {
219+
pinnedfeedVersionIds = deployment.pinnedfeedVersionIds.filter(
220+
id => id !== version.id
221+
)
222+
} else {
223+
pinnedfeedVersionIds = [...deployment.pinnedfeedVersionIds, version.id]
224+
}
225+
dispatch(updateDeployment(deployment, {pinnedfeedVersionIds}))
226+
}
227+
}
228+
212229
export function updateDeployment (
213230
deployment: Deployment,
214231
changes: any // using the any type because $Shape<Deployment> was giving
Lines changed: 13 additions & 157 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,16 @@
11
// @flow
22

33
import React, {Component} from 'react'
4-
import {Table, Button, Badge, Glyphicon, ButtonToolbar} from 'react-bootstrap'
5-
import { Link } from 'react-router'
4+
import {Table} from 'react-bootstrap'
65

7-
import * as deploymentActions from '../../actions/deployments'
86
import {getComponentMessages} from '../../../common/util/config'
9-
import {formatTimestamp, fromNow} from '../../../common/util/date-time'
10-
import {versionHasExpired, versionHasNotBegun} from '../../util/version'
7+
import FeedVersionTableRow from './FeedVersionTableRow'
118

12-
import type {Deployment, Feed, Project, SummarizedFeedVersion} from '../../../types'
13-
import type {ManagerUserState} from '../../../types/reducers'
9+
import type {Deployment, Project, SummarizedFeedVersion} from '../../../types'
1410

1511
type Props = {
16-
deleteFeedVersion: typeof deploymentActions.deleteFeedVersion,
1712
deployment: Deployment,
1813
project: Project,
19-
updateVersionForFeedSource: typeof deploymentActions.updateVersionForFeedSource,
20-
user: ManagerUserState,
2114
versions: Array<SummarizedFeedVersion>
2215
}
2316

@@ -27,19 +20,15 @@ export default class DeploymentVersionsTable extends Component<Props> {
2720
render () {
2821
const {
2922
deployment,
30-
deleteFeedVersion,
3123
project,
32-
versions,
33-
updateVersionForFeedSource,
34-
user
24+
versions
3525
} = this.props
3626
return (
3727
<Table striped hover fill>
3828
<thead>
3929
<tr>
4030
<th className='col-md-4'>{this.messages('name')}</th>
4131
<th>Version</th>
42-
<th className='hidden-xs'>{this.messages('dateRetrieved')}</th>
4332
<th className='hidden-xs'>{this.messages('loadStatus')}</th>
4433
<th className='hidden-xs'>{this.messages('errorCount')}</th>
4534
<th className='hidden-xs'>{this.messages('routeCount')}</th>
@@ -52,151 +41,18 @@ export default class DeploymentVersionsTable extends Component<Props> {
5241
</thead>
5342
<tbody>
5443
{versions.map((version) => {
55-
return <FeedVersionTableRow
56-
feedSource={version.feedSource}
57-
version={version}
58-
project={project}
59-
deployment={deployment}
60-
key={version.id}
61-
user={user}
62-
updateVersionForFeedSource={updateVersionForFeedSource}
63-
deleteFeedVersion={deleteFeedVersion} />
44+
return (
45+
<FeedVersionTableRow
46+
feedSource={version.feedSource}
47+
version={version}
48+
project={project}
49+
deployment={deployment}
50+
key={version.id}
51+
/>
52+
)
6453
})}
6554
</tbody>
6655
</Table>
6756
)
6857
}
6958
}
70-
71-
type RowProps = {
72-
deleteFeedVersion: typeof deploymentActions.deleteFeedVersion,
73-
deployment: Deployment,
74-
feedSource: Feed,
75-
project: Project,
76-
updateVersionForFeedSource: typeof deploymentActions.updateVersionForFeedSource,
77-
user: ManagerUserState,
78-
version: SummarizedFeedVersion
79-
}
80-
81-
class FeedVersionTableRow extends Component<RowProps> {
82-
_decrementVersion = () => {
83-
const {deployment, feedSource, updateVersionForFeedSource, version} = this.props
84-
const {previousVersionId: id} = version
85-
if (!id) {
86-
console.warn('No previous version ID exists for version', version)
87-
return
88-
}
89-
updateVersionForFeedSource(deployment, feedSource, {id})
90-
}
91-
92-
_incrementVersion = () => {
93-
const {deployment, feedSource, updateVersionForFeedSource, version} = this.props
94-
const {nextVersionId: id} = version
95-
if (!id) {
96-
console.warn('No next version ID exists for version', version)
97-
return
98-
}
99-
updateVersionForFeedSource(deployment, feedSource, {id})
100-
}
101-
102-
_removeVersion = () => {
103-
const {deleteFeedVersion, deployment, version} = this.props
104-
deleteFeedVersion(deployment, version)
105-
}
106-
107-
render () {
108-
const {
109-
deployment,
110-
feedSource,
111-
project,
112-
user,
113-
version
114-
} = this.props
115-
const {validationResult: result} = version
116-
const na = (<span style={{ color: 'lightGray' }}>N/A</span>)
117-
const hasVersionStyle = {cursor: 'pointer'}
118-
const noVersionStyle = {color: 'lightGray'}
119-
const disabled = !user.permissions ||
120-
!user.permissions.hasFeedPermission(
121-
project.organizationId,
122-
project.id,
123-
feedSource.id,
124-
'manage-feed'
125-
)
126-
const expired = versionHasExpired(version)
127-
const future = versionHasNotBegun(version)
128-
return (
129-
<tr key={feedSource.id}>
130-
<td>
131-
<Link to={`/feed/${feedSource.id}`}>{feedSource.name}</Link>
132-
</td>
133-
<td className='col-md-1 col-xs-2'>
134-
<Link to={`/feed/${feedSource.id}/version/${version.version}`}>
135-
<small>Version {version.version}</small>
136-
</Link>
137-
<ButtonToolbar>
138-
<Button
139-
bsSize='xsmall'
140-
bsStyle='default'
141-
style={{color: 'black'}}
142-
disabled={!version.previousVersionId}
143-
onClick={this._decrementVersion}>
144-
<Glyphicon
145-
glyph='menu-left'
146-
style={version.previousVersionId ? hasVersionStyle : noVersionStyle}
147-
title={version.previousVersionId ? 'Previous version' : 'No previous versions'}
148-
alt='Previous version' />
149-
</Button>
150-
<Button
151-
bsSize='xsmall'
152-
bsStyle='default'
153-
style={{color: 'black'}}
154-
disabled={!version.nextVersionId}
155-
onClick={this._incrementVersion}>
156-
<Glyphicon
157-
glyph='menu-right'
158-
style={version.nextVersionId ? hasVersionStyle : noVersionStyle}
159-
title={version.nextVersionId ? 'Next version' : 'No newer versions'}
160-
alt='Next Version' />
161-
</Button>
162-
</ButtonToolbar>
163-
</td>
164-
<td className='hidden-xs'>
165-
{na}
166-
</td>
167-
<td className='hidden-xs'>
168-
<Badge>{result.loadStatus}</Badge>
169-
</td>
170-
<td className={`hidden-xs${result.errorCount && ' warning'}`}>
171-
{result.errorCount}
172-
</td>
173-
<td className={`hidden-xs${!result.routeCount ? ' warning' : ''}`}>
174-
{result.routeCount}
175-
</td>
176-
<td className={`hidden-xs${!result.tripCount ? ' warning' : ''}`}>
177-
{result.tripCount}
178-
</td>
179-
<td className={`hidden-xs${!result.stopTimesCount ? ' warning' : ''}`}>
180-
{result.stopTimesCount}
181-
</td>
182-
<td className={future ? 'danger' : ''}>
183-
{formatTimestamp(result.startDate, false)} ({fromNow(result.startDate)})
184-
</td>
185-
<td className={expired ? 'danger' : ''}>
186-
{formatTimestamp(result.endDate, false)} ({fromNow(result.endDate)})
187-
</td>
188-
<td>
189-
<Button
190-
bsStyle='danger'
191-
bsSize='xsmall'
192-
// Cannot remove feed source if the deployment is feed-specific
193-
disabled={disabled || deployment.feedSourceId === feedSource.id}
194-
className='pull-right'
195-
onClick={this._removeVersion}>
196-
<Glyphicon glyph='remove' />
197-
</Button>
198-
</td>
199-
</tr>
200-
)
201-
}
202-
}

lib/manager/components/deployment/DeploymentViewer.js

Lines changed: 8 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -45,15 +45,13 @@ import type {ManagerUserState} from '../../../types/reducers'
4545

4646
type Props = ContainerProps & {
4747
addFeedVersion: typeof deploymentActions.addFeedVersion,
48-
deleteFeedVersion: typeof deploymentActions.deleteFeedVersion,
4948
deployJobs: Array<ServerJob>,
5049
deployToTarget: typeof deploymentActions.deployToTarget,
5150
downloadBuildArtifact: typeof deploymentActions.downloadBuildArtifact,
5251
downloadDeployment: typeof deploymentActions.downloadDeployment,
5352
fetchDeployment: typeof deploymentActions.fetchDeployment,
5453
terminateEC2InstanceForDeployment: typeof deploymentActions.terminateEC2InstanceForDeployment,
5554
updateDeployment: typeof deploymentActions.updateDeployment,
56-
updateVersionForFeedSource: typeof deploymentActions.updateVersionForFeedSource,
5755
user: ManagerUserState
5856
}
5957

@@ -306,15 +304,12 @@ export default class DeploymentViewer extends Component<Props, State> {
306304

307305
render () {
308306
const {
309-
deleteFeedVersion,
310307
deployJobs,
311308
deployment,
312309
deployToTarget,
313310
feedSources,
314311
project,
315-
updateDeployment,
316-
updateVersionForFeedSource,
317-
user
312+
updateDeployment
318313
} = this.props
319314
const {target} = this.state
320315
const {feedVersions} = deployment
@@ -361,13 +356,13 @@ export default class DeploymentViewer extends Component<Props, State> {
361356
? <p className='lead text-center margin-top-15'>
362357
No feed sources found.
363358
</p>
364-
: <DeploymentVersionsTable
365-
deleteFeedVersion={deleteFeedVersion}
366-
deployment={deployment}
367-
project={project}
368-
updateVersionForFeedSource={updateVersionForFeedSource}
369-
user={user}
370-
versions={versions} />
359+
: (
360+
<DeploymentVersionsTable
361+
deployment={deployment}
362+
project={project}
363+
versions={versions}
364+
/>
365+
)
371366
}
372367
</ListGroup>
373368
</Panel>

lib/manager/components/deployment/DeploymentsPanel.js

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import React, {Component} from 'react'
55
import { LinkContainer } from 'react-router-bootstrap'
66
import {
77
Button,
8+
Checkbox,
89
Col,
910
ControlLabel,
1011
Glyphicon,
@@ -56,6 +57,12 @@ export default class DeploymentsPanel extends Component<Props> {
5657
this._updateProject({autoDeployTypes: options.map(o => o.value)})
5758
}
5859

60+
_onChangeDeployWithCriticalErrors = (evt: SyntheticInputEvent<HTMLInputElement>) => {
61+
this._updateProject({
62+
autoDeployWithCriticalErrors: !this.props.project.autoDeployWithCriticalErrors
63+
})
64+
}
65+
5966
_onDeleteDeployment = (deployment: Deployment) => {
6067
this.refs.confirmModal.open({
6168
title: 'Delete Deployment?',
@@ -118,9 +125,9 @@ export default class DeploymentsPanel extends Component<Props> {
118125
/>
119126
<HelpBlock>{this.messages('pinnedDeployment.help')}</HelpBlock>
120127
</FormGroup>
121-
<FormGroup controlId='pinnedDeploymentId'>
128+
<FormGroup controlId='autoDeployTypes'>
122129
<ControlLabel>
123-
<Icon type='thumb-tack' />{' '}
130+
<Icon type='bolt' />{' '}
124131
{this.messages('autoDeploy.label')}
125132
</ControlLabel>
126133
<Select
@@ -139,6 +146,22 @@ export default class DeploymentsPanel extends Component<Props> {
139146
/>
140147
<HelpBlock>{this.messages('autoDeploy.help')}</HelpBlock>
141148
</FormGroup>
149+
<FormGroup controlId='autoDeployWithCriticalErrors'>
150+
<ControlLabel>
151+
<Icon type='warning' />{' '}
152+
{this.messages('autoDeploy.deployWithErrors.title')}
153+
</ControlLabel>
154+
<Checkbox
155+
checked={project.autoDeployWithCriticalErrors}
156+
name='autoDeployWithCriticalErrors'
157+
onChange={this._onChangeDeployWithCriticalErrors}
158+
>
159+
{this.messages('autoDeploy.deployWithErrors.checklabel')}
160+
</Checkbox>
161+
<HelpBlock>
162+
{this.messages('autoDeploy.deployWithErrors.help')}
163+
</HelpBlock>
164+
</FormGroup>
142165
</Panel>
143166
<Panel header={
144167
<h3><Icon type='cog' /> {this.messages('config.title')}</h3>

0 commit comments

Comments
 (0)