import throwGlobalError from '../app/utils/throwGlobalError';
export interface PendingTask {
+ branch?: string;
+ branchType?: string;
componentKey: string;
componentName: string;
componentQualifier: string;
id: string;
logs: boolean;
organization: string;
+ pullRequest?: string;
+ pullRequestTitle?: string;
status: string;
submittedAt: Date;
submitterLogin?: string;
import { Component, BranchLike } from '../types';
import handleRequiredAuthorization from '../utils/handleRequiredAuthorization';
import { getBranches, getPullRequests } from '../../api/branches';
-import { Task, getTasksForComponent } from '../../api/ce';
+import { Task, getTasksForComponent, PendingTask } from '../../api/ce';
import { getComponentData } from '../../api/components';
import { getComponentNavigation } from '../../api/nav';
import { fetchOrganizations } from '../../store/rootActions';
import { STATUSES } from '../../apps/background-tasks/constants';
-import { isPullRequest, isBranch } from '../../helpers/branches';
+import {
+ isPullRequest,
+ isBranch,
+ isMainBranch,
+ isLongLivingBranch,
+ isShortLivingBranch
+} from '../../helpers/branches';
interface Props {
children: any;
interface State {
branchLikes: BranchLike[];
- loading: boolean;
component?: Component;
currentTask?: Task;
- isInProgress?: boolean;
- isPending?: boolean;
+ loading: boolean;
+ pendingTasks?: PendingTask[];
}
export class ComponentContainer extends React.PureComponent<Props, State> {
getTasksForComponent(component.key).then(
({ current, queue }) => {
if (this.mounted) {
- this.setState({
- currentTask: current,
- isInProgress: queue.some(task => task.status === STATUSES.IN_PROGRESS),
- isPending: queue.some(task => task.status === STATUSES.PENDING)
- });
+ this.setState({ currentTask: current, pendingTasks: queue });
}
},
() => {}
);
};
+ getCurrentTask = (branchLike?: BranchLike) => {
+ const { currentTask } = this.state;
+ return currentTask && this.isSameBranch(currentTask, branchLike) ? currentTask : undefined;
+ };
+
+ getPendingTasks = (branchLike?: BranchLike) => {
+ const { pendingTasks = [] } = this.state;
+ return pendingTasks.filter(task => this.isSameBranch(task, branchLike));
+ };
+
+ isSameBranch = (
+ task: Pick<PendingTask, 'branch' | 'branchType' | 'pullRequest'>,
+ branchLike?: BranchLike
+ ) => {
+ if (branchLike && !isMainBranch(branchLike)) {
+ if (isPullRequest(branchLike)) {
+ return branchLike.key === task.pullRequest;
+ }
+ if (isShortLivingBranch(branchLike) || isLongLivingBranch(branchLike)) {
+ return branchLike.type === task.branchType && branchLike.name === task.branch;
+ }
+ }
+ return !task.branch && !task.pullRequest;
+ };
+
handleComponentChange = (changes: {}) => {
if (this.mounted) {
this.setState(state => ({ component: { ...state.component, ...changes } }));
? branchLikes.find(b => isPullRequest(b) && b.key === query.pullRequest)
: branchLikes.find(b => isBranch(b) && (query.branch ? b.name === query.branch : b.isMain));
+ const currentTask = this.getCurrentTask(branchLike);
+ const pendingTasks = this.getPendingTasks(branchLike);
+ const isInProgress = pendingTasks.some(task => task.status === STATUSES.IN_PROGRESS);
+ const isPending = pendingTasks.some(task => task.status === STATUSES.PENDING);
+
return (
<div>
{component &&
branchLikes={branchLikes}
component={component}
currentBranchLike={branchLike}
- currentTask={this.state.currentTask}
- isInProgress={this.state.isInProgress}
- isPending={this.state.isPending}
+ currentTask={currentTask}
+ isInProgress={isInProgress}
+ isPending={isPending}
location={this.props.location}
/>
)}
branchLike,
branchLikes,
component,
- isInProgress: this.state.isInProgress,
- isPending: this.state.isPending,
+ isInProgress,
+ isPending,
onBranchesChange: this.handleBranchesChange,
onComponentChange: this.handleComponentChange
})
import { shallow, mount } from 'enzyme';
import { ComponentContainer } from '../ComponentContainer';
import { getBranches, getPullRequests } from '../../../api/branches';
-import { getTasksForComponent } from '../../../api/ce';
+import { getTasksForComponent, Task } from '../../../api/ce';
import { getComponentData } from '../../../api/components';
import { getComponentNavigation } from '../../../api/nav';
+import {
+ ShortLivingBranch,
+ MainBranch,
+ LongLivingBranch,
+ PullRequest,
+ BranchType
+} from '../../types';
jest.mock('../../../api/branches', () => ({
getBranches: jest.fn(() => Promise.resolve([])),
await new Promise(setImmediate);
expect(getTasksForComponent).toBeCalledWith('portfolioKey');
});
+
+it('filters correctly the pending tasks for a main branch', () => {
+ const wrapper = shallow(
+ <ComponentContainer fetchOrganizations={jest.fn()} location={{ query: { id: 'foo' } }}>
+ <Inner />
+ </ComponentContainer>
+ );
+
+ const component = wrapper.instance() as ComponentContainer;
+ const mainBranch: MainBranch = { isMain: true, name: 'master' };
+ const shortBranch: ShortLivingBranch = {
+ isMain: false,
+ mergeBranch: 'master',
+ name: 'feature',
+ type: BranchType.SHORT
+ };
+ const longBranch: LongLivingBranch = { isMain: false, name: 'branch-7.2', type: BranchType.LONG };
+ const pullRequest: PullRequest = {
+ base: 'feature',
+ branch: 'feature',
+ key: 'pr-89',
+ title: 'PR Feature'
+ };
+
+ expect(component.isSameBranch({}, undefined)).toBeTruthy();
+ expect(component.isSameBranch({}, mainBranch)).toBeTruthy();
+ expect(component.isSameBranch({}, shortBranch)).toBeFalsy();
+ expect(
+ component.isSameBranch({ branch: 'feature', branchType: 'SHORT' }, shortBranch)
+ ).toBeTruthy();
+ expect(
+ component.isSameBranch({ branch: 'feature', branchType: 'SHORT' }, longBranch)
+ ).toBeFalsy();
+ expect(
+ component.isSameBranch({ branch: 'feature', branchType: 'SHORT' }, longBranch)
+ ).toBeFalsy();
+ expect(
+ component.isSameBranch({ branch: 'branch-7.1', branchType: 'LONG' }, longBranch)
+ ).toBeFalsy();
+ expect(
+ component.isSameBranch({ branch: 'branch-7.2', branchType: 'LONG' }, pullRequest)
+ ).toBeFalsy();
+ expect(component.isSameBranch({ pullRequest: 'pr-89' }, pullRequest)).toBeTruthy();
+
+ const currentTask = { pullRequest: 'pr-89' } as Task;
+ const pendingTasks = [
+ currentTask,
+ { branch: 'feature', branchType: 'SHORT' } as Task,
+ {} as Task
+ ];
+ expect(component.getCurrentTask(undefined)).toBe(undefined);
+ component.setState({ currentTask });
+ expect(component.getCurrentTask(mainBranch)).toBe(undefined);
+ expect(component.getCurrentTask(pullRequest)).toMatchObject(currentTask);
+ component.setState({ pendingTasks });
+ expect(component.getPendingTasks(mainBranch)).toMatchObject([{}]);
+ expect(component.getPendingTasks(pullRequest)).toMatchObject([currentTask]);
+});
};
render() {
- const { currentTask, isInProgress, isPending } = this.props;
+ const { component, currentBranchLike, currentTask, isInProgress, isPending } = this.props;
let notifComponent;
if (isInProgress || isPending || (currentTask && currentTask.status === STATUSES.FAILED)) {
notifComponent = (
<ComponentNavBgTaskNotif
- component={this.props.component}
+ component={component}
currentTask={currentTask}
isInProgress={isInProgress}
isPending={isPending}
<div className="navbar-context-justified">
<ComponentNavHeader
branchLikes={this.props.branchLikes}
- component={this.props.component}
- currentBranchLike={this.props.currentBranchLike}
+ component={component}
+ currentBranchLike={currentBranchLike}
// to close dropdown on any location change
location={this.props.location}
/>
- <ComponentNavMeta
- branchLike={this.props.currentBranchLike}
- component={this.props.component}
- />
+ <ComponentNavMeta branchLike={currentBranchLike} component={component} />
</div>
<ComponentNavMenu
- branchLike={this.props.currentBranchLike}
- component={this.props.component}
+ branchLike={currentBranchLike}
+ component={component}
// to re-render selected menu item
location={this.props.location}
/>