OPC # 0006: OPC Git Trunk-Based management

This commit is contained in:
amadzarak
2026-04-26 14:40:05 -04:00
parent bb0c6e08c7
commit 2badb5264b
2 changed files with 134 additions and 51 deletions
+101 -15
View File
@@ -804,30 +804,116 @@ body {
.opc-sdlc-pipeline { .opc-sdlc-pipeline {
display: flex; display: flex;
align-items: center; align-items: flex-start;
flex-wrap: wrap; flex-wrap: nowrap;
gap: 0.2rem; gap: 0;
margin-bottom: 0.35rem; overflow-x: auto;
} padding-bottom: 0.25rem;
.opc-sdlc-stage-item {
display: flex;
align-items: center;
gap: 0.2rem;
} }
.opc-sdlc-arrow { .opc-sdlc-arrow {
color: #8f99a8; color: #8f99a8;
font-size: 0.8rem; font-size: 1rem;
font-weight: 600; font-weight: 600;
margin: 0 0.1rem; flex-shrink: 0;
align-self: center;
margin: 0 0.4rem;
user-select: none; user-select: none;
} }
.opc-sdlc-furthest { /* Individual branch box */
font-size: 0.75rem; .opc-sdlc-box {
flex: 1 1 140px;
min-width: 130px;
max-width: 200px;
display: flex;
flex-direction: column;
border: 1px solid #dce0e6;
border-radius: 6px;
background: #fff;
overflow: hidden;
flex-shrink: 0;
}
.opc-sdlc-box--reached {
border-width: 2px;
}
.opc-sdlc-box-header {
display: flex;
align-items: center;
justify-content: space-between;
padding: 0.3rem 0.5rem;
background: #f6f7f9;
border-bottom: 1px solid #e5e8eb;
flex-shrink: 0;
}
.opc-sdlc-box-count {
font-size: 0.68rem;
color: #738091; color: #738091;
margin-top: 0.3rem; background: #e5e8eb;
border-radius: 10px;
padding: 0 6px;
line-height: 1.5;
}
/* Scrollable body */
.opc-sdlc-box-body {
flex: 1;
overflow-y: auto;
max-height: 140px;
min-height: 60px;
padding: 0.3rem 0.4rem;
display: flex;
flex-direction: column;
gap: 0.15rem;
}
.opc-sdlc-sha-row {
display: flex;
align-items: baseline;
gap: 0.35rem;
padding: 0.1rem 0.2rem;
border-radius: 3px;
opacity: 0.35;
}
.opc-sdlc-sha-row--reached {
opacity: 1;
}
.opc-sdlc-sha {
font-family: 'Consolas', 'Courier New', monospace;
font-size: 0.7rem;
color: #2d72d2;
flex-shrink: 0;
}
.opc-sdlc-sha-msg {
font-size: 0.68rem;
color: #4a5568;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
flex: 1;
min-width: 0;
}
.opc-sdlc-box-empty {
font-size: 0.7rem;
color: #a3acb6;
font-style: italic;
padding: 0.2rem 0;
}
.opc-sdlc-box-pending {
font-size: 0.68rem;
color: #a3acb6;
font-style: italic;
margin-top: auto;
padding-top: 0.25rem;
border-top: 1px dashed #e5e8eb;
} }
/* Commits section labels */ /* Commits section labels */
+33 -36
View File
@@ -1,4 +1,4 @@
import { useState, useMemo, useEffect, useCallback } from 'react'; import { useState, useMemo, useEffect, useCallback, Fragment } from 'react';
import { GitCommitDrawer } from '../components/GitCommitDrawer'; import { GitCommitDrawer } from '../components/GitCommitDrawer';
import { import {
Button, Callout, Divider, Drawer, FormGroup, Button, Callout, Divider, Drawer, FormGroup,
@@ -79,15 +79,6 @@ const SDLC_STAGES: { branch: string; label: string; intent: Intent }[] = [
{ branch: 'main', label: 'Production', intent: Intent.SUCCESS }, { branch: 'main', label: 'Production', intent: Intent.SUCCESS },
]; ];
function deriveSdlcSummary(coverage: BranchCoverage[]): { label: string; intent: Intent } | null {
for (let i = SDLC_STAGES.length - 1; i >= 0; i--) {
const stage = SDLC_STAGES[i];
const hit = coverage.find(c => c.branch === stage.branch);
if (hit?.contains) return { label: stage.label, intent: stage.intent };
}
return null;
}
// Aggregate per-repo branch coverage into a single view. // Aggregate per-repo branch coverage into a single view.
// A stage is "reached" only when every repo that recognised at least one hash // A stage is "reached" only when every repo that recognised at least one hash
// reports contains=true for that branch. Repos that recognised no hashes are // reports contains=true for that branch. Repos that recognised no hashes are
@@ -487,42 +478,48 @@ function CommitsTab({ opc, isActive }: { opc: Opc; isActive: boolean }) {
{/* SDLC Delivery Chain */} {/* SDLC Delivery Chain */}
{coverage.length > 0 && (() => { {coverage.length > 0 && (() => {
const summary = deriveSdlcSummary(coverage); const allCommits = [
...autoCommits,
...pinned.map(p => ({ repoKey: 'pinned', hash: p.hash, shortHash: p.shortHash, author: p.pinnedBy, date: p.pinnedAt, subject: p.subject, files: [] })),
].filter((c, i, a) => a.findIndex(x => x.hash === c.hash) === i);
return ( return (
<div className="opc-delivery-chain"> <div className="opc-delivery-chain">
<div className="opc-field-label" style={{ marginBottom: '0.6rem' }}>Delivery Chain</div> <div className="opc-field-label" style={{ marginBottom: '0.75rem' }}>Delivery Chain</div>
<div className="opc-sdlc-pipeline"> <div className="opc-sdlc-pipeline">
{SDLC_STAGES.map((stage, i) => { {SDLC_STAGES.map((stage, i) => {
const hit = coverage.find(c => c.branch === stage.branch); const hit = coverage.find(c => c.branch === stage.branch);
const reached = hit?.contains ?? false; const reached = hit?.contains ?? false;
return ( return (
<div key={stage.branch} className="opc-sdlc-stage-item"> <Fragment key={stage.branch}>
{i > 0 && <span className="opc-sdlc-arrow"></span>} {i > 0 && <span className="opc-sdlc-arrow"></span>}
<Tooltip content={ <div className={`opc-sdlc-box${reached ? ' opc-sdlc-box--reached' : ''}`} style={{ borderColor: reached ? SDLC_STAGES[i].intent === 'primary' ? '#2d72d2' : SDLC_STAGES[i].intent === 'warning' ? '#c87619' : SDLC_STAGES[i].intent === 'danger' ? '#ac2f33' : '#1c6e42' : '#dce0e6' }}>
reached {/* Box header */}
? `All linked commits have reached ${stage.label}` <div className="opc-sdlc-box-header">
: hit <Tag intent={reached ? stage.intent : Intent.NONE} minimal={!reached} round style={{ fontWeight: 600, fontSize: '0.72rem' }}>
? `Not all linked commits have reached ${stage.label} yet` {stage.label}
: `${stage.label} branch not found locally` </Tag>
}> {reached && <span className="opc-sdlc-box-count">{allCommits.length}</span>}
<Tag </div>
intent={reached ? stage.intent : Intent.NONE} {/* Scrollable SHA list */}
icon={reached ? 'tick-circle' : 'circle'} <div className="opc-sdlc-box-body">
minimal={!reached} {allCommits.length === 0 ? (
round <span className="opc-sdlc-box-empty">No linked commits</span>
> ) : allCommits.map(c => (
{stage.label} <div key={c.hash} className={`opc-sdlc-sha-row${reached ? ' opc-sdlc-sha-row--reached' : ''}`} title={c.subject}>
</Tag> <code className="opc-sdlc-sha">{c.shortHash}</code>
</Tooltip> <span className="opc-sdlc-sha-msg">{c.subject}</span>
</div> </div>
))}
{!reached && allCommits.length > 0 && (
<div className="opc-sdlc-box-pending">Not yet promoted</div>
)}
</div>
</div>
</Fragment>
); );
})} })}
</div> </div>
{summary && (
<div className="opc-sdlc-furthest">
Furthest: <strong>{summary.label}</strong>
</div>
)}
</div> </div>
); );
})()} })()}