• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

ory / keto / 22132777730

18 Feb 2026 08:47AM UTC coverage: 52.398% (+2.7%) from 49.747%
22132777730

push

github

ory-bot
feat: keto-cli improvements

GitOrigin-RevId: 7e569c384

235 of 372 new or added lines in 8 files covered. (63.17%)

3 existing lines in 3 files now uncovered.

4130 of 7882 relevant lines covered (52.4%)

0.58 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

58.33
/cmd/relationtuple/parse.go
1
// Copyright © 2023 Ory Corp
2
// SPDX-License-Identifier: Apache-2.0
3

4
package relationtuple
5

6
import (
7
        "fmt"
8
        "io"
9
        "strings"
10

11
        "github.com/spf13/cobra"
12

13
        "github.com/ory/x/cmdx"
14

15
        "github.com/ory/keto/ketoapi"
16
)
17

18
func NewParseCmd() *cobra.Command {
1✔
19
        cmd := &cobra.Command{
1✔
20
                Use:   "parse",
1✔
21
                Short: "Parse human readable relationships",
1✔
22
                Long: "Parse human readable relationships as used in the documentation.\n" +
1✔
23
                        "Supports various output formats. Especially useful for piping into other commands by using `--format json`.\n" +
1✔
24
                        "Ignores comments (lines starting with `//`) and blank lines.\n\n" +
1✔
25
                        "From file or folder:\n" +
1✔
26
                        "\tketo relation-tuple parse -f tuples1.txt -f tuples2.txt\n" +
1✔
27
                        "\tketo relation-tuple parse -f tuples-dir\n\n" +
1✔
28
                        "Use '-' as filename to read from STD_IN:\n" +
1✔
29
                        "\tketo relation-tuple parse -f -",
1✔
30
                Args: cobra.NoArgs,
1✔
31
                RunE: func(cmd *cobra.Command, args []string) error {
1✔
NEW
32
                        files, err := cmd.Flags().GetStringSlice(FlagFile)
×
NEW
33
                        if err != nil {
×
NEW
34
                                return err
×
NEW
35
                        }
×
NEW
36
                        if len(files) == 0 {
×
NEW
37
                                return fmt.Errorf("at least one file must be specified with -f")
×
NEW
38
                        }
×
39

40
                        var rts []*ketoapi.RelationTuple
×
NEW
41
                        for _, fn := range files {
×
NEW
42
                                rtss, err := readTuplesFromPath(cmd, fn, 0, parseHumanReadable)
×
43
                                if err != nil {
×
NEW
44
                                        _, _ = fmt.Fprintln(cmd.ErrOrStderr(), err.Error())
×
NEW
45
                                        return cmdx.FailSilently(cmd)
×
46
                                }
×
47
                                rts = append(rts, rtss...)
×
48
                        }
49

50
                        if len(rts) == 1 {
×
51
                                cmdx.PrintRow(cmd, rts[0])
×
52
                                return nil
×
53
                        }
×
54
                        cmdx.PrintTable(cmd, NewAPICollection(rts))
×
55
                        return nil
×
56
                },
57
        }
58

59
        registerFileFlag(cmd.Flags())
1✔
60
        cmdx.RegisterFormatFlags(cmd.Flags())
1✔
61

1✔
62
        return cmd
1✔
63
}
64

65
// parseHumanReadable reads human-readable relation tuples from the reader.
66
// Input is limited to MaxFileSizeBytes.
67
func parseHumanReadable(r io.Reader) ([]*ketoapi.RelationTuple, error) {
1✔
68
        fc, err := io.ReadAll(io.LimitReader(r, int64(MaxFileSizeBytes)+1))
1✔
69
        if err != nil {
1✔
NEW
70
                return nil, fmt.Errorf("reading input: %w", err)
×
NEW
71
        }
×
72
        if len(fc) > MaxFileSizeBytes {
1✔
NEW
73
                return nil, fmt.Errorf("input exceeds maximum size of %d bytes", MaxFileSizeBytes)
×
UNCOV
74
        }
×
75

76
        parts := strings.Split(string(fc), "\n")
1✔
77
        rts := make([]*ketoapi.RelationTuple, 0, len(parts))
1✔
78
        for i, row := range parts {
2✔
79
                row = strings.TrimSpace(row)
1✔
80
                // ignore comments and empty lines
1✔
81
                if row == "" || strings.HasPrefix(row, "//") {
2✔
82
                        continue
1✔
83
                }
84

85
                rt, err := (&ketoapi.RelationTuple{}).FromString(row)
1✔
86
                if err != nil {
2✔
87
                        return nil, fmt.Errorf("line %d: could not decode %q: %w", i+1, row, err)
1✔
88
                }
1✔
89
                rts = append(rts, rt)
1✔
90
        }
91

92
        return rts, nil
1✔
93
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc