-
Notifications
You must be signed in to change notification settings - Fork 39
feat(sdk): source-file codegen for EntityIdentifier helpers #3232
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
15 commits
Select commit
Hold shift + click to select a range
4a27c96
feat(sdk): add ergonomic EntityIdentifier constructors for authorizat…
marythought 58ef471
refactor(sdk): move EntityIdentifier helpers to protocol/go/authoriza…
marythought 70823f9
chore(deps): go mod tidy for protocol/go (testify dependency)
marythought d856ec9
chore(sdk): use stdlib testing instead of testify in entity_identifie…
marythought 89f9154
chore(sdk): refactor entity identifier tests to table-driven with edg…
marythought 0f17ccc
refactor(sdk): move EntityIdentifier helpers to sdk package
marythought fbfd822
refactor(sdk): source-file codegen for EntityIdentifier helpers
marythought a3e7f2e
chore(sdk): add unit tests for codegen import rewriting
marythought a7e4a82
fix(sdk): remove stale .gen.go files before copying helpers
marythought cde41d0
fix(ci): exclude codegen and helpers from proto-generate cleanup
marythought f5130f9
fix(ci): trigger proto-generate check on codegen and Makefile changes
marythought f196ffe
refactor(sdk): rename helpers/ to internal/, buffer codegen writes
marythought 7a155ef
refactor(sdk): move proto helper codegen to separate module
marythought 37fa13a
refactor(sdk): add local go.work for protocol/codegen
marythought 54c5bef
chore(sdk): review feedback — tests, cleanup, and polish
marythought File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or 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 hidden or 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 hidden or 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,3 @@ | ||
| module github.com/opentdf/platform/protocol/codegen | ||
|
|
||
| go 1.25.5 |
This file contains hidden or 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,5 @@ | ||
| // Isolate this module from the root workspace so `go run .` resolves locally | ||
| // without adding protocol/codegen to the root go.work. | ||
| go 1.25.5 | ||
|
|
||
| use . |
This file contains hidden or 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,157 @@ | ||
| // Command codegen copies helper source files from protocol/go/internal/ into their | ||
|
marythought marked this conversation as resolved.
|
||
| // corresponding proto package directories with a "Code generated" header prepended. | ||
| // Helper source files import proto types explicitly for IDE support; the copier strips | ||
| // the self-referencing import and type qualifiers so the output compiles in-package. | ||
| // | ||
| // See https://github.com/opentdf/platform/pull/3232 for background on the source-file codegen approach. | ||
| package main | ||
|
|
||
| import ( | ||
| "errors" | ||
| "fmt" | ||
| "log" | ||
| "os" | ||
| "path/filepath" | ||
| "regexp" | ||
| "runtime" | ||
| "strings" | ||
| ) | ||
|
|
||
| // helperMapping defines a source directory (relative to protocol/go/internal/) and its | ||
| // target directory (relative to protocol/go/) where files will be copied. | ||
| type helperMapping struct { | ||
| // Source is the subdirectory under internal/ containing the source files. | ||
| Source string | ||
| // Target is the subdirectory under protocol/go/ where files are copied. | ||
| Target string | ||
| // ProtoImportPath is the full Go import path of the target proto package. | ||
| ProtoImportPath string | ||
| // ProtoImportAlias is the import alias used in the source files for the proto package. | ||
| ProtoImportAlias string | ||
| } | ||
|
|
||
| var mappings = []helperMapping{ | ||
| { | ||
| Source: "authorization/v2", | ||
| Target: "authorization/v2", | ||
| ProtoImportPath: "github.com/opentdf/platform/protocol/go/authorization/v2", | ||
| ProtoImportAlias: "authorizationv2", | ||
| }, | ||
| } | ||
|
|
||
| const generatedHeader = "// Code generated by protocol/codegen. DO NOT EDIT.\n\n" | ||
|
|
||
| func main() { | ||
| baseDir, err := getBaseDir() | ||
| if err != nil { | ||
| log.Fatal(err) | ||
| } | ||
|
|
||
| helpersDir := filepath.Join(baseDir, "internal") | ||
| for _, m := range mappings { | ||
| srcDir := filepath.Join(helpersDir, m.Source) | ||
| dstDir := filepath.Join(baseDir, m.Target) | ||
| if err := copyHelpers(srcDir, dstDir, m); err != nil { | ||
| log.Fatalf("copying helpers from %s to %s: %v", srcDir, dstDir, err) | ||
| } | ||
| } | ||
| } | ||
|
|
||
| // generatedFile holds a transformed helper ready to write. | ||
| type generatedFile struct { | ||
| dst string | ||
| content []byte | ||
| src string | ||
| } | ||
|
|
||
| func copyHelpers(srcDir, dstDir string, m helperMapping) error { | ||
| entries, err := os.ReadDir(srcDir) | ||
| if err != nil { | ||
| return fmt.Errorf("reading source directory: %w", err) | ||
| } | ||
|
|
||
| // Read and transform all source files before touching the target directory. | ||
| var files []generatedFile | ||
| for _, entry := range entries { | ||
| name := entry.Name() | ||
| if entry.IsDir() || !strings.HasSuffix(name, ".go") || strings.HasSuffix(name, "_test.go") { | ||
| continue | ||
| } | ||
|
|
||
| src := filepath.Join(srcDir, name) | ||
| content, err := os.ReadFile(src) | ||
| if err != nil { | ||
| return fmt.Errorf("reading %s: %w", src, err) | ||
| } | ||
|
|
||
| transformed := rewriteImports(string(content), m) | ||
| outName := strings.TrimSuffix(name, ".go") + ".gen.go" | ||
|
|
||
| files = append(files, generatedFile{ | ||
| dst: filepath.Join(dstDir, outName), | ||
| content: []byte(generatedHeader + transformed), | ||
| src: src, | ||
| }) | ||
| } | ||
|
|
||
| // Only remove stale .gen.go files once all reads succeeded. | ||
| if err := removeGenFiles(dstDir); err != nil { | ||
| return fmt.Errorf("cleaning target directory: %w", err) | ||
| } | ||
|
|
||
| for _, f := range files { | ||
| if err := os.WriteFile(f.dst, f.content, 0o644); err != nil { | ||
| return fmt.Errorf("writing %s: %w", f.dst, err) | ||
| } | ||
| fmt.Printf(" %s -> %s\n", f.src, f.dst) | ||
| } | ||
| return nil | ||
| } | ||
|
|
||
| func removeGenFiles(dir string) error { | ||
| entries, err := os.ReadDir(dir) | ||
| if err != nil { | ||
| return fmt.Errorf("reading directory: %w", err) | ||
| } | ||
| for _, entry := range entries { | ||
| if !entry.IsDir() && strings.HasSuffix(entry.Name(), ".gen.go") { | ||
| if err := os.Remove(filepath.Join(dir, entry.Name())); err != nil { | ||
| return fmt.Errorf("removing %s: %w", entry.Name(), err) | ||
| } | ||
| } | ||
| } | ||
| return nil | ||
| } | ||
|
|
||
| // rewriteImports removes the self-referencing proto import and strips the alias qualifier | ||
| // from type references so the file compiles inside the proto package. | ||
| // | ||
| // The qualifier regex also matches inside string literals and comments. This is acceptable | ||
| // because we control the source files and don't use the alias in non-code contexts. | ||
| func rewriteImports(content string, m helperMapping) string { | ||
| // Remove the import line: `authorizationv2 "github.com/.../authorization/v2"` | ||
| importLineRe := regexp.MustCompile( | ||
| `(?m)^\s*` + regexp.QuoteMeta(m.ProtoImportAlias) + `\s+"` + regexp.QuoteMeta(m.ProtoImportPath) + `"\s*\n`, | ||
| ) | ||
| content = importLineRe.ReplaceAllString(content, "") | ||
|
|
||
| // Strip the alias qualifier from type references: `authorizationv2.Foo` -> `Foo` | ||
| qualifierRe := regexp.MustCompile(regexp.QuoteMeta(m.ProtoImportAlias) + `\.`) | ||
| content = qualifierRe.ReplaceAllString(content, "") | ||
|
|
||
| // Clean up empty import blocks left behind when the proto import was the only one. | ||
| emptyImportRe := regexp.MustCompile(`\nimport \(\n\)\n`) | ||
| content = emptyImportRe.ReplaceAllString(content, "") | ||
|
|
||
| return content | ||
| } | ||
|
coderabbitai[bot] marked this conversation as resolved.
|
||
|
|
||
| // getBaseDir returns the protocol/go/ directory by navigating from this file's location. | ||
| // From protocol/codegen/main.go, go up two levels to protocol/, then into go/. | ||
| func getBaseDir() (string, error) { | ||
| _, filename, _, ok := runtime.Caller(0) | ||
| if !ok { | ||
| return "", errors.New("could not determine current file location") | ||
| } | ||
| return filepath.Join(filepath.Dir(filepath.Dir(filename)), "go"), nil | ||
| } | ||
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.