Skip to content

Commit

Permalink
Rotate currently running pipelines if configuration value rotateRunni…
Browse files Browse the repository at this point in the history
…ngPipelines set to true
  • Loading branch information
Sakari Laine committed Apr 22, 2024
1 parent 277b7bf commit 5be6d14
Show file tree
Hide file tree
Showing 9 changed files with 55 additions and 12 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ Optional configuration properties:
- `gitlabs / ignoreArchived` - Ignore archived projects. Default value is `true`
- `groupSuccessfulProjects` - If set to `true` projects with successful pipeline status are grouped by namespace. Projects with other pipeline statuses are still rendered seperately. Default value is `false`.
- `horizontal` - If set to `true` jobs are ordered horizontally to stages. Default value is `false`.
- `rotateRunningPipelines` - If set to `true` all currently running pipelines are rotated in view. Default value is `false`.
- `auth / username` - Enables HTTP basic authentication with the defined username and password.
- `auth / password` - Enables HTTP basic authentication with the defined username and password.
- `projectsOrder` - Array of project attributes to use for sorting projects. Default value is `['name']` (available attributes are `status, name, id, nameWithoutNamespace, group`).
Expand Down
1 change: 1 addition & 0 deletions src/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ const globalState = {
projectsOrder: config.projectsOrder,
columns: config.columns,
horizontal: config.horizontal,
rotateRunningPipelines: config.rotateRunningPipelines,
groupSuccessfulProjects: config.groupSuccessfulProjects
}

Expand Down
2 changes: 2 additions & 0 deletions src/client/gitlab-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ export interface GlobalState {
columns: number
error: string | null
groupSuccessfulProjects: boolean
rotateRunningPipelines: boolean
horizontal: boolean
projects: Project[] | null
projectsOrder: string[]
Expand Down Expand Up @@ -30,6 +31,7 @@ export interface Pipeline {
ref: string
stages: Stage[]
status: 'success' | 'failed'
running: boolean
}

export interface Commit {
Expand Down
10 changes: 5 additions & 5 deletions src/client/groupedProjects.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,20 @@ import {Projects} from './projects'
import React from 'react'
import type {Project} from './gitlab-types'

export function GroupedProjects({projects, projectsOrder, groupSuccessfulProjects, zoom, columns, now, screen}: {projects: Project[], projectsOrder: string[], groupSuccessfulProjects: boolean, zoom: number, columns: number, now: number, screen: {id: number, total: number}}): JSX.Element {
export function GroupedProjects({projects, projectsOrder, groupSuccessfulProjects, zoom, columns, rotateRunningPipelines, now, screen}: {projects: Project[], projectsOrder: string[], groupSuccessfulProjects: boolean, zoom: number, columns: number, rotateRunningPipelines: boolean, now: number, screen: {id: number, total: number}}): JSX.Element {
if (groupSuccessfulProjects) {
return renderProjectsGrouped(projects, projectsOrder, zoom, columns, now, screen)
return renderProjectsGrouped(projects, projectsOrder, zoom, columns, rotateRunningPipelines, now, screen)
}
return <Projects now={now} zoom={zoom} columns={columns} projects={projects} projectsOrder={projectsOrder} screen={screen}/>
return <Projects now={now} zoom={zoom} columns={columns} projects={projects} projectsOrder={projectsOrder} screen={screen} rotateRunningPipelines={rotateRunningPipelines}/>
}

function renderProjectsGrouped(projects: Project[], projectsOrder: string[], zoom: number, columns: number, now: number, screen: {id: number, total: number}) {
function renderProjectsGrouped(projects: Project[], projectsOrder: string[], zoom: number, columns: number, rotateRunningPipelines: boolean, now: number, screen: {id: number, total: number}) {
const successfullProjects = projects.filter(({status}) => status === 'success')
const otherProjects= projects.filter(({status}) => status !== 'success')
const groupedProjects = groupBy(successfullProjects, 'group')

return <React.Fragment>
<Projects now={now} zoom={zoom} columns={columns} projects={otherProjects} projectsOrder={projectsOrder} screen={screen}/>
<Projects now={now} zoom={zoom} columns={columns} projects={otherProjects} projectsOrder={projectsOrder} screen={screen} rotateRunningPipelines={rotateRunningPipelines}/>
<Groups now={now} zoom={zoom} columns={columns} groupedProjects={groupedProjects}/>
</React.Fragment>
}
4 changes: 3 additions & 1 deletion src/client/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ class RadiatorApp extends React.Component<unknown, GlobalState> {
columns: 1,
error: null,
groupSuccessfulProjects: false,
rotateRunningPipelines: false,
horizontal: false,
projects: null,
projectsOrder: [],
Expand All @@ -35,7 +36,7 @@ class RadiatorApp extends React.Component<unknown, GlobalState> {

render = () => {
const {screen} = this.args
const {now, zoom, columns, projects, projectsOrder, groupSuccessfulProjects, horizontal} = this.state
const {now, zoom, columns, projects, projectsOrder, groupSuccessfulProjects, horizontal, rotateRunningPipelines} = this.state
return <div className={horizontal ? 'horizontal': ''}>
{this.renderErrorMessage()}
{this.renderProgressMessage()}
Expand All @@ -44,6 +45,7 @@ class RadiatorApp extends React.Component<unknown, GlobalState> {
<GroupedProjects now={now} zoom={zoom} columns={columns}
projects={projects} projectsOrder={projectsOrder}
groupSuccessfulProjects={groupSuccessfulProjects}
rotateRunningPipelines={rotateRunningPipelines}
screen={screen}/>
}
</div>
Expand Down
28 changes: 23 additions & 5 deletions src/client/projects.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,39 @@ import sortBy from 'lodash/sortBy'
import {Stages} from './stages'
import type {Project} from './gitlab-types'

export function Projects({columns, now, projects, projectsOrder, screen, zoom}: {columns: number, now: number, projects: Project[], projectsOrder: string[], screen: {id: number, total: number}, zoom: number}): JSX.Element {
let runningPipelineIndex: number[] = []

export function Projects({columns, now, projects, projectsOrder, screen, zoom, rotateRunningPipelines}: {columns: number, now: number, projects: Project[], projectsOrder: string[], screen: {id: number, total: number}, zoom: number, rotateRunningPipelines: boolean}): JSX.Element {
return <ol className="projects" style={zoomStyle(zoom)}>
{sortBy(projects, projectsOrder)
.filter(forScreen(screen, projects.length))
.map(project => <ProjectElement now={now} columns={columns} project={project} key={project.id}/>)
.map(project => <ProjectElement now={now} columns={columns} project={project} key={project.id} rotateRunningPipelines={rotateRunningPipelines}/>)
}
</ol>
}

function ProjectElement({columns, now, project}: {columns: number, now: number, project: Project}) {
const [pipeline] = project.pipelines
function ProjectElement({columns, now, project, rotateRunningPipelines}: {columns: number, now: number, project: Project, rotateRunningPipelines: boolean}) {
let [pipeline] = project.pipelines

let txt = ''

if (rotateRunningPipelines) {
const running = project.pipelines.filter(runningPipeline => runningPipeline.running)

if (running.length > 1) {
if (runningPipelineIndex[project.id] === undefined) {
runningPipelineIndex[project.id] = 0
}

runningPipelineIndex[project.id] = ++runningPipelineIndex[project.id] % running.length
pipeline = running[runningPipelineIndex[project.id]]
txt = (runningPipelineIndex[project.id] + 1) + '/' + running.length + ' '
}
}

return <li className={`project ${project.status}`} style={style(columns)}>
<h2>
{project.url && <a href={`${project.url}/pipelines`} target="_blank" rel="noopener noreferrer">{project.name}</a>}
{project.url && <a href={`${project.url}/pipelines`} target="_blank" rel="noopener noreferrer">{txt} {project.name}</a>}
{!project.url && project.name}
</h2>
<Stages stages={pipeline.stages} maxNonFailedJobsVisible={project.maxNonFailedJobsVisible}/>
Expand Down
1 change: 1 addition & 0 deletions src/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ config.port = Number(config.port || 3000)
config.zoom = Number(config.zoom || 1.0)
config.columns = Number(config.columns || 1)
config.horizontal = config.horizontal || false
config.rotateRunningPipelines = config.rotateRunningPipelines || false
config.groupSuccessfulProjects = config.groupSuccessfulProjects || false
config.projectsOrder = config.projectsOrder || ['name']
config.gitlabs = config.gitlabs.map((gitlab) => {
Expand Down
12 changes: 11 additions & 1 deletion src/gitlab/pipelines.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ export async function fetchLatestPipelines(projectId, gitlab) {
ref,
status,
commit,
stages: stages.concat(downstreamStages)
stages: stages.concat(downstreamStages),
running: status === 'running'
})
}
return pipelinesWithStages
Expand All @@ -25,6 +26,15 @@ async function fetchLatestAndMasterPipeline(projectId, config) {
if (pipelines.length === 0) {
return []
}

if (config.rotateRunningPipelines) {
const runningPipelines = pipelines.filter(pipeline => pipeline.status === 'running')

if (runningPipelines.length > 0) {
return runningPipelines
}
}

const latestPipeline = _.take(pipelines, 1)
if (latestPipeline[0].ref === 'master') {
return latestPipeline
Expand Down
8 changes: 8 additions & 0 deletions test/gitlab-integration.js
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ describe('Gitlab client', () => {
},
id: 1261086942,
ref: 'master',
running: false,
stages: [{
jobs: [{
finishedAt: '2024-04-20T08:24:58.581Z',
Expand Down Expand Up @@ -80,6 +81,7 @@ describe('Gitlab client', () => {
author: 'Heikki Pora'
},
ref: 'feature/test-branch',
running: false,
stages: [
{
name: 'test',
Expand Down Expand Up @@ -117,6 +119,7 @@ describe('Gitlab client', () => {
title: 'Fail more'
},
ref: 'master',
running: false,
stages: [
{
jobs: [
Expand Down Expand Up @@ -173,6 +176,7 @@ describe('Gitlab client', () => {
title: '[ci skip] do nothing'
},
ref: 'master',
running: false,
stages: [{
jobs: [{
finishedAt: '2024-04-20T08:24:58.581Z',
Expand Down Expand Up @@ -207,6 +211,7 @@ describe('Gitlab client', () => {
author: 'Heikki Pora'
},
ref: 'feature/test-branch',
running: false,
stages: [
{
name: 'test',
Expand Down Expand Up @@ -239,6 +244,7 @@ describe('Gitlab client', () => {
{
id: 234613296,
ref: 'master',
running: false,
status: 'failed',
commit: {
title: 'Fail more',
Expand Down Expand Up @@ -290,6 +296,7 @@ describe('Gitlab client', () => {
{
id: 234493901,
ref: 'master',
running: false,
status: 'success',
commit: {
title: 'Fail manual step',
Expand Down Expand Up @@ -395,6 +402,7 @@ describe('Gitlab client', () => {
},
id: 1261086879,
ref: 'master',
running: false,
stages: [{
jobs: [{
finishedAt: '2024-04-20T08:24:30.130Z',
Expand Down

0 comments on commit 5be6d14

Please sign in to comment.