Diffs name their chain; history shows the ruleset's diff
The ruleset's diff names the chain each hunk is in on its @@ line, as
git names the function. A history entry shows what it did to the
ruleset (web page, hc history diff, GET /history/{id}/diff), rebuilt
from the current configuration by stepping back through the later
entries. A changed setting is listed by its own fields
(builtins.drop_invalid) instead of the whole object.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
4e35236dba
commit
92147c8681
12 files changed
+289
-11
No files matched your search
+40
-1
@@ -66,6 +66,30 @@ func historyCmd() *cobra.Command {
|
||||
})
|
||||
},
|
||||
})
|
||||
cmd.AddCommand(&cobra.Command{
|
||||
Use: "diff ID", Short: "Show what a change did to the ruleset", Args: cobra.ExactArgs(1),
|
||||
Long: `Shows the ruleset's diff for a change: the configuration before and after
|
||||
it, rendered by this version of Housecarl.`,
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
c, err := newClient()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var d struct {
|
||||
Diff string `json:"diff"`
|
||||
}
|
||||
if err := c.Get(ctx(), "/history/"+args[0]+"/diff", nil, &d); err != nil {
|
||||
return err
|
||||
}
|
||||
return output(d, func(w io.Writer) {
|
||||
if d.Diff == "" {
|
||||
fmt.Fprintln(w, "the ruleset didn't change")
|
||||
return
|
||||
}
|
||||
printDiff(w, d.Diff)
|
||||
})
|
||||
},
|
||||
})
|
||||
cmd.AddCommand(&cobra.Command{
|
||||
Use: "undo ID",
|
||||
Short: "Undo a change",
|
||||
@@ -88,11 +112,13 @@ change touched has changed since; undo the later changes first.`,
|
||||
}
|
||||
|
||||
// diffJSON lists the fields that differ between two versions of an
|
||||
// object: "name: office -> lab".
|
||||
// object: "name: office -> lab". An object within (settings' builtins)
|
||||
// is compared field by field: "builtins.drop_invalid: false -> true".
|
||||
func diffJSON(before, after json.RawMessage) []string {
|
||||
var a, b map[string]any
|
||||
json.Unmarshal(before, &a)
|
||||
json.Unmarshal(after, &b)
|
||||
a, b = flatten(a, "", map[string]any{}), flatten(b, "", map[string]any{})
|
||||
keys := map[string]bool{}
|
||||
for k := range a {
|
||||
keys[k] = true
|
||||
@@ -132,6 +158,19 @@ func diffJSON(before, after json.RawMessage) []string {
|
||||
return out
|
||||
}
|
||||
|
||||
// flatten lifts the fields of objects within m to dotted keys; lists
|
||||
// stay whole.
|
||||
func flatten(m map[string]any, prefix string, out map[string]any) map[string]any {
|
||||
for k, v := range m {
|
||||
if o, ok := v.(map[string]any); ok && len(o) > 0 {
|
||||
flatten(o, prefix+k+".", out)
|
||||
} else {
|
||||
out[prefix+k] = v
|
||||
}
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
func whoamiCmd() *cobra.Command {
|
||||
return &cobra.Command{
|
||||
Use: "whoami", Short: "Show who you are to the server", Args: cobra.NoArgs,
|
||||
|
||||
Reference in new issue
Block a user