Skip to content

Commit c4f3429

Browse files
grokspawntimflannagan
authored andcommitted
relocate mermaid channel writer (openshift#987)
Signed-off-by: Jordan Keister <[email protected]> Upstream-repository: operator-registry Upstream-commit: 524a11c9271d1b655d2427d4e7c5d39430faea80
1 parent 6c8e86c commit c4f3429

File tree

9 files changed

+225
-60
lines changed

9 files changed

+225
-60
lines changed

staging/operator-registry/alpha/declcfg/write.go

+81
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,94 @@ package declcfg
33
import (
44
"bytes"
55
"encoding/json"
6+
"fmt"
67
"io"
78
"sort"
9+
"strings"
810

911
"k8s.io/apimachinery/pkg/util/sets"
1012
"sigs.k8s.io/yaml"
1113
)
1214

15+
// writes out the channel edges of the declarative config graph in a mermaid format capable of being pasted into
16+
// mermaid renderers like github, mermaid.live, etc.
17+
// output is sorted lexicographically by package name, and then by channel name
18+
//
19+
// NB: Output has wrapper comments stating the skipRange edge caveat in HTML comment format, which cannot be parsed by mermaid renderers.
20+
// This is deliberate, and intended as an explicit acknowledgement of the limitations, instead of requiring the user to notice the missing edges upon inspection.
21+
//
22+
// Example output:
23+
// <!-- PLEASE NOTE: skipRange edges are not currently displayed -->
24+
// graph LR
25+
// %% package "neuvector-certified-operator-rhmp"
26+
// subgraph "neuvector-certified-operator-rhmp"
27+
// %% channel "beta"
28+
// subgraph neuvector-certified-operator-rhmp-beta["beta"]
29+
// neuvector-certified-operator-rhmp-beta-neuvector-operator.v1.2.8["neuvector-operator.v1.2.8"]
30+
// neuvector-certified-operator-rhmp-beta-neuvector-operator.v1.2.9["neuvector-operator.v1.2.9"]
31+
// neuvector-certified-operator-rhmp-beta-neuvector-operator.v1.3.0["neuvector-operator.v1.3.0"]
32+
// neuvector-certified-operator-rhmp-beta-neuvector-operator.v1.3.0["neuvector-operator.v1.3.0"]-- replaces --> neuvector-certified-operator-rhmp-beta-neuvector-operator.v1.2.8["neuvector-operator.v1.2.8"]
33+
// neuvector-certified-operator-rhmp-beta-neuvector-operator.v1.3.0["neuvector-operator.v1.3.0"]-- skips --> neuvector-certified-operator-rhmp-beta-neuvector-operator.v1.2.9["neuvector-operator.v1.2.9"]
34+
// end
35+
// end
36+
// end
37+
// <!-- PLEASE NOTE: skipRange edges are not currently displayed -->
38+
func WriteMermaidChannels(cfg DeclarativeConfig, out io.Writer) error {
39+
pkgs := map[string]*strings.Builder{}
40+
41+
sort.Slice(cfg.Channels, func(i, j int) bool {
42+
return cfg.Channels[i].Name < cfg.Channels[j].Name
43+
})
44+
45+
for _, c := range cfg.Channels {
46+
pkgBuilder, ok := pkgs[c.Package]
47+
if !ok {
48+
pkgBuilder = &strings.Builder{}
49+
pkgs[c.Package] = pkgBuilder
50+
}
51+
channelID := fmt.Sprintf("%s-%s", c.Package, c.Name)
52+
pkgBuilder.WriteString(fmt.Sprintf(" %%%% channel %q\n", c.Name))
53+
pkgBuilder.WriteString(fmt.Sprintf(" subgraph %s[%q]\n", channelID, c.Name))
54+
55+
for _, ce := range c.Entries {
56+
entryId := fmt.Sprintf("%s-%s", channelID, ce.Name)
57+
pkgBuilder.WriteString(fmt.Sprintf(" %s[%q]\n", entryId, ce.Name))
58+
59+
// no support for SkipRange yet
60+
if len(ce.Replaces) > 0 {
61+
replacesId := fmt.Sprintf("%s-%s", channelID, ce.Replaces)
62+
pkgBuilder.WriteString(fmt.Sprintf(" %s[%q]-- %s --> %s[%q]\n", entryId, ce.Name, "replaces", replacesId, ce.Replaces))
63+
}
64+
if len(ce.Skips) > 0 {
65+
for _, s := range ce.Skips {
66+
skipsId := fmt.Sprintf("%s-%s", channelID, s)
67+
pkgBuilder.WriteString(fmt.Sprintf(" %s[%q]-- %s --> %s[%q]\n", entryId, ce.Name, "skips", skipsId, s))
68+
}
69+
}
70+
}
71+
pkgBuilder.WriteString(" end\n")
72+
}
73+
74+
out.Write([]byte("<!-- PLEASE NOTE: skipRange edges are not currently displayed -->\n"))
75+
out.Write([]byte("graph LR\n"))
76+
pkgNames := []string{}
77+
for pname, _ := range pkgs {
78+
pkgNames = append(pkgNames, pname)
79+
}
80+
sort.Slice(pkgNames, func(i, j int) bool {
81+
return pkgNames[i] < pkgNames[j]
82+
})
83+
for _, pkgName := range pkgNames {
84+
out.Write([]byte(fmt.Sprintf(" %%%% package %q\n", pkgName)))
85+
out.Write([]byte(fmt.Sprintf(" subgraph %q\n", pkgName)))
86+
out.Write([]byte(pkgs[pkgName].String()))
87+
out.Write([]byte(" end\n"))
88+
}
89+
out.Write([]byte("<!-- PLEASE NOTE: skipRange edges are not currently displayed -->\n"))
90+
91+
return nil
92+
}
93+
1394
func WriteJSON(cfg DeclarativeConfig, w io.Writer) error {
1495
enc := json.NewEncoder(w)
1596
enc.SetIndent("", " ")

staging/operator-registry/alpha/declcfg/write_test.go

+53
Original file line numberDiff line numberDiff line change
@@ -469,3 +469,56 @@ func removeJSONWhitespace(cfg *DeclarativeConfig) {
469469
cfg.Others[io].Blob = buf.Bytes()
470470
}
471471
}
472+
473+
func TestWriteMermaidChannels(t *testing.T) {
474+
type spec struct {
475+
name string
476+
cfg DeclarativeConfig
477+
expected string
478+
}
479+
specs := []spec{
480+
{
481+
name: "Success",
482+
cfg: buildValidDeclarativeConfig(true),
483+
expected: `<!-- PLEASE NOTE: skipRange edges are not currently displayed -->
484+
graph LR
485+
%% package "anakin"
486+
subgraph "anakin"
487+
%% channel "dark"
488+
subgraph anakin-dark["dark"]
489+
anakin-dark-anakin.v0.0.1["anakin.v0.0.1"]
490+
anakin-dark-anakin.v0.1.0["anakin.v0.1.0"]
491+
anakin-dark-anakin.v0.1.0["anakin.v0.1.0"]-- replaces --> anakin-dark-anakin.v0.0.1["anakin.v0.0.1"]
492+
anakin-dark-anakin.v0.1.1["anakin.v0.1.1"]
493+
anakin-dark-anakin.v0.1.1["anakin.v0.1.1"]-- replaces --> anakin-dark-anakin.v0.0.1["anakin.v0.0.1"]
494+
anakin-dark-anakin.v0.1.1["anakin.v0.1.1"]-- skips --> anakin-dark-anakin.v0.1.0["anakin.v0.1.0"]
495+
end
496+
%% channel "light"
497+
subgraph anakin-light["light"]
498+
anakin-light-anakin.v0.0.1["anakin.v0.0.1"]
499+
anakin-light-anakin.v0.1.0["anakin.v0.1.0"]
500+
anakin-light-anakin.v0.1.0["anakin.v0.1.0"]-- replaces --> anakin-light-anakin.v0.0.1["anakin.v0.0.1"]
501+
end
502+
end
503+
%% package "boba-fett"
504+
subgraph "boba-fett"
505+
%% channel "mando"
506+
subgraph boba-fett-mando["mando"]
507+
boba-fett-mando-boba-fett.v1.0.0["boba-fett.v1.0.0"]
508+
boba-fett-mando-boba-fett.v2.0.0["boba-fett.v2.0.0"]
509+
boba-fett-mando-boba-fett.v2.0.0["boba-fett.v2.0.0"]-- replaces --> boba-fett-mando-boba-fett.v1.0.0["boba-fett.v1.0.0"]
510+
end
511+
end
512+
<!-- PLEASE NOTE: skipRange edges are not currently displayed -->
513+
`,
514+
},
515+
}
516+
for _, s := range specs {
517+
t.Run(s.name, func(t *testing.T) {
518+
var buf bytes.Buffer
519+
err := WriteMermaidChannels(s.cfg, &buf)
520+
require.NoError(t, err)
521+
require.Equal(t, s.expected, buf.String())
522+
})
523+
}
524+
}

staging/operator-registry/alpha/veneer/semver/semver.go

-27
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,8 @@
11
package semver
22

33
import (
4-
"bytes"
54
"context"
65
"fmt"
7-
"io"
86
"io/ioutil"
97
"sort"
108

@@ -421,31 +419,6 @@ func getMinorVersion(v semver.Version) semver.Version {
421419
}
422420
}
423421

424-
func MermaidChannelWriter(cfg declcfg.DeclarativeConfig, out io.Writer) error {
425-
for _, c := range cfg.Channels {
426-
var buf bytes.Buffer
427-
428-
buf.WriteString(fmt.Sprintf("<-- Channel %q --> \n", c.Name))
429-
buf.WriteString("graph LR\n")
430-
431-
for _, ce := range c.Entries {
432-
433-
// no support for SkipRange yet
434-
buf.WriteString(fmt.Sprintf("%s\n", ce.Name))
435-
if len(ce.Replaces) > 0 {
436-
buf.WriteString(fmt.Sprintf("%s-- %s --> %s\n", ce.Name, "replaces", ce.Replaces))
437-
}
438-
if len(ce.Skips) > 0 {
439-
for _, s := range ce.Skips {
440-
buf.WriteString(fmt.Sprintf("%s-- %s --> %s\n", ce.Name, "skips", s))
441-
}
442-
}
443-
}
444-
out.Write(buf.Bytes())
445-
}
446-
return nil
447-
}
448-
449422
func withoutBuildMetadataConflict(versions *map[string]semver.Version) error {
450423
errs := []error{}
451424

staging/operator-registry/cmd/opm/alpha/veneer/semver.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ func newSemverCmd() *cobra.Command {
3737
case "yaml":
3838
write = declcfg.WriteYAML
3939
case "mermaid":
40-
write = semver.MermaidChannelWriter
40+
write = declcfg.WriteMermaidChannels
4141
default:
4242
return fmt.Errorf("invalid output format %q", output)
4343
}

staging/operator-registry/cmd/opm/render/cmd.go

+4-2
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,10 @@ func NewCmd() *cobra.Command {
3737
write = declcfg.WriteYAML
3838
case "json":
3939
write = declcfg.WriteJSON
40+
case "mermaid":
41+
write = declcfg.WriteMermaidChannels
4042
default:
41-
log.Fatalf("invalid --output value %q, expected (json|yaml)", output)
43+
log.Fatalf("invalid --output value %q, expected (json|yaml|mermaid)", output)
4244
}
4345

4446
// The bundle loading impl is somewhat verbose, even on the happy path,
@@ -79,7 +81,7 @@ func NewCmd() *cobra.Command {
7981
}
8082
},
8183
}
82-
cmd.Flags().StringVarP(&output, "output", "o", "json", "Output format (json|yaml)")
84+
cmd.Flags().StringVarP(&output, "output", "o", "json", "Output format (json|yaml|mermaid)")
8385
cmd.Flags().Bool("skip-tls-verify", false, "disable TLS verification")
8486
cmd.Flags().Bool("use-http", false, "use plain HTTP")
8587
return cmd

vendor/github.com/operator-framework/operator-registry/alpha/declcfg/write.go

+81
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

vendor/github.com/operator-framework/operator-registry/alpha/veneer/semver/semver.go

-27
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

vendor/github.com/operator-framework/operator-registry/cmd/opm/alpha/veneer/semver.go

+1-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

vendor/github.com/operator-framework/operator-registry/cmd/opm/render/cmd.go

+4-2
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)