Skip to content

Commit

Permalink
Display placeholders for pipeline tasks that haven't begun executing yet
Browse files Browse the repository at this point in the history
On the PipelineRun details page, display placeholders for pipeline tasks
that don't yet have a corresponding TaskRun. Fill in spec details where
available so the user can still view the definition.

Once the pipeline task begins executing the placeholder will be replaced
with the real TaskRun and corresponding details.

In the case of Conditions, we make a best effort to display placeholders
for the TaskRuns generated to evaluate them. Once they execute we will
display the correct TaskRun details, however before this is available
the placeholder may be incomplete and may become unselected as the
PipelineRun updates. This is due to a lack of required runtime information
to produce a consistent link between the resources. Since Conditions are
deprecated, we're not planning to invest further effort in improving this.

This update also changes the ordering of TaskRun in the TaskTree component.
Instead of sorting by start time of the first step in each TaskRun, they're
now sorted in order of definition in the Pipeline.

A nice (subj.) side effect of this is that retries for a given TaskRun
will be displayed immediately following the corresponding TaskRun rather
than interspersed among other TaskRuns in an often unpredictable order.
Future changes to the display of retries will further improve this grouping.
  • Loading branch information
AlanGreene committed Dec 10, 2020
1 parent 69b9ff6 commit 0cb9c14
Show file tree
Hide file tree
Showing 5 changed files with 411 additions and 53 deletions.
35 changes: 0 additions & 35 deletions packages/components/src/components/PipelineRun/PipelineRun.js
Original file line number Diff line number Diff line change
Expand Up @@ -74,33 +74,6 @@ export /* istanbul ignore next */ class PipelineRunContainer extends Component {
);
}

sortTaskRuns = taskRuns => {
const toReturn = taskRuns.sort((taskRunA, taskRunB) => {
if (!taskRunA || !taskRunB) {
return 0;
}

const firstStepA = taskRunA.status?.steps?.[0];
const firstStepB = taskRunB.status?.steps?.[0];

if (!firstStepA || !firstStepB) {
return 0;
}

const { startedAt: startedAtA } =
firstStepA.terminated || firstStepA.running || {};
const { startedAt: startedAtB } =
firstStepB.terminated || firstStepB.running || {};

if (!startedAtA || !startedAtB) {
return 0;
}

return new Date(startedAtA).getTime() - new Date(startedAtB).getTime();
});
return toReturn;
};

loadTaskRuns = () => {
const { intl, pipelineRun } = this.props;
if (!pipelineRun?.status?.taskRuns) {
Expand Down Expand Up @@ -186,7 +159,6 @@ export /* istanbul ignore next */ class PipelineRunContainer extends Component {
selectedStepId,
selectedTaskId,
showIO,
sortTaskRuns,
triggerHeader,
view
} = this.props;
Expand Down Expand Up @@ -275,11 +247,6 @@ export /* istanbul ignore next */ class PipelineRunContainer extends Component {
}

const taskRuns = this.loadTaskRuns();

if (sortTaskRuns) {
this.sortTaskRuns(taskRuns);
}

const taskRun =
taskRuns.find(run => run.metadata.uid === selectedTaskId) || {};

Expand Down Expand Up @@ -360,7 +327,6 @@ PipelineRunContainer.propTypes = {
onViewChange: PropTypes.func,
selectedStepId: PropTypes.string,
selectedTaskId: PropTypes.string,
sortTaskRuns: PropTypes.bool,
view: PropTypes.string
};

Expand All @@ -369,7 +335,6 @@ PipelineRunContainer.defaultProps = {
onViewChange: /* istanbul ignore next */ () => {},
selectedStepId: null,
selectedTaskId: null,
sortTaskRuns: false,
view: null
};

Expand Down
1 change: 1 addition & 0 deletions packages/utils/src/utils/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ limitations under the License.
export const labels = {
CLUSTER_TASK: 'tekton.dev/clusterTask',
CONDITION_CHECK: 'tekton.dev/conditionCheck',
CONDITION_NAME: 'tekton.dev/conditionName',
DASHBOARD_IMPORT: 'dashboard.tekton.dev/import',
DASHBOARD_RETRY_NAME: 'dashboard.tekton.dev/retryName',
PIPELINE: 'tekton.dev/pipeline',
Expand Down
98 changes: 98 additions & 0 deletions packages/utils/src/utils/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ See the License for the specific language governing permissions and
limitations under the License.
*/

import { labels as labelConstants } from './constants';

export { default as buildGraphData } from './buildGraphData';
export * from './constants';
export { paths, urls } from './router';
Expand Down Expand Up @@ -277,3 +279,99 @@ export function getTranslateWithId(intl) {
}
};
}

export function getTaskSpecFromTaskRef({ clusterTasks, pipelineTask, tasks }) {
if (!pipelineTask.taskRef) {
return {};
}

const definitions =
pipelineTask.taskRef.kind === 'ClusterTask' ? clusterTasks : tasks;
const definition = (definitions || []).find(
task => task.metadata.name === pipelineTask.taskRef.name
);

return definition?.spec || {};
}

export function getPlaceholderTaskRun({
clusterTasks,
condition,
pipelineTask,
tasks
}) {
const { name: pipelineTaskName, taskSpec } = pipelineTask;
const specToDisplay =
taskSpec || getTaskSpecFromTaskRef({ clusterTasks, pipelineTask, tasks });
const { steps = [] } = specToDisplay;

const displayName =
pipelineTaskName + (condition ? `-${condition.conditionRef}` : '');

return {
metadata: {
name: displayName,
labels: {
[labelConstants.PIPELINE_TASK]: pipelineTaskName,
...(condition && {
[labelConstants.CONDITION_CHECK]: displayName,
[labelConstants.CONDITION_NAME]: condition.conditionRef
})
},
uid: `_placeholder_${displayName}`
},
spec: {
taskSpec: specToDisplay
},
status: {
steps: steps.map(({ name }) => ({ name }))
}
};
}

export function getTaskRunsWithPlaceholders({
clusterTasks,
pipeline,
pipelineRun,
taskRuns,
tasks
}) {
const pipelineTasks = []
.concat(pipeline?.spec?.tasks)
.concat(pipelineRun?.spec?.pipelineSpec?.tasks)
.concat(pipeline?.spec?.finally)
.concat(pipelineRun?.spec?.pipelineSpec?.finally)
.filter(Boolean);

const taskRunsToDisplay = [];
pipelineTasks.forEach(pipelineTask => {
if (pipelineTask.conditions) {
pipelineTask.conditions.forEach(condition => {
const conditionTaskRun = taskRuns.find(
taskRun =>
taskRun.metadata.labels?.[labelConstants.PIPELINE_TASK] ===
pipelineTask.name &&
taskRun.metadata.labels?.[labelConstants.CONDITION_NAME] ===
condition.conditionRef
);
taskRunsToDisplay.push(
conditionTaskRun || getPlaceholderTaskRun({ pipelineTask, condition })
);
});
}

const realTaskRun = taskRuns.find(
taskRun =>
taskRun.metadata.labels?.[labelConstants.PIPELINE_TASK] ===
pipelineTask.name &&
!taskRun.metadata.labels?.[labelConstants.CONDITION_CHECK]
);

taskRunsToDisplay.push(
realTaskRun ||
getPlaceholderTaskRun({ clusterTasks, pipelineTask, tasks })
);
});

return taskRunsToDisplay;
}
Loading

0 comments on commit 0cb9c14

Please sign in to comment.