From a43ddd318ece46199d9a312a83874d2eca986034 Mon Sep 17 00:00:00 2001 From: Christian Mesh Date: Wed, 15 Nov 2023 09:24:16 -0500 Subject: [PATCH 1/8] Move common file output to single package --- src/internal/files/files.go | 1 + src/internal/repository-metadata-files/provider/create.go | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/internal/files/files.go b/src/internal/files/files.go index 2f7bc8c03a..895be8a567 100644 --- a/src/internal/files/files.go +++ b/src/internal/files/files.go @@ -11,6 +11,7 @@ func SafeWriteObjectToJsonFile(filePath string, data interface{}) error { marshalledJson, err := json.MarshalIndent(data, "", " ") if err != nil { return fmt.Errorf("failed to marshal for %s: %w", filePath, err) + } err = os.MkdirAll(path.Dir(filePath), 0755) diff --git a/src/internal/repository-metadata-files/provider/create.go b/src/internal/repository-metadata-files/provider/create.go index 69c73b6092..0b9acdff13 100644 --- a/src/internal/repository-metadata-files/provider/create.go +++ b/src/internal/repository-metadata-files/provider/create.go @@ -13,7 +13,7 @@ func CreateMetadataFile(p provider.Provider, providerDataDir string) error { if err != nil { return err } - + filePath := getFilePath(p, providerDataDir) return files.SafeWriteObjectToJsonFile(filePath, repositoryFileData) } From 64e19ebd69315e979380fcfccf3a9d70d7abfc68 Mon Sep 17 00:00:00 2001 From: Christian Mesh Date: Wed, 15 Nov 2023 14:54:19 -0500 Subject: [PATCH 2/8] Start to define the generator / module package responsibilities --- src/cmd/generate-v1/main.go | 7 ++-- src/internal/module/module.go | 61 ++++++++++++++++++++++++++++- src/internal/v1api/generator.go | 5 +++ src/internal/v1api/modules.go | 68 +++++++++++---------------------- 4 files changed, 90 insertions(+), 51 deletions(-) diff --git a/src/cmd/generate-v1/main.go b/src/cmd/generate-v1/main.go index fbd3e724a3..1f27feb7da 100644 --- a/src/cmd/generate-v1/main.go +++ b/src/cmd/generate-v1/main.go @@ -28,6 +28,7 @@ func main() { ModuleDirectory: *moduleDataDir, ProviderDirectory: *providerDataDir, + Logger: slog.Default(), } v1APIGenerator.WriteWellKnownFile(ctx) @@ -39,13 +40,11 @@ func main() { } for _, m := range modules { - slog.Info("Generating", slog.String("module", m.Namespace+"/"+m.Name+"/"+m.TargetSystem)) - err := v1APIGenerator.GenerateModuleResponses(ctx, m.Namespace, m.Name, m.TargetSystem) + err := v1APIGenerator.GenerateModuleResponses(ctx, m) if err != nil { - slog.Error("Failed to generate module version listing response", slog.Any("err", err)) + m.Logger(v1APIGenerator.Logger).Error("Failed to generate module version listing response", slog.Any("err", err)) os.Exit(1) } - slog.Info("Generated", slog.String("module", m.Namespace+"/"+m.Name+"/"+m.TargetSystem)) } // For now just the ultradns provider diff --git a/src/internal/module/module.go b/src/internal/module/module.go index b918c9a473..900de69493 100644 --- a/src/internal/module/module.go +++ b/src/internal/module/module.go @@ -1,6 +1,13 @@ package module -import "fmt" +import ( + "encoding/json" + "fmt" + "log/slog" + "os" + "path/filepath" + "registry-stable/internal" +) type Version struct { Version string `json:"version"` // The version number of the provider. Correlates to a tag in the module repository @@ -16,7 +23,59 @@ type Module struct { TargetSystem string // The module target system } +func (m Module) String() string { + return m.Namespace + "/" + m.Name + "/" + m.TargetSystem +} + +func (m Module) Logger(logger *slog.Logger) *slog.Logger { + return logger.With(slog.String("namespace", m.Namespace), slog.String("name", m.Name), slog.String("targetSystem", m.TargetSystem)) +} + func (m Module) RepositoryURL() string { repoName := fmt.Sprintf("terraform-%s-%s", m.TargetSystem, m.Name) return fmt.Sprintf("https://github.com/%s/%s", m.Namespace, repoName) } + +func (m Module) MetadataPath(directory string) string { + return filepath.Join(directory, m.Namespace[0:1], m.Namespace, m.Name, m.TargetSystem+".json") +} + +// ReadMetadata reads the module metadata file from the filesystem directly. This data should be the data fetched from the git repository. +func (m Module) ReadMetadata(moduleDirectory string, logger *slog.Logger) (*MetadataFile, error) { + path := m.MetadataPath(moduleDirectory) + + // open the file + metadataFile, err := os.ReadFile(path) + if err != nil { + return nil, fmt.Errorf("failed to open metadata file: %w", err) + } + + // Read the file contents into a Module[] struct + var metadata MetadataFile + err = json.Unmarshal(metadataFile, &metadata) + if err != nil { + return nil, err + } + + logger.Debug("Loaded Module Versions", slog.Any("count", len(metadata.Versions))) + + return &metadata, nil +} + +func (m Module) outputPath(directory string) string { + return filepath.Join(directory, "v1", "modules", m.Namespace, m.Name, m.TargetSystem) +} + +func (m Module) VersionListingPath(directory string) string { + return filepath.Join(m.outputPath(directory), "versions") +} + +func (m Module) VersionDownloadPath(directory string, v Version) string { + return filepath.Join(m.outputPath(directory), internal.TrimTagPrefix(v.Version), "download") +} + +// the file should just contain a link to GitHub to download the tarball, ie: +// git::https://github.com/terraform-aws-modules/terraform-aws-iam?ref=v5.30.0 +func (m Module) VersionDownloadURL(version Version) string { + return fmt.Sprintf("git::github.com/%s/terraform-%s-%s?ref=%s", m.Namespace, m.Name, m.TargetSystem, version.Version) +} diff --git a/src/internal/v1api/generator.go b/src/internal/v1api/generator.go index 8ab9b5e104..a259dea252 100644 --- a/src/internal/v1api/generator.go +++ b/src/internal/v1api/generator.go @@ -1,5 +1,7 @@ package v1api +import "log/slog" + // Generator is responsible for generating the responses used by v1 registry APIs. // This should take information from the current state of the registry and generate the responses // to be served by the API. @@ -15,4 +17,7 @@ type Generator struct { // ProviderDirectory is the directory to read provider metadata from. ProviderDirectory string + + // Logger for this generator + Logger *slog.Logger } diff --git a/src/internal/v1api/modules.go b/src/internal/v1api/modules.go index 41eab576d1..67e1254e7b 100644 --- a/src/internal/v1api/modules.go +++ b/src/internal/v1api/modules.go @@ -2,14 +2,10 @@ package v1api import ( "context" - "encoding/json" "fmt" "log/slog" - "os" "path/filepath" - "strings" - "registry-stable/internal" "registry-stable/internal/files" "registry-stable/internal/module" ) @@ -18,13 +14,12 @@ import ( // For more information see // https://opentofu.org/docs/internals/module-registry-protocol/#list-available-versions-for-a-specific-module // https://opentofu.org/docs/internals/module-registry-protocol/#download-source-code-for-a-specific-module-version -func (g Generator) GenerateModuleResponses(_ context.Context, namespace string, name string, targetSystem string) error { - logger := slog.With(slog.String("namespace", namespace), slog.String("name", name), slog.String("targetSystem", targetSystem)) +func (g Generator) GenerateModuleResponses(_ context.Context, m module.Module) error { + logger := m.Logger(g.Logger) - // TODO: Get path calculation from somewhere else - path := filepath.Join(g.ModuleDirectory, strings.ToLower(namespace[0:1]), namespace, name, targetSystem+".json") + logger.Info("Generating Module") - metadata, err := g.readModuleMetadata(path, logger) + metadata, err := m.ReadMetadata(g.ModuleDirectory, logger) if err != nil { return err } @@ -32,60 +27,41 @@ func (g Generator) GenerateModuleResponses(_ context.Context, namespace string, // Right now the format is pretty much identical, however if we want to extend the results in the future to include // more information, we can do that here. (i.e. the root module, or the submodules) versionsResponse := make([]ModuleVersionResponseItem, len(metadata.Versions)) - for i, m := range metadata.Versions { - versionsResponse[i] = ModuleVersionResponseItem{Version: m.Version} + for i, v := range metadata.Versions { + versionsResponse[i] = ModuleVersionResponseItem{Version: v.Version} - err := g.writeModuleVersionDownload(namespace, name, targetSystem, m.Version) + err := g.writeModuleVersionDownload(m, v) if err != nil { - return fmt.Errorf("failed to write metadata version download file for version %s: %w", m.Version, err) + return fmt.Errorf("failed to write metadata version download file for version %s: %w", v.Version, err) } - logger.Debug("Wrote metadata version download file", slog.String("version", m.Version)) + logger.Debug("Wrote metadata version download file", slog.String("version", v.Version)) } // Write the /versions response - err = g.writeModuleVersionListing(namespace, name, targetSystem, versionsResponse) + err = g.writeModuleVersionListing(m, versionsResponse) if err != nil { return err } - return nil -} - -// readModuleMetadata reads the module metadata file from the filesystem directly. This data should be the data fetched from the git repository. -func (g Generator) readModuleMetadata(path string, logger *slog.Logger) (*module.MetadataFile, error) { - // open the file - metadataFile, err := os.ReadFile(path) - if err != nil { - return nil, fmt.Errorf("failed to open metadata file: %w", err) - } + logger.Info("Generated Module") - // Read the file contents into a Module[] struct - var metadata module.MetadataFile - err = json.Unmarshal(metadataFile, &metadata) - if err != nil { - return nil, err - } - - logger.Debug("Loaded Modules", slog.Any("count", len(metadata.Versions))) - - return &metadata, nil + return nil } // writeModuleVersionListing writes the file containing the module version listing. // This data is to be consumed when an end user requests /v1/modules/{namespace}/{name}/{targetSystem}/versions -func (g Generator) writeModuleVersionListing(namespace string, name string, targetSystem string, versions []ModuleVersionResponseItem) error { - path := filepath.Join(g.DestinationDir, "v1", "modules", namespace, name, targetSystem, "versions") - return files.SafeWriteObjectToJsonFile(path, ModuleVersionListingResponse{Modules: []ModuleVersionListingResponseItem{{Versions: versions}}}) +func (g Generator) writeModuleVersionListing(m module.Module, versions []ModuleVersionResponseItem) error { + return files.SafeWriteObjectToJsonFile( + filepath.Join(g.DestinationDir, m.VersionListingPath(g.DestinationDir)), + ModuleVersionListingResponse{Modules: []ModuleVersionListingResponseItem{{Versions: versions}}}, + ) } // writeModuleVersionDownload writes the file containing the download link for the module version. // This data is to be consumed when an end user requests /v1/modules/{namespace}/{name}/{targetSystem}/{version}/download -func (g Generator) writeModuleVersionDownload(namespace string, name string, system string, version string) interface{} { - // the file should just contain a link to GitHub to download the tarball, ie: - // git::https://github.com/terraform-aws-modules/terraform-aws-iam?ref=v5.30.0 - location := fmt.Sprintf("git::github.com/%s/terraform-%s-%s?ref=%s", namespace, name, system, version) - response := ModuleVersionDownloadResponse{Location: location} - - path := filepath.Join(g.DestinationDir, "v1", "modules", namespace, name, system, internal.TrimTagPrefix(version), "download") - return files.SafeWriteObjectToJsonFile(path, response) +func (g Generator) writeModuleVersionDownload(m module.Module, version module.Version) interface{} { + return files.SafeWriteObjectToJsonFile( + filepath.Join(g.DestinationDir, m.VersionDownloadPath(g.DestinationDir, version)), + ModuleVersionDownloadResponse{Location: m.VersionDownloadURL(version)}, + ) } From 17b2d6fdf67310b6ae6d07af1b40780ad0bcb0da Mon Sep 17 00:00:00 2001 From: Christian Mesh Date: Wed, 15 Nov 2023 15:16:34 -0500 Subject: [PATCH 3/8] Fixes #12: module repo path incorrect --- src/internal/module/module.go | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/src/internal/module/module.go b/src/internal/module/module.go index 900de69493..c9aa32306d 100644 --- a/src/internal/module/module.go +++ b/src/internal/module/module.go @@ -23,17 +23,16 @@ type Module struct { TargetSystem string // The module target system } -func (m Module) String() string { - return m.Namespace + "/" + m.Name + "/" + m.TargetSystem -} - func (m Module) Logger(logger *slog.Logger) *slog.Logger { return logger.With(slog.String("namespace", m.Namespace), slog.String("name", m.Name), slog.String("targetSystem", m.TargetSystem)) } +func (m Module) repositoryPath() string { + return fmt.Sprintf("%s/terraform-%s-%s", m.Namespace, m.TargetSystem, m.Name) +} + func (m Module) RepositoryURL() string { - repoName := fmt.Sprintf("terraform-%s-%s", m.TargetSystem, m.Name) - return fmt.Sprintf("https://github.com/%s/%s", m.Namespace, repoName) + return fmt.Sprintf("https://github.com/%s", m.repositoryPath()) } func (m Module) MetadataPath(directory string) string { @@ -77,5 +76,5 @@ func (m Module) VersionDownloadPath(directory string, v Version) string { // the file should just contain a link to GitHub to download the tarball, ie: // git::https://github.com/terraform-aws-modules/terraform-aws-iam?ref=v5.30.0 func (m Module) VersionDownloadURL(version Version) string { - return fmt.Sprintf("git::github.com/%s/terraform-%s-%s?ref=%s", m.Namespace, m.Name, m.TargetSystem, version.Version) + return fmt.Sprintf("git::github.com/%s?ref=%s", m.repositoryPath(), version.Version) } From 9e48136c5a0b8290fe1197afca0b02598564eb01 Mon Sep 17 00:00:00 2001 From: Christian Mesh Date: Wed, 15 Nov 2023 15:55:19 -0500 Subject: [PATCH 4/8] Add tests to match spec/comments for module --- src/internal/module/module.go | 40 +++++------------------------- src/internal/module/module_test.go | 35 ++++++++++++++++++++++++++ 2 files changed, 41 insertions(+), 34 deletions(-) create mode 100644 src/internal/module/module_test.go diff --git a/src/internal/module/module.go b/src/internal/module/module.go index c9aa32306d..3e299e6731 100644 --- a/src/internal/module/module.go +++ b/src/internal/module/module.go @@ -1,10 +1,8 @@ package module import ( - "encoding/json" "fmt" "log/slog" - "os" "path/filepath" "registry-stable/internal" ) @@ -27,40 +25,20 @@ func (m Module) Logger(logger *slog.Logger) *slog.Logger { return logger.With(slog.String("namespace", m.Namespace), slog.String("name", m.Name), slog.String("targetSystem", m.TargetSystem)) } -func (m Module) repositoryPath() string { - return fmt.Sprintf("%s/terraform-%s-%s", m.Namespace, m.TargetSystem, m.Name) +func (m Module) RepositoryURL() string { + return fmt.Sprintf("https://github.com/%s/terraform-%s-%s", m.Namespace, m.TargetSystem, m.Name) } -func (m Module) RepositoryURL() string { - return fmt.Sprintf("https://github.com/%s", m.repositoryPath()) +// the file should just contain a link to GitHub to download the tarball, ie: +// git::https://github.com/terraform-aws-modules/terraform-aws-iam?ref=v5.30.0 +func (m Module) VersionDownloadURL(version Version) string { + return fmt.Sprintf("git::%s?ref=%s", m.RepositoryURL(), version.Version) } func (m Module) MetadataPath(directory string) string { return filepath.Join(directory, m.Namespace[0:1], m.Namespace, m.Name, m.TargetSystem+".json") } -// ReadMetadata reads the module metadata file from the filesystem directly. This data should be the data fetched from the git repository. -func (m Module) ReadMetadata(moduleDirectory string, logger *slog.Logger) (*MetadataFile, error) { - path := m.MetadataPath(moduleDirectory) - - // open the file - metadataFile, err := os.ReadFile(path) - if err != nil { - return nil, fmt.Errorf("failed to open metadata file: %w", err) - } - - // Read the file contents into a Module[] struct - var metadata MetadataFile - err = json.Unmarshal(metadataFile, &metadata) - if err != nil { - return nil, err - } - - logger.Debug("Loaded Module Versions", slog.Any("count", len(metadata.Versions))) - - return &metadata, nil -} - func (m Module) outputPath(directory string) string { return filepath.Join(directory, "v1", "modules", m.Namespace, m.Name, m.TargetSystem) } @@ -72,9 +50,3 @@ func (m Module) VersionListingPath(directory string) string { func (m Module) VersionDownloadPath(directory string, v Version) string { return filepath.Join(m.outputPath(directory), internal.TrimTagPrefix(v.Version), "download") } - -// the file should just contain a link to GitHub to download the tarball, ie: -// git::https://github.com/terraform-aws-modules/terraform-aws-iam?ref=v5.30.0 -func (m Module) VersionDownloadURL(version Version) string { - return fmt.Sprintf("git::github.com/%s?ref=%s", m.repositoryPath(), version.Version) -} diff --git a/src/internal/module/module_test.go b/src/internal/module/module_test.go new file mode 100644 index 0000000000..efa4b662ba --- /dev/null +++ b/src/internal/module/module_test.go @@ -0,0 +1,35 @@ +package module + +import ( + "bufio" + "bytes" + "log/slog" + "testing" + + "github.com/stretchr/testify/assert" +) + +func Test_Module(t *testing.T) { + m := Module{ + Namespace: "spacename", + Name: "name", + TargetSystem: "target", + } + v := Version{ + Version: "v1.0.1", + } + assert.Equal(t, "https://github.com/spacename/terraform-target-name", m.RepositoryURL()) + assert.Equal(t, "git::https://github.com/spacename/terraform-target-name?ref=v1.0.1", m.VersionDownloadURL(v)) + assert.Equal(t, "dir/s/spacename/name/target.json", m.MetadataPath("./dir")) + assert.Equal(t, "dir/v1/modules/spacename/name/target/versions", m.VersionListingPath("./dir")) + assert.Equal(t, "dir/v1/modules/spacename/name/target/1.0.1/download", m.VersionDownloadPath("./dir", v)) + + buff := bytes.NewBufferString("") + bw := bufio.NewWriter(buff) + + logger := slog.New(slog.NewJSONHandler(bw, nil)) + m.Logger(logger).Info("Module") + bw.Flush() + + assert.Contains(t, buff.String(), `"namespace":"spacename","name":"name","targetSystem":"target"`) +} From 3b998d96e62a64cae89288d2fafad2540e7e15d3 Mon Sep 17 00:00:00 2001 From: Christian Mesh Date: Thu, 16 Nov 2023 09:19:10 -0500 Subject: [PATCH 5/8] Back out logging changes for now --- src/cmd/generate-v1/main.go | 5 +++-- src/internal/module/module.go | 5 ----- src/internal/module/module_test.go | 12 ------------ src/internal/v1api/generator.go | 5 ----- src/internal/v1api/modules.go | 6 +----- 5 files changed, 4 insertions(+), 29 deletions(-) diff --git a/src/cmd/generate-v1/main.go b/src/cmd/generate-v1/main.go index 1f27feb7da..a60744b9e7 100644 --- a/src/cmd/generate-v1/main.go +++ b/src/cmd/generate-v1/main.go @@ -28,7 +28,6 @@ func main() { ModuleDirectory: *moduleDataDir, ProviderDirectory: *providerDataDir, - Logger: slog.Default(), } v1APIGenerator.WriteWellKnownFile(ctx) @@ -40,11 +39,13 @@ func main() { } for _, m := range modules { + slog.Info("Generating", slog.String("module", m.Namespace+"/"+m.Name+"/"+m.TargetSystem)) err := v1APIGenerator.GenerateModuleResponses(ctx, m) if err != nil { - m.Logger(v1APIGenerator.Logger).Error("Failed to generate module version listing response", slog.Any("err", err)) + slog.Error("Failed to generate module version listing response", slog.Any("err", err)) os.Exit(1) } + slog.Info("Generated", slog.String("module", m.Namespace+"/"+m.Name+"/"+m.TargetSystem)) } // For now just the ultradns provider diff --git a/src/internal/module/module.go b/src/internal/module/module.go index 3e299e6731..0fd35568c9 100644 --- a/src/internal/module/module.go +++ b/src/internal/module/module.go @@ -2,7 +2,6 @@ package module import ( "fmt" - "log/slog" "path/filepath" "registry-stable/internal" ) @@ -21,10 +20,6 @@ type Module struct { TargetSystem string // The module target system } -func (m Module) Logger(logger *slog.Logger) *slog.Logger { - return logger.With(slog.String("namespace", m.Namespace), slog.String("name", m.Name), slog.String("targetSystem", m.TargetSystem)) -} - func (m Module) RepositoryURL() string { return fmt.Sprintf("https://github.com/%s/terraform-%s-%s", m.Namespace, m.TargetSystem, m.Name) } diff --git a/src/internal/module/module_test.go b/src/internal/module/module_test.go index efa4b662ba..5103cc4e73 100644 --- a/src/internal/module/module_test.go +++ b/src/internal/module/module_test.go @@ -1,9 +1,6 @@ package module import ( - "bufio" - "bytes" - "log/slog" "testing" "github.com/stretchr/testify/assert" @@ -23,13 +20,4 @@ func Test_Module(t *testing.T) { assert.Equal(t, "dir/s/spacename/name/target.json", m.MetadataPath("./dir")) assert.Equal(t, "dir/v1/modules/spacename/name/target/versions", m.VersionListingPath("./dir")) assert.Equal(t, "dir/v1/modules/spacename/name/target/1.0.1/download", m.VersionDownloadPath("./dir", v)) - - buff := bytes.NewBufferString("") - bw := bufio.NewWriter(buff) - - logger := slog.New(slog.NewJSONHandler(bw, nil)) - m.Logger(logger).Info("Module") - bw.Flush() - - assert.Contains(t, buff.String(), `"namespace":"spacename","name":"name","targetSystem":"target"`) } diff --git a/src/internal/v1api/generator.go b/src/internal/v1api/generator.go index a259dea252..8ab9b5e104 100644 --- a/src/internal/v1api/generator.go +++ b/src/internal/v1api/generator.go @@ -1,7 +1,5 @@ package v1api -import "log/slog" - // Generator is responsible for generating the responses used by v1 registry APIs. // This should take information from the current state of the registry and generate the responses // to be served by the API. @@ -17,7 +15,4 @@ type Generator struct { // ProviderDirectory is the directory to read provider metadata from. ProviderDirectory string - - // Logger for this generator - Logger *slog.Logger } diff --git a/src/internal/v1api/modules.go b/src/internal/v1api/modules.go index 67e1254e7b..ac88ab6aad 100644 --- a/src/internal/v1api/modules.go +++ b/src/internal/v1api/modules.go @@ -15,9 +15,7 @@ import ( // https://opentofu.org/docs/internals/module-registry-protocol/#list-available-versions-for-a-specific-module // https://opentofu.org/docs/internals/module-registry-protocol/#download-source-code-for-a-specific-module-version func (g Generator) GenerateModuleResponses(_ context.Context, m module.Module) error { - logger := m.Logger(g.Logger) - - logger.Info("Generating Module") + logger := slog.With(slog.String("namespace", m.Namespace), slog.String("name", m.Name), slog.String("targetSystem", m.TargetSystem)) metadata, err := m.ReadMetadata(g.ModuleDirectory, logger) if err != nil { @@ -43,8 +41,6 @@ func (g Generator) GenerateModuleResponses(_ context.Context, m module.Module) e return err } - logger.Info("Generated Module") - return nil } From 0a1a3535ef53d8fa95cb62fa0c62d823f309e1d3 Mon Sep 17 00:00:00 2001 From: Christian Mesh Date: Thu, 16 Nov 2023 09:24:48 -0500 Subject: [PATCH 6/8] Move base path awareness out of module.go --- src/internal/module/module.go | 16 ++++++++-------- src/internal/module/module_test.go | 6 +++--- src/internal/v1api/modules.go | 28 ++++++++++++++++++++++++++-- 3 files changed, 37 insertions(+), 13 deletions(-) diff --git a/src/internal/module/module.go b/src/internal/module/module.go index 0fd35568c9..713d0a3211 100644 --- a/src/internal/module/module.go +++ b/src/internal/module/module.go @@ -30,18 +30,18 @@ func (m Module) VersionDownloadURL(version Version) string { return fmt.Sprintf("git::%s?ref=%s", m.RepositoryURL(), version.Version) } -func (m Module) MetadataPath(directory string) string { - return filepath.Join(directory, m.Namespace[0:1], m.Namespace, m.Name, m.TargetSystem+".json") +func (m Module) MetadataPath() string { + return filepath.Join(m.Namespace[0:1], m.Namespace, m.Name, m.TargetSystem+".json") } -func (m Module) outputPath(directory string) string { - return filepath.Join(directory, "v1", "modules", m.Namespace, m.Name, m.TargetSystem) +func (m Module) outputPath() string { + return filepath.Join("v1", "modules", m.Namespace, m.Name, m.TargetSystem) } -func (m Module) VersionListingPath(directory string) string { - return filepath.Join(m.outputPath(directory), "versions") +func (m Module) VersionListingPath() string { + return filepath.Join(m.outputPath(), "versions") } -func (m Module) VersionDownloadPath(directory string, v Version) string { - return filepath.Join(m.outputPath(directory), internal.TrimTagPrefix(v.Version), "download") +func (m Module) VersionDownloadPath(v Version) string { + return filepath.Join(m.outputPath(), internal.TrimTagPrefix(v.Version), "download") } diff --git a/src/internal/module/module_test.go b/src/internal/module/module_test.go index 5103cc4e73..efde369058 100644 --- a/src/internal/module/module_test.go +++ b/src/internal/module/module_test.go @@ -17,7 +17,7 @@ func Test_Module(t *testing.T) { } assert.Equal(t, "https://github.com/spacename/terraform-target-name", m.RepositoryURL()) assert.Equal(t, "git::https://github.com/spacename/terraform-target-name?ref=v1.0.1", m.VersionDownloadURL(v)) - assert.Equal(t, "dir/s/spacename/name/target.json", m.MetadataPath("./dir")) - assert.Equal(t, "dir/v1/modules/spacename/name/target/versions", m.VersionListingPath("./dir")) - assert.Equal(t, "dir/v1/modules/spacename/name/target/1.0.1/download", m.VersionDownloadPath("./dir", v)) + assert.Equal(t, "s/spacename/name/target.json", m.MetadataPath()) + assert.Equal(t, "v1/modules/spacename/name/target/versions", m.VersionListingPath()) + assert.Equal(t, "v1/modules/spacename/name/target/1.0.1/download", m.VersionDownloadPath(v)) } diff --git a/src/internal/v1api/modules.go b/src/internal/v1api/modules.go index ac88ab6aad..f55cc04bf4 100644 --- a/src/internal/v1api/modules.go +++ b/src/internal/v1api/modules.go @@ -2,8 +2,10 @@ package v1api import ( "context" + "encoding/json" "fmt" "log/slog" + "os" "path/filepath" "registry-stable/internal/files" @@ -48,16 +50,38 @@ func (g Generator) GenerateModuleResponses(_ context.Context, m module.Module) e // This data is to be consumed when an end user requests /v1/modules/{namespace}/{name}/{targetSystem}/versions func (g Generator) writeModuleVersionListing(m module.Module, versions []ModuleVersionResponseItem) error { return files.SafeWriteObjectToJsonFile( - filepath.Join(g.DestinationDir, m.VersionListingPath(g.DestinationDir)), + filepath.Join(g.DestinationDir, m.VersionListingPath()), ModuleVersionListingResponse{Modules: []ModuleVersionListingResponseItem{{Versions: versions}}}, ) } +// readModuleMetadata reads the module metadata file from the filesystem directly. This data should be the data fetched from the git repository. +func (g Generator) readModuleMetadata(m module.Module, logger *slog.Logger) (*module.MetadataFile, error) { + path := filepath.Join(g.ModuleDirectory, m.MetadataPath()) + + // open the file + metadataFile, err := os.ReadFile(path) + if err != nil { + return nil, fmt.Errorf("failed to open metadata file: %w", err) + } + + // Read the file contents into a Module[] struct + var metadata module.MetadataFile + err = json.Unmarshal(metadataFile, &metadata) + if err != nil { + return nil, err + } + + logger.Debug("Loaded Module Versions", slog.Any("count", len(metadata.Versions))) + + return &metadata, nil +} + // writeModuleVersionDownload writes the file containing the download link for the module version. // This data is to be consumed when an end user requests /v1/modules/{namespace}/{name}/{targetSystem}/{version}/download func (g Generator) writeModuleVersionDownload(m module.Module, version module.Version) interface{} { return files.SafeWriteObjectToJsonFile( - filepath.Join(g.DestinationDir, m.VersionDownloadPath(g.DestinationDir, version)), + filepath.Join(g.DestinationDir, m.VersionDownloadPath(version)), ModuleVersionDownloadResponse{Location: m.VersionDownloadURL(version)}, ) } From c269f56a613a7a82e01554fea1ad7c18e7a3f895 Mon Sep 17 00:00:00 2001 From: James Humphries Date: Fri, 17 Nov 2023 10:42:25 +0000 Subject: [PATCH 7/8] Fixed messy rebase error Signed-off-by: James Humphries --- src/internal/v1api/modules.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/internal/v1api/modules.go b/src/internal/v1api/modules.go index f55cc04bf4..79a6bc1b3c 100644 --- a/src/internal/v1api/modules.go +++ b/src/internal/v1api/modules.go @@ -19,7 +19,7 @@ import ( func (g Generator) GenerateModuleResponses(_ context.Context, m module.Module) error { logger := slog.With(slog.String("namespace", m.Namespace), slog.String("name", m.Name), slog.String("targetSystem", m.TargetSystem)) - metadata, err := m.ReadMetadata(g.ModuleDirectory, logger) + metadata, err := g.readModuleMetadata(m, logger) if err != nil { return err } From 07334192afe23e372f8640fda735e835b7d7798b Mon Sep 17 00:00:00 2001 From: James Humphries Date: Fri, 17 Nov 2023 10:45:02 +0000 Subject: [PATCH 8/8] Removed empty newline Signed-off-by: James Humphries --- src/internal/files/files.go | 1 - 1 file changed, 1 deletion(-) diff --git a/src/internal/files/files.go b/src/internal/files/files.go index 895be8a567..2f7bc8c03a 100644 --- a/src/internal/files/files.go +++ b/src/internal/files/files.go @@ -11,7 +11,6 @@ func SafeWriteObjectToJsonFile(filePath string, data interface{}) error { marshalledJson, err := json.MarshalIndent(data, "", " ") if err != nil { return fmt.Errorf("failed to marshal for %s: %w", filePath, err) - } err = os.MkdirAll(path.Dir(filePath), 0755)