domain/architecture/system/plan/ops.bend

near-v-framework@0.4.0.0 · 126 lines · 12 definitions

1import Base
2import near-v-framework@0.4.0.0/domain/architecture/system/release/type.bend as Rl
3import near-v-framework@0.4.0.0/domain/architecture/system/release/ops.bend as RlO
4import near-v-framework@0.4.0.0/domain/architecture/system/plan/type.bend as P
5
6def visibility(p: Bool) -> String:
7  match p:
8    case True{}:
9      "public"
10    case False{}:
11      "private"
12
13# ---- the repository: Bend only and no dead code come first, then GitHub ----
14def repo_steps(+fs: List<&2, String>, +reached: List<&2, String>) -> List<&2, P.Step>:
15  List.append(&2, P.Step,
16    Bool.pick(List<&2, P.Step>, String.is_empty(RlO.not_bend(fs)), [],
17      [P.Blocked{"repository", RlO.not_bend(fs) ++ " is not Bend"}]),
18    List.append(&2, P.Step,
19      Bool.pick(List<&2, P.Step>, String.is_empty(RlO.dead(fs, reached)), [],
20        [P.Blocked{"repository", RlO.dead(fs, reached) ++ " is dead code: no entry reaches it"}]),
21      Bool.pick(List<&2, P.Step>, String.is_empty(RlO.hub_refused(reached)), [],
22        [P.Blocked{"repository", RlO.hub_refused(reached) ++ ": the Bend hub refuses this path (segments of letters, digits and _)"}])))
23
24def remote_step(+repo: Rl.Repository, rm: P.Remote) -> P.Step:
25  match repo rm:
26    case Rl.Repository{+name, +public} P.Remote{+origin, +vis, clean, pushed}:
27      Bool.pick(P.Step, String.contains(origin, name),
28        Bool.pick(P.Step, String.eq(vis, visibility(public)),
29          Bool.pick(P.Step, clean,
30            Bool.pick(P.Step, pushed, P.Current{"github " ++ name}, P.Push{name}),
31            P.Blocked{"github " ++ name, "uncommitted changes"}),
32          P.Blocked{"github " ++ name, "GitHub says " ++ Bool.pick(String, String.is_empty(vis), "nothing (unreachable)", vis) ++ ", declared " ++ visibility(public)}),
33        P.Blocked{"github " ++ name, "origin is " ++ origin})
34
35# ---- each package: already published as it is, new, or changed without a new version ----
36def package_step(p: Rl.Package, h: P.Hub) -> P.Step:
37  match p:
38    case Rl.Package{+n, +v, e, _}:
39      match h:
40        case P.Same{}:
41          P.Current{"package " ++ n ++ "@" ++ v}
42        case P.Unpublished{}:
43          P.Publish{n, v, e}
44        case P.Differs{f}:
45          P.Blocked{"package " ++ n ++ "@" ++ v, f ++ " changed since it was published; give it a new version"}
46
47def package_steps(ps: List<&2, Rl.Package>, hs: List<&2, P.Hub>) -> List<&2, P.Step>:
48  match ps:
49    case []:
50      []
51    case p <> prest:
52      match hs:
53        case []:
54          []
55        case h <> hrest:
56          package_step(p, h) <> package_steps(prest, hrest)
57
58# ---- each plugin: released as it builds, new, or changed without a new version ----
59def plugin_step(g: Rl.Plugin, t: P.Tag) -> P.Step:
60  match g t:
61    case Rl.Plugin{+n, +v, _, _, Rl.Repository{+r, _}} P.Tag{repo, tagged, +built, differs}:
62      +what = "plugin " ++ n ++ "@" ++ v
63      Bool.pick(P.Step, String.is_empty(built), P.Blocked{what, "does not build"},
64        Bool.pick(P.Step, Bool.not(String.eq(built, v)), P.Blocked{what, "builds as version " ++ built},
65          Bool.pick(P.Step, Bool.not(repo), P.ReleasePlugin{n, v, r, True{}},
66            Bool.pick(P.Step, Bool.not(tagged), P.ReleasePlugin{n, v, r, False{}},
67              Bool.pick(P.Step, differs, P.Blocked{what, "changed since " ++ n ++ "-v" ++ v ++ " was released; give it a new version"},
68                P.Current{what})))))
69
70def plugin_steps(gs: List<&2, Rl.Plugin>, ts: List<&2, P.Tag>) -> List<&2, P.Step>:
71  match gs:
72    case []:
73      []
74    case g <> grest:
75      match ts:
76        case []:
77          []
78        case t <> trest:
79          plugin_step(g, t) <> plugin_steps(grest, trest)
80
81# The plan: what a deploy would do, from the release and what was observed.
82def plan(r: Rl.Release, o: P.Observed) -> List<&2, P.Step>:
83  match r o:
84    case Rl.Release{repo, ps, gs} P.Observed{+fs, +reached, hs, rm, ts}:
85      List.append(&2, P.Step, repo_steps(fs, reached), List.append(&2, P.Step, package_steps(ps, hs),
86        List.append(&2, P.Step, plugin_steps(gs, ts), [remote_step(repo, rm)])))
87
88def blocked(s: P.Step) -> Bool:
89  match s:
90    case P.Blocked{_, _}:
91      True{}
92    case _:
93      False{}
94
95def any_blocked(ss: List<&2, P.Step>) -> Bool:
96  match ss:
97    case []:
98      False{}
99    case s <> rest:
100      blocked(s) || any_blocked(rest)
101
102def show(s: P.Step) -> String:
103  match s:
104    case P.Current{w}:
105      "current  " ++ w
106    case P.Publish{n, v, _}:
107      "publish  " ++ n ++ "@" ++ v
108    case P.Push{r}:
109      "push     github " ++ r
110    case P.ReleasePlugin{+n, +v, r, create}:
111      "release  plugin " ++ n ++ "@" ++ v ++ " to marketplace github " ++ r ++ " as tag " ++ n ++ "-v" ++ v ++ Bool.pick(String, create, " (a new repository)", "")
112    case P.Rebuild{h, _, _}:
113      "rebuild  nix-darwin " ++ h
114    case P.ServePort{p, t, _}:
115      "serve    :" ++ U32.show(p) ++ " -> " ++ t
116    case P.Change{w, now, want}:
117      "change   " ++ w ++ ": " ++ now ++ " -> " ++ want
118    case P.Blocked{w, why}:
119      "blocked  " ++ w ++ ": " ++ why
120
121def show_all(ss: List<&2, P.Step>) -> String:
122  match ss:
123    case []:
124      ""
125    case s <> rest:
126      show(s) ++ "\n" ++ show_all(rest)