-
Notifications
You must be signed in to change notification settings - Fork 29
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(generate): generate pkl testing
- Loading branch information
1 parent
be65811
commit ee0c467
Showing
7 changed files
with
843 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
package generate | ||
|
||
import "github.com/spf13/cobra" | ||
|
||
var GenerateCmd = &cobra.Command{ | ||
Use: "generate", | ||
Short: "Generate code", | ||
Long: "Generate code to facilitate testing, modeling and working with OpenFGA.", | ||
} | ||
|
||
func init() { | ||
GenerateCmd.AddCommand(pklCmd) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,85 @@ | ||
package generate | ||
|
||
import ( | ||
"encoding/json" | ||
"fmt" | ||
"github.com/openfga/cli/internal/authorizationmodel" | ||
"github.com/openfga/cli/internal/cmdutils" | ||
"github.com/openfga/cli/internal/generate" | ||
"github.com/openfga/cli/internal/output" | ||
openfga "github.com/openfga/go-sdk" | ||
"github.com/spf13/cobra" | ||
) | ||
|
||
var pklCmd = &cobra.Command{ | ||
Use: "pkl", | ||
Short: "Generate pkl test utilities", | ||
Long: "Generate pkl test utilities based on the given model", | ||
Example: `fga generate pkl --file=model.json | ||
fga generate --file=fga.mod | ||
fga generate '{"type_definitions":[{"type":"user"},{"type":"document","relations":{"can_view":{"this":{}}},"metadata":{"relations":{"can_view":{"directly_related_user_types":[{"type":"user"}]}}}}],"schema_version":"1.1"}' --format=json | ||
fga generate --file=fga.mod --out=testing | ||
fga generate --file=fga.mod --out=testing --config='{"user": {"base_type_name": "Awesome"}}'`, //nolint:lll | ||
Args: cobra.MaximumNArgs(1), | ||
RunE: func(cmd *cobra.Command, args []string) error { | ||
clientConfig := cmdutils.GetClientConfig(cmd) | ||
|
||
_, err := clientConfig.GetFgaClient() | ||
if err != nil { | ||
return fmt.Errorf("failed to initialize FGA Client due to %w", err) | ||
} | ||
|
||
var inputModel string | ||
if err := authorizationmodel.ReadFromInputFileOrArg( | ||
cmd, | ||
args, | ||
"file", | ||
false, | ||
&inputModel, | ||
openfga.PtrString(""), | ||
&writeInputFormat); err != nil { | ||
return err //nolint:wrapcheck | ||
} | ||
|
||
authModel := authorizationmodel.AuthzModel{} | ||
|
||
err = authModel.ReadModelFromString(inputModel, writeInputFormat) | ||
if err != nil { | ||
return err //nolint:wrapcheck | ||
} | ||
|
||
out, err := cmd.Flags().GetString("out") | ||
if err != nil { | ||
return fmt.Errorf("failed to parse output directory due to %w", err) | ||
} | ||
config, err := cmd.Flags().GetString("config") | ||
if err != nil { | ||
return fmt.Errorf("failed to parse config due to %w", err) | ||
} | ||
cn := make(map[string]generate.PklConventionConfig) | ||
err = json.Unmarshal([]byte(config), &cn) | ||
if err != nil { | ||
return fmt.Errorf("failed to parse config content due to %w", err) | ||
} | ||
|
||
g := &generate.PklGenerator{ | ||
Model: authModel.TypeDefinitions, | ||
Convention: &generate.PklConvention{Config: cn}, | ||
} | ||
files, err := g.Generate() | ||
err = files.SaveAll(out) | ||
if err != nil { | ||
return fmt.Errorf("failed to save generated files due to %w", err) | ||
} | ||
return output.Display(fmt.Sprintf("generated files in directory %v successfully", out)) | ||
}, | ||
} | ||
|
||
var writeInputFormat = authorizationmodel.ModelFormatDefault | ||
|
||
func init() { | ||
pklCmd.Flags().String("out", "testing", "Output of testing directory") | ||
pklCmd.Flags().String("config", "{}", "Generator configurations") | ||
pklCmd.Flags().String("file", "", "File Name. The file should have the model in the JSON or DSL format") | ||
pklCmd.Flags().Var(&writeInputFormat, "format", `Authorization model input format. Can be "fga", "json", or "modular"`) //nolint:lll | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,94 @@ | ||
package generate | ||
|
||
import ( | ||
"errors" | ||
"fmt" | ||
"os" | ||
"path" | ||
) | ||
|
||
type GeneratedFile struct { | ||
Path string | ||
Content string | ||
OverrideIfExists bool | ||
} | ||
|
||
type GeneratedFiles struct { | ||
Files []GeneratedFile | ||
} | ||
|
||
func (f *GeneratedFiles) SaveAll(out string) error { | ||
for _, file := range f.Files { | ||
if err := file.Save(out); err != nil { | ||
return err | ||
} | ||
} | ||
return nil | ||
} | ||
|
||
func (f *GeneratedFile) Save(out string) error { | ||
if f.OverrideIfExists { | ||
if err := f.writeFile(out, f.Path, f.Content); err != nil { | ||
return err | ||
} | ||
} else { | ||
if err := f.writeFileIfNotExists(out, f.Path, f.Content); err != nil { | ||
return err | ||
} | ||
} | ||
return nil | ||
} | ||
|
||
func (f *GeneratedFile) writeFileIfNotExists(out, filePath, content string) error { | ||
pwd, err := os.Getwd() | ||
if err != nil { | ||
return fmt.Errorf("failed to get Working Directory %v", err) | ||
} | ||
|
||
file := path.Join(pwd, out, filePath) | ||
if _, err = os.Stat(file); errors.Is(err, os.ErrNotExist) { | ||
dir := path.Dir(file) | ||
err := os.MkdirAll(dir, os.ModePerm) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
f, err := os.Create(file) | ||
if err != nil { | ||
return err | ||
} | ||
defer f.Close() | ||
|
||
_, err = f.WriteString(content) | ||
if err != nil { | ||
return err | ||
} | ||
} | ||
return nil | ||
} | ||
|
||
func (f *GeneratedFile) writeFile(out, filePath, content string) error { | ||
pwd, err := os.Getwd() | ||
if err != nil { | ||
return fmt.Errorf("failed to get Working Directory %v", err) | ||
} | ||
|
||
fp := path.Join(pwd, out, filePath) | ||
dir := path.Dir(fp) | ||
err = os.MkdirAll(dir, os.ModePerm) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
file, err := os.OpenFile(fp, os.O_RDWR|os.O_CREATE|os.O_TRUNC, os.FileMode(0644)) | ||
if err != nil { | ||
return fmt.Errorf("failed to open or create file %v", err) | ||
} | ||
defer file.Close() | ||
|
||
_, err = file.WriteString(content) | ||
if err != nil { | ||
return err | ||
} | ||
return nil | ||
} |
Oops, something went wrong.