Skip to content

Commit b9f2254

Browse files
feat: [KSBP-101776] - Updates to treatment of combined parallel and sequential at same level
1 parent 98701e2 commit b9f2254

4 files changed

Lines changed: 105 additions & 76 deletions

File tree

k8s-deployer/src/dependency-resolver.ts

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -221,24 +221,35 @@ export const printDependencyGraph = (graph: Schema.Graph): void => {
221221
const { components, testApp } = graph
222222
const { levels } = topologicalSort(components)
223223
const sep = "─".repeat(40)
224-
const label = (c: Schema.DeployableComponent) => c.parallel ? `${c.id} 🔀` : c.id
225224
const edges = components.flatMap(c => (c.dependsOn ?? []).map(dep => ` ${dep} ──▶ ${c.id}`))
226225
const anyConcurrent = components.some(c => c.parallel) || testApp.parallel === true
227226

227+
// Format a single dependency level into a display string.
228+
// Parallel components are grouped in brackets; sequential follow after an arrow.
229+
// e.g. "[B 🔀 C 🔀] → D E" or "[B 🔀] → C" or "A B" (all sequential)
230+
const formatLevel = (level: Array<Schema.DeployableComponent>): string => {
231+
const parallel = level.filter(c => c.parallel === true)
232+
const sequential = level.filter(c => c.parallel !== true)
233+
const parallelPart = parallel.length > 0 ? `[${parallel.map(c => `${c.id} 🔀`).join(" ")}]` : ""
234+
const sequentialPart = sequential.map(c => c.id).join(" ")
235+
if (parallelPart && sequentialPart) return `${parallelPart}${sequentialPart}`
236+
return parallelPart || sequentialPart
237+
}
238+
228239
console.log("Dependency Graph")
229240
console.log(sep)
230241

231242
if (testApp.parallel === true) {
232243
// testApp runs concurrently with the entire component chain — show it in a separate section
233244
levels.forEach((level, idx) =>
234-
console.log(` Stage ${idx + 1}${level.map(label).join(" ")}`)
245+
console.log(` Stage ${idx + 1}${formatLevel(level)}`)
235246
)
236247
console.log(sep)
237-
console.log(` ${label(testApp)} (concurrent with component stages)`)
248+
console.log(` ${testApp.id} 🔀 (concurrent with component stages)`)
238249
} else {
239250
// testApp runs after all components — append it as the final stage
240251
levels.forEach((level, idx) =>
241-
console.log(` Stage ${idx + 1}${level.map(label).join(" ")}`)
252+
console.log(` Stage ${idx + 1}${formatLevel(level)}`)
242253
)
243254
console.log(` Stage ${levels.length + 1}${testApp.id}`)
244255
}

k8s-deployer/src/test-suite-handler.ts

Lines changed: 25 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -70,36 +70,31 @@ export const deployGraph = async (config: Config, workspace: string, testSuiteId
7070
const parallelGroup = level.filter(c => c.parallel === true)
7171
const sequentialGroup = level.filter(c => c.parallel !== true)
7272

73-
// Fire both groups concurrently; await both before moving to the next level.
74-
const parallelChain = parallelGroup.length > 0
75-
? (async () => {
76-
logger.info("")
77-
logger.info("Deploying %d component(s) in parallel for suite \"%s\": %s", parallelGroup.length, testSuiteId, parallelGroup.map(c => c.id).join(", "))
78-
const results = await Promise.all(
79-
parallelGroup.map(async componentSpec => {
80-
const idx = ++componentIndex
81-
logger.info("Deploying graph component (%s of %s) \"%s\" for suite \"%s\"...", idx, sortedComponents.length, componentSpec.name, testSuiteId)
82-
const commitSha = await Deployer.deployComponent(config, workspace, componentSpec, namespace)
83-
logger.info("Graph component \"%s\" for suite \"%s\" deployed.", componentSpec.name, testSuiteId)
84-
return new DeployedComponent(commitSha, componentSpec)
85-
})
86-
)
87-
deployments.push(...results)
88-
})()
89-
: Promise.resolve()
90-
91-
const sequentialChain = (async () => {
92-
for (const componentSpec of sequentialGroup) {
93-
const idx = ++componentIndex
94-
logger.info("")
95-
logger.info("Deploying graph component (%s of %s) \"%s\" for suite \"%s\"...", idx, sortedComponents.length, componentSpec.name, testSuiteId)
96-
logger.info("")
97-
const commitSha = await Deployer.deployComponent(config, workspace, componentSpec, namespace)
98-
deployments.push(new DeployedComponent(commitSha, componentSpec))
99-
}
100-
})()
101-
102-
await Promise.all([parallelChain, sequentialChain])
73+
// First, deploy parallel-flagged components concurrently.
74+
// Then, once all parallel components at this level are done, deploy sequential ones in order.
75+
if (parallelGroup.length > 0) {
76+
logger.info("")
77+
logger.info("Deploying %d component(s) in parallel for suite \"%s\": %s", parallelGroup.length, testSuiteId, parallelGroup.map(c => c.id).join(", "))
78+
const results = await Promise.all(
79+
parallelGroup.map(async componentSpec => {
80+
const idx = ++componentIndex
81+
logger.info("Deploying graph component (%s of %s) \"%s\" for suite \"%s\"...", idx, sortedComponents.length, componentSpec.name, testSuiteId)
82+
const commitSha = await Deployer.deployComponent(config, workspace, componentSpec, namespace)
83+
logger.info("Graph component \"%s\" for suite \"%s\" deployed.", componentSpec.name, testSuiteId)
84+
return new DeployedComponent(commitSha, componentSpec)
85+
})
86+
)
87+
deployments.push(...results)
88+
}
89+
90+
for (const componentSpec of sequentialGroup) {
91+
const idx = ++componentIndex
92+
logger.info("")
93+
logger.info("Deploying graph component (%s of %s) \"%s\" for suite \"%s\"...", idx, sortedComponents.length, componentSpec.name, testSuiteId)
94+
logger.info("")
95+
const commitSha = await Deployer.deployComponent(config, workspace, componentSpec, namespace)
96+
deployments.push(new DeployedComponent(commitSha, componentSpec))
97+
}
10398
}
10499
})()
105100

k8s-deployer/test/dependency-resolver.spec.ts

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -461,13 +461,27 @@ describe("Dependency Resolver", () => {
461461
printDependencyGraph({ testApp, components })
462462
expect(logOutput[0]).to.equal("Dependency Graph")
463463
expect(logOutput).to.include(" Stage 1 │ a")
464-
expect(logOutput).to.include(" Stage 2 │ b 🔀 c 🔀")
464+
expect(logOutput).to.include(" Stage 2 │ [b 🔀 c 🔀]")
465465
expect(logOutput).to.include(" Stage 3 │ test-app")
466466
expect(logOutput).to.include(" a ──▶ b")
467467
expect(logOutput).to.include(" a ──▶ c")
468468
expect(logOutput).to.include(" 🔀 = concurrent deployment")
469469
})
470470

471+
it("shows mixed parallel/sequential at same level as [parallel] → sequential", () => {
472+
const components: Array<Schema.DeployableComponent> = [
473+
{ name: "A", id: "a", location: { type: Schema.LocationType.Local }, deploy: { command: "deploy.sh" }, undeploy: { command: "undeploy.sh" } },
474+
{ name: "B", id: "b", location: { type: Schema.LocationType.Local }, deploy: { command: "deploy.sh" }, undeploy: { command: "undeploy.sh" }, dependsOn: ["a"], parallel: true },
475+
{ name: "C", id: "c", location: { type: Schema.LocationType.Local }, deploy: { command: "deploy.sh" }, undeploy: { command: "undeploy.sh" }, dependsOn: ["a"] }
476+
]
477+
printDependencyGraph({ testApp, components })
478+
expect(logOutput[0]).to.equal("Dependency Graph")
479+
expect(logOutput).to.include(" Stage 1 │ a")
480+
expect(logOutput).to.include(" Stage 2 │ [b 🔀] → c")
481+
expect(logOutput).to.include(" Stage 3 │ test-app")
482+
expect(logOutput).to.include(" 🔀 = concurrent deployment")
483+
})
484+
471485
it("shows testApp in a concurrent section when testApp.parallel is true", () => {
472486
const parallelTestApp: Schema.DeployableComponent = { ...testApp, id: "my-test-app", parallel: true }
473487
const components: Array<Schema.DeployableComponent> = [

0 commit comments

Comments
 (0)