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