Skip to content

Commit

Permalink
Merge pull request #14 from opentofu/refactor_module_generation
Browse files Browse the repository at this point in the history
  • Loading branch information
Yantrio authored Nov 17, 2023
2 parents fe9b7fb + 0733419 commit d9f7fc5
Show file tree
Hide file tree
Showing 5 changed files with 80 additions and 36 deletions.
2 changes: 1 addition & 1 deletion src/cmd/generate-v1/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ 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))
os.Exit(1)
Expand Down
31 changes: 28 additions & 3 deletions src/internal/module/module.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
package module

import "fmt"
import (
"fmt"
"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
Expand All @@ -17,6 +21,27 @@ type Module struct {
}

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/terraform-%s-%s", m.Namespace, m.TargetSystem, m.Name)
}

// 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() string {
return filepath.Join(m.Namespace[0:1], m.Namespace, m.Name, m.TargetSystem+".json")
}

func (m Module) outputPath() string {
return filepath.Join("v1", "modules", m.Namespace, m.Name, m.TargetSystem)
}

func (m Module) VersionListingPath() string {
return filepath.Join(m.outputPath(), "versions")
}

func (m Module) VersionDownloadPath(v Version) string {
return filepath.Join(m.outputPath(), internal.TrimTagPrefix(v.Version), "download")
}
23 changes: 23 additions & 0 deletions src/internal/module/module_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package module

import (
"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, "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))
}
2 changes: 1 addition & 1 deletion src/internal/repository-metadata-files/provider/create.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
Expand Down
58 changes: 27 additions & 31 deletions src/internal/v1api/modules.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,7 @@ import (
"log/slog"
"os"
"path/filepath"
"strings"

"registry-stable/internal"
"registry-stable/internal/files"
"registry-stable/internal/module"
)
Expand All @@ -18,41 +16,49 @@ 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 := slog.With(slog.String("namespace", m.Namespace), slog.String("name", m.Name), slog.String("targetSystem", m.TargetSystem))

// TODO: Get path calculation from somewhere else
path := filepath.Join(g.ModuleDirectory, strings.ToLower(namespace[0:1]), namespace, name, targetSystem+".json")

metadata, err := g.readModuleMetadata(path, logger)
metadata, err := g.readModuleMetadata(m, logger)
if err != nil {
return err
}

// 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
}

// 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(m module.Module, versions []ModuleVersionResponseItem) error {
return files.SafeWriteObjectToJsonFile(
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(path string, logger *slog.Logger) (*module.MetadataFile, error) {
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 {
Expand All @@ -66,26 +72,16 @@ func (g Generator) readModuleMetadata(path string, logger *slog.Logger) (*module
return nil, err
}

logger.Debug("Loaded Modules", slog.Any("count", len(metadata.Versions)))
logger.Debug("Loaded Module Versions", slog.Any("count", len(metadata.Versions)))

return &metadata, 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}}})
}

// 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(version)),
ModuleVersionDownloadResponse{Location: m.VersionDownloadURL(version)},
)
}

0 comments on commit d9f7fc5

Please sign in to comment.