The Gatekeeper, or a project gating system
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

269 lines
7.4 KiB

// Copyright 2018 Red Hat, Inc
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may
// not use this file except in compliance with the License. You may obtain
// a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations
// under the License.
import * as React from 'react'
import PropTypes from 'prop-types'
import { connect } from 'react-redux'
import { Link } from 'react-router-dom'
import ReactJson from 'react-json-view'
import {
DescriptionList,
DescriptionListTerm,
DescriptionListGroup,
DescriptionListDescription,
List,
ListItem,
ListVariant,
} from '@patternfly/react-core'
import {
AnsibleTowerIcon,
BanIcon,
CatalogIcon,
ClipboardCheckIcon,
ClusterIcon,
CodeBranchIcon,
CodeIcon,
ConnectedIcon,
DisconnectedIcon,
ExternalLinkAltIcon,
FlagIcon,
HistoryIcon,
InfrastructureIcon,
LockIcon,
LockedIcon,
OutlinedClockIcon,
PackageIcon,
RedoIcon,
WrenchIcon
} from '@patternfly/react-icons'
import SourceContext from '../SourceContext'
import Nodeset from './Nodeset'
import Role from './Role'
import JobProject from './JobProject'
import JobDescriptionCard from './JobDescriptionCard'
class JobVariant extends React.Component {
static propTypes = {
parent: PropTypes.object,
tenant: PropTypes.object,
variant: PropTypes.object.isRequired
}
renderStatus (variant) {
const status = [{
icon: variant.voting ? <ConnectedIcon /> : <DisconnectedIcon />,
name: variant.voting ? 'Voting' : 'Non-voting'
}]
if (variant.abstract) {
status.push({
icon: <InfrastructureIcon />,
name: 'Abstract'
})
}
if (variant.final) {
status.push({
icon: <InfrastructureIcon />,
name: 'Final'
})
}
if (variant.post_review) {
status.push({
icon: <LockedIcon />,
name: 'Post review'
})
}
if (variant.protected) {
status.push({
icon: <LockedIcon />,
name: 'Protected'
})
}
return (
<List iconSize="large" variant={ListVariant.inline}>
{status.map((item, idx) => (
<ListItem key={idx} icon={item.icon}>{item.name}</ListItem>
))}
</List>
)
}
render () {
const { tenant, variant } = this.props
const rows = []
const jobInfos = [
'source_context', 'builds', 'status',
'parent', 'attempts', 'timeout', 'semaphores',
'nodeset', 'variables', 'override_checkout',
]
jobInfos.forEach(key => {
let label = key
let nice_label = key
let value = variant[key]
if (label === 'source_context' && value) {
value = (
<SourceContext
context={variant.source_context}
showBranch={true}/>
)
nice_label = (<span><PackageIcon /> Defined at</span>)
}
if (label === 'builds') {
value = (
<Link to={this.props.tenant.linkPrefix + '/builds?job_name=' + variant.name}>
<ExternalLinkAltIcon />&nbsp;{variant.name}
</Link>
)
nice_label = (<span><HistoryIcon/> Build history</span>)
}
if (label === 'status') {
value = this.renderStatus(variant)
nice_label = (<span><FlagIcon/> Job flags</span>)
}
if (!value) {
return
}
if (label === 'attempts') {
nice_label = (<span><RedoIcon/> Retry attempts</span>)
}
if (label === 'timeout') {
value = (<span>{value} seconds</span>)
nice_label = (<span><OutlinedClockIcon /> Timeout</span>)
}
if (label === 'semaphores') {
if (value.length === 0) {
value = (<i>none</i>)
}
nice_label = (<span><LockIcon /> Semaphores</span>)
}
if (label === 'nodeset') {
value = (
<Nodeset nodeset={value} />
)
nice_label = (<span><ClusterIcon /> Required nodes</span>)
}
if (label === 'parent') {
value = (
<Link to={tenant.linkPrefix + '/job/' + value}>
<ExternalLinkAltIcon />&nbsp;{value}
</Link>
)
nice_label = (<span><CodeBranchIcon /> Parent</span>)
}
if (label === 'variables') {
value = (
<span style={{whiteSpace: 'pre-wrap'}}>
<ReactJson
src={value}
name={null}
collapsed={true}
sortKeys={true}
enableClipboard={false}
displayDataTypes={false}/>
</span>
)
nice_label = (<span><CodeIcon /> Job variables</span>)
}
if (label === 'description') {
value = (
<div style={{whiteSpace: 'pre-wrap'}}>
{value}
</div>
)
nice_label = (<span><CatalogIcon /> Description</span>)
}
rows.push({label: nice_label, value: value})
})
const jobInfosList = [
'required_projects', 'dependencies', 'files', 'irrelevant_files', 'roles'
]
jobInfosList.forEach(key => {
let label = key
let nice_label = key
let values = variant[key]
if (values.length === 0) {
return
}
const items = (
<List isPlain>
{values.map((value, idx) => {
let item
if (label === 'required_projects') {
nice_label = 'Required Projects'
item = <JobProject project={value} />
} else if (label === 'roles') {
nice_label = (<span><AnsibleTowerIcon /> Uses roles from</span>)
item = <Role role={value} />
} else if (label === 'dependencies') {
nice_label = (<span><WrenchIcon /> Job dependencies</span>)
if (value['soft']) {
item = value['name'] + ' (soft)'
} else {
item = value['name']
}
} else if (label === 'irrelevant_files') {
nice_label = (<span><BanIcon /> Irrelevant files matchers</span>)
item = value
} else if (label === 'files') {
nice_label = (<span><ClipboardCheckIcon />Files matchers</span>)
item = value
} else {
item = value
}
return (
<ListItem key={idx}>
{item}
</ListItem>
)
})}
</List>
)
rows.push({label: nice_label, value: items})
})
return (
<React.Fragment>
<JobDescriptionCard description={variant.description}/>
<DescriptionList isHorizontal
style={{'--pf-c-description-list--RowGap': '0.5rem'}}
className='pf-u-m-xl'>
{rows.map((item, idx) => (
<DescriptionListGroup key={idx}>
<DescriptionListTerm>
{item.label}
</DescriptionListTerm>
<DescriptionListDescription>
{item.value}
</DescriptionListDescription>
</DescriptionListGroup>
))}
</DescriptionList>
</React.Fragment>
)
}
}
export default connect(state => ({tenant: state.tenant}))(JobVariant)