Skip to content

Commit 0e8cfc1

Browse files
committed
initial semantic refactoring
1 parent 6f87b9b commit 0e8cfc1

File tree

3 files changed

+71
-35
lines changed

3 files changed

+71
-35
lines changed

alpha/declcfg/write.go

Lines changed: 47 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ func NewMermaidWriter(opts ...MermaidOption) *MermaidWriter {
3333
m := &MermaidWriter{
3434
MinEdgeName: minEdgeName,
3535
SpecifiedPackageName: specifiedPackageName,
36+
UseV0Semantics: true,
3637
}
3738

3839
for _, opt := range opts {
@@ -53,9 +54,9 @@ func WithSpecifiedPackageName(specifiedPackageName string) MermaidOption {
5354
}
5455
}
5556

56-
func WithV0Semantics() MermaidOption {
57+
func WithV0Semantics(useV0Semantics bool) MermaidOption {
5758
return func(o *MermaidWriter) {
58-
o.UseV0Semantics = true
59+
o.UseV0Semantics = useV0Semantics
5960
}
6061
}
6162

@@ -131,7 +132,8 @@ func (writer *MermaidWriter) WriteChannels(cfg DeclarativeConfig, out io.Writer)
131132
}
132133

133134
var deprecatedPackage string
134-
deprecatedChannels := []string{}
135+
deprecatedChannelIDs := []string{}
136+
decoratedBundleIDs := map[string][]string{"deprecated": {}, "skipped": {}, "deprecatedskipped": {}}
135137
linkID := 0
136138
skippedLinkIDs := []string{}
137139

@@ -154,7 +156,7 @@ func (writer *MermaidWriter) WriteChannels(cfg DeclarativeConfig, out io.Writer)
154156
}
155157

156158
if depByChannel.Has(filteredChannel.Name) {
157-
deprecatedChannels = append(deprecatedChannels, channelID)
159+
deprecatedChannelIDs = append(deprecatedChannelIDs, channelID)
158160
}
159161

160162
// sort edges by decreasing version
@@ -169,29 +171,45 @@ func (writer *MermaidWriter) WriteChannels(cfg DeclarativeConfig, out io.Writer)
169171

170172
skippedEntities := sets.Set[string]{}
171173

174+
const (
175+
captureNewEntry = true
176+
processExisting = false
177+
)
178+
handleSemantics := func(edge string, linkID int, captureNew bool) {
179+
if writer.UseV0Semantics {
180+
if captureNew {
181+
if skippedEntities.Has(edge) {
182+
skippedLinkIDs = append(skippedLinkIDs, fmt.Sprintf("%d", linkID))
183+
} else {
184+
skippedEntities.Insert(edge)
185+
}
186+
} else {
187+
if skippedEntities.Has(edge) {
188+
skippedLinkIDs = append(skippedLinkIDs, fmt.Sprintf("%d", linkID))
189+
}
190+
}
191+
}
192+
}
193+
172194
for _, ce := range sortedEntries {
173-
bundleDecoration := ""
195+
entryID := fmt.Sprintf("%s-%s", channelID, ce.Name)
196+
fmt.Fprintf(pkgBuilder, " %s[%q]\n", entryID, ce.Name)
197+
198+
// mermaid allows specification of only a single decoration class, so any combinations must be independently represented
174199
switch {
175200
case depByBundle.Has(ce.Name) && skippedEntities.Has(ce.Name):
176-
bundleDecoration = ":::depandskip"
201+
decoratedBundleIDs["deprecatedskipped"] = append(decoratedBundleIDs["deprecatedskipped"], entryID)
177202
case depByBundle.Has(ce.Name):
178-
bundleDecoration = ":::deprecated"
203+
decoratedBundleIDs["deprecated"] = append(decoratedBundleIDs["deprecated"], entryID)
179204
case skippedEntities.Has(ce.Name):
180-
bundleDecoration = ":::skipped"
205+
decoratedBundleIDs["skipped"] = append(decoratedBundleIDs["skipped"], entryID)
181206
}
182207

183-
entryID := fmt.Sprintf("%s-%s", channelID, ce.Name)
184-
fmt.Fprintf(pkgBuilder, " %s[%q]%s\n", entryID, ce.Name, bundleDecoration)
185-
186208
if len(ce.Skips) > 0 {
187209
for _, s := range ce.Skips {
188210
skipsID := fmt.Sprintf("%s-%s", channelID, s)
189211
fmt.Fprintf(pkgBuilder, " %s[%q]-- %s --> %s[%q]\n", skipsID, s, "skip", entryID, ce.Name)
190-
if skippedEntities.Has(s) {
191-
skippedLinkIDs = append(skippedLinkIDs, fmt.Sprintf("%d", linkID))
192-
} else {
193-
skippedEntities.Insert(s)
194-
}
212+
handleSemantics(s, linkID, captureNewEntry)
195213
linkID++
196214
}
197215
}
@@ -202,9 +220,7 @@ func (writer *MermaidWriter) WriteChannels(cfg DeclarativeConfig, out io.Writer)
202220
if skipRange(versionMap[edgeName.Name]) {
203221
skipRangeID := fmt.Sprintf("%s-%s", channelID, edgeName.Name)
204222
fmt.Fprintf(pkgBuilder, " %s[%q]-- \"%s(%s)\" --> %s[%q]\n", skipRangeID, edgeName.Name, "skipRange", ce.SkipRange, entryID, ce.Name)
205-
if skippedEntities.Has(ce.Name) {
206-
skippedLinkIDs = append(skippedLinkIDs, fmt.Sprintf("%d", linkID))
207-
}
223+
handleSemantics(ce.Name, linkID, processExisting)
208224
linkID++
209225
}
210226
}
@@ -216,9 +232,7 @@ func (writer *MermaidWriter) WriteChannels(cfg DeclarativeConfig, out io.Writer)
216232
if len(ce.Replaces) > 0 {
217233
replacesID := fmt.Sprintf("%s-%s", channelID, ce.Replaces)
218234
fmt.Fprintf(pkgBuilder, " %s[%q]-- %s --> %s[%q]\n", replacesID, ce.Replaces, "replace", entryID, ce.Name)
219-
if skippedEntities.Has(ce.Name) {
220-
skippedLinkIDs = append(skippedLinkIDs, fmt.Sprintf("%d", linkID))
221-
}
235+
handleSemantics(ce.Name, linkID, processExisting)
222236
linkID++
223237
}
224238
}
@@ -229,7 +243,7 @@ func (writer *MermaidWriter) WriteChannels(cfg DeclarativeConfig, out io.Writer)
229243
_, _ = out.Write([]byte("graph LR\n"))
230244
_, _ = out.Write([]byte(" classDef deprecated fill:#E8960F\n"))
231245
_, _ = out.Write([]byte(" classDef skipped stroke:#FF0000,stroke-width:4px\n"))
232-
_, _ = out.Write([]byte(" classDef depandskip fill:#E8960,stroke:#FF0000,stroke-width:4px\n"))
246+
_, _ = out.Write([]byte(" classDef deprecatedskipped fill:#E8960F,stroke:#FF0000,stroke-width:4px\n"))
233247
pkgNames := []string{}
234248
for pname := range pkgs {
235249
pkgNames = append(pkgNames, pname)
@@ -248,14 +262,21 @@ func (writer *MermaidWriter) WriteChannels(cfg DeclarativeConfig, out io.Writer)
248262
_, _ = out.Write([]byte(fmt.Sprintf("style %s fill:#989695\n", deprecatedPackage)))
249263
}
250264

251-
if len(deprecatedChannels) > 0 {
252-
for _, deprecatedChannel := range deprecatedChannels {
265+
if len(deprecatedChannelIDs) > 0 {
266+
for _, deprecatedChannel := range deprecatedChannelIDs {
253267
_, _ = out.Write([]byte(fmt.Sprintf("style %s fill:#DCD0FF\n", deprecatedChannel)))
254268
}
255269
}
256270

271+
// express the decoration classes
272+
for key := range decoratedBundleIDs {
273+
if len(decoratedBundleIDs[key]) > 0 {
274+
_, _ = out.Write([]byte(fmt.Sprintf("class %s %s\n", strings.Join(decoratedBundleIDs[key], ","), key)))
275+
}
276+
}
277+
257278
if len(skippedLinkIDs) > 0 {
258-
_, _ = out.Write([]byte("linkStyle " + strings.Join(skippedLinkIDs, ",") + " stroke:#FF0000,stroke-width:3px,stroke-dasharray:5;"))
279+
_, _ = out.Write([]byte("linkStyle " + strings.Join(skippedLinkIDs, ",") + " stroke:#FF0000,stroke-width:3px,stroke-dasharray:5;\n"))
259280
}
260281

261282
return nil

alpha/declcfg/write_test.go

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -527,35 +527,40 @@ func TestWriteMermaidChannels(t *testing.T) {
527527
packageFilter: "",
528528
expected: `graph LR
529529
classDef deprecated fill:#E8960F
530+
classDef skipped stroke:#FF0000,stroke-width:4px
531+
classDef deprecatedskipped fill:#E8960F,stroke:#FF0000,stroke-width:4px
530532
%% package "anakin"
531533
subgraph "anakin"
532534
%% channel "dark"
533535
subgraph anakin-dark["dark"]
534-
anakin-dark-anakin.v0.0.1["anakin.v0.0.1"]:::deprecated
535-
anakin-dark-anakin.v0.1.0["anakin.v0.1.0"]
536-
anakin-dark-anakin.v0.0.1["anakin.v0.0.1"]-- replace --> anakin-dark-anakin.v0.1.0["anakin.v0.1.0"]
537536
anakin-dark-anakin.v0.1.1["anakin.v0.1.1"]
538-
anakin-dark-anakin.v0.0.1["anakin.v0.0.1"]-- replace --> anakin-dark-anakin.v0.1.1["anakin.v0.1.1"]
539537
anakin-dark-anakin.v0.1.0["anakin.v0.1.0"]-- skip --> anakin-dark-anakin.v0.1.1["anakin.v0.1.1"]
538+
anakin-dark-anakin.v0.0.1["anakin.v0.0.1"]-- replace --> anakin-dark-anakin.v0.1.1["anakin.v0.1.1"]
539+
anakin-dark-anakin.v0.1.0["anakin.v0.1.0"]
540+
anakin-dark-anakin.v0.0.1["anakin.v0.0.1"]-- replace --> anakin-dark-anakin.v0.1.0["anakin.v0.1.0"]
541+
anakin-dark-anakin.v0.0.1["anakin.v0.0.1"]
540542
end
541543
%% channel "light"
542544
subgraph anakin-light["light"]
543-
anakin-light-anakin.v0.0.1["anakin.v0.0.1"]:::deprecated
544545
anakin-light-anakin.v0.1.0["anakin.v0.1.0"]
545546
anakin-light-anakin.v0.0.1["anakin.v0.0.1"]-- replace --> anakin-light-anakin.v0.1.0["anakin.v0.1.0"]
547+
anakin-light-anakin.v0.0.1["anakin.v0.0.1"]
546548
end
547549
end
548550
%% package "boba-fett"
549551
subgraph "boba-fett"
550552
%% channel "mando"
551553
subgraph boba-fett-mando["mando"]
552-
boba-fett-mando-boba-fett.v1.0.0["boba-fett.v1.0.0"]
553554
boba-fett-mando-boba-fett.v2.0.0["boba-fett.v2.0.0"]
554555
boba-fett-mando-boba-fett.v1.0.0["boba-fett.v1.0.0"]-- replace --> boba-fett-mando-boba-fett.v2.0.0["boba-fett.v2.0.0"]
556+
boba-fett-mando-boba-fett.v1.0.0["boba-fett.v1.0.0"]
555557
end
556558
end
557559
style anakin fill:#989695
558560
style anakin-light fill:#DCD0FF
561+
class anakin-dark-anakin.v0.0.1,anakin-light-anakin.v0.0.1 deprecated
562+
class anakin-dark-anakin.v0.1.0 skipped
563+
linkStyle 2 stroke:#FF0000,stroke-width:3px,stroke-dasharray:5;
559564
`,
560565
},
561566
{
@@ -565,13 +570,15 @@ style anakin-light fill:#DCD0FF
565570
packageFilter: "",
566571
expected: `graph LR
567572
classDef deprecated fill:#E8960F
573+
classDef skipped stroke:#FF0000,stroke-width:4px
574+
classDef deprecatedskipped fill:#E8960F,stroke:#FF0000,stroke-width:4px
568575
%% package "anakin"
569576
subgraph "anakin"
570577
%% channel "dark"
571578
subgraph anakin-dark["dark"]
572-
anakin-dark-anakin.v0.1.0["anakin.v0.1.0"]
573579
anakin-dark-anakin.v0.1.1["anakin.v0.1.1"]
574580
anakin-dark-anakin.v0.1.0["anakin.v0.1.0"]-- skip --> anakin-dark-anakin.v0.1.1["anakin.v0.1.1"]
581+
anakin-dark-anakin.v0.1.0["anakin.v0.1.0"]
575582
end
576583
%% channel "light"
577584
subgraph anakin-light["light"]
@@ -580,6 +587,7 @@ style anakin-light fill:#DCD0FF
580587
end
581588
style anakin fill:#989695
582589
style anakin-light fill:#DCD0FF
590+
class anakin-dark-anakin.v0.1.0 skipped
583591
`,
584592
},
585593
{
@@ -589,13 +597,15 @@ style anakin-light fill:#DCD0FF
589597
packageFilter: "boba-fett",
590598
expected: `graph LR
591599
classDef deprecated fill:#E8960F
600+
classDef skipped stroke:#FF0000,stroke-width:4px
601+
classDef deprecatedskipped fill:#E8960F,stroke:#FF0000,stroke-width:4px
592602
%% package "boba-fett"
593603
subgraph "boba-fett"
594604
%% channel "mando"
595605
subgraph boba-fett-mando["mando"]
596-
boba-fett-mando-boba-fett.v1.0.0["boba-fett.v1.0.0"]
597606
boba-fett-mando-boba-fett.v2.0.0["boba-fett.v2.0.0"]
598607
boba-fett-mando-boba-fett.v1.0.0["boba-fett.v1.0.0"]-- replace --> boba-fett-mando-boba-fett.v2.0.0["boba-fett.v2.0.0"]
608+
boba-fett-mando-boba-fett.v1.0.0["boba-fett.v1.0.0"]
599609
end
600610
end
601611
`,

cmd/opm/alpha/render-graph/cmd.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ func NewCmd() *cobra.Command {
1818
render action.Render
1919
minEdge string
2020
specifiedPackageName string
21+
includeV0Semantics bool
2122
)
2223
cmd := &cobra.Command{
2324
Use: "render-graph [index-image | fbc-dir]",
@@ -67,13 +68,17 @@ $ opm alpha render-graph quay.io/operatorhubio/catalog:latest | \
6768
log.Fatal(err)
6869
}
6970

70-
writer := declcfg.NewMermaidWriter(declcfg.WithMinEdgeName(minEdge), declcfg.WithSpecifiedPackageName(specifiedPackageName))
71+
writer := declcfg.NewMermaidWriter(
72+
declcfg.WithMinEdgeName(minEdge),
73+
declcfg.WithSpecifiedPackageName(specifiedPackageName),
74+
declcfg.WithV0Semantics(includeV0Semantics))
7175
if err := writer.WriteChannels(*cfg, os.Stdout); err != nil {
7276
log.Fatal(err)
7377
}
7478
},
7579
}
7680
cmd.Flags().StringVar(&minEdge, "minimum-edge", "", "the channel edge to be used as the lower bound of the set of edges composing the upgrade graph; default is to include all edges")
7781
cmd.Flags().StringVarP(&specifiedPackageName, "package-name", "p", "", "a specific package name to filter output; default is to include all packages in reference")
82+
cmd.Flags().BoolVar(&includeV0Semantics, "include-v0-semantics", false, "whether to indicate OLMv0 semantics in the output; default is to simply represent the upgrade graph")
7883
return cmd
7984
}

0 commit comments

Comments
 (0)