Add GoModule support to template context and update gitignore

- Add GoModule struct with Module and Version fields
- Parse go.mod file to extract module name and Go version
- Expose GoModule in template context as {{.GoModule}}
- Update asset templates to use {{.GoModule}} instead of hardcoded values
- Add gitignore pattern for testdata directories (keep only plugin.json files)
- All templates now have access to both manifest and Go module information

Templates can now use:
- {{.GoModule.Module}} for module name
- {{.GoModule.Version}} for Go version
- {{if .GoModule}}...{{end}} for conditional logic

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Felipe M 2025-07-14 22:16:41 +02:00
parent 04fa4154b3
commit 2e2a95d7d6
No known key found for this signature in database
GPG key ID: 52E5D65FCF99808A
4 changed files with 62 additions and 9 deletions

5
.gitignore vendored
View file

@ -31,3 +31,8 @@ Thumbs.db
.env .env
.env.local .env.local
.claude .claude
# Ignore all files in testdata except plugin.json
testdata/**/*
!testdata/**/
!testdata/**/plugin.json

View file

@ -6,7 +6,7 @@ linters-settings:
gofmt: gofmt:
simplify: true simplify: true
goimports: goimports:
local-prefixes: github.com/mattermost/mattermost-starter-template local-prefixes: {{.GoModule}}
govet: govet:
check-shadowing: true check-shadowing: true
enable-all: true enable-all: true

View file

@ -33,7 +33,7 @@ endif
mock: mock:
ifneq ($(HAS_SERVER),) ifneq ($(HAS_SERVER),)
go install github.com/golang/mock/mockgen@v1.6.0 go install github.com/golang/mock/mockgen@v1.6.0
mockgen -destination=server/command/mocks/mock_commands.go -package=mocks github.com/mattermost/mattermost-plugin-starter-template/server/command Command mockgen -destination=server/command/mocks/mock_commands.go -package=mocks {{.GoModule}}/server/command Command
endif endif
## Show help documentation. ## Show help documentation.

View file

@ -128,9 +128,16 @@ type AssetProcessorConfig struct {
manifest *model.Manifest manifest *model.Manifest
} }
// GoModule represents information from go.mod file.
type GoModule struct {
Module string
Version string
}
// TemplateContext holds the data available to templates. // TemplateContext holds the data available to templates.
type TemplateContext struct { type TemplateContext struct {
Manifest *model.Manifest Manifest *model.Manifest
GoModule *GoModule
} }
func processAssetEntry(path string, d fs.DirEntry, err error, config AssetProcessorConfig) error { func processAssetEntry(path string, d fs.DirEntry, err error, config AssetProcessorConfig) error {
@ -165,13 +172,13 @@ func processAssetEntry(path string, d fs.DirEntry, err error, config AssetProces
} }
func processAssetFile(embeddedPath, targetPath, relativePath string, config AssetProcessorConfig) error { func processAssetFile(embeddedPath, targetPath, relativePath string, config AssetProcessorConfig) error {
shouldUpdate, err := shouldUpdateFile(embeddedPath, targetPath, config.manifest) shouldUpdate, err := shouldUpdateFile(embeddedPath, targetPath, config)
if err != nil { if err != nil {
return err return err
} }
if shouldUpdate { if shouldUpdate {
err = updateFile(embeddedPath, targetPath, relativePath, config.manifest) err = updateFile(embeddedPath, targetPath, relativePath, config)
if err != nil { if err != nil {
return err return err
} }
@ -189,9 +196,9 @@ func createDirectory(targetPath string) error {
return nil return nil
} }
func shouldUpdateFile(embeddedPath, targetPath string, manifest *model.Manifest) (bool, error) { func shouldUpdateFile(embeddedPath, targetPath string, config AssetProcessorConfig) (bool, error) {
// Process the template to get the final content // Process the template to get the final content
processedContent, err := processTemplate(embeddedPath, manifest) processedContent, err := processTemplate(embeddedPath, config.manifest, config.pluginPath)
if err != nil { if err != nil {
return false, fmt.Errorf("failed to process template %s: %w", embeddedPath, err) return false, fmt.Errorf("failed to process template %s: %w", embeddedPath, err)
} }
@ -205,9 +212,9 @@ func shouldUpdateFile(embeddedPath, targetPath string, manifest *model.Manifest)
return !bytes.Equal(existingContent, processedContent), nil return !bytes.Equal(existingContent, processedContent), nil
} }
func updateFile(embeddedPath, targetPath, relativePath string, manifest *model.Manifest) error { func updateFile(embeddedPath, targetPath, relativePath string, config AssetProcessorConfig) error {
// Process the template to get the final content // Process the template to get the final content
processedContent, err := processTemplate(embeddedPath, manifest) processedContent, err := processTemplate(embeddedPath, config.manifest, config.pluginPath)
if err != nil { if err != nil {
return fmt.Errorf("failed to process template %s: %w", embeddedPath, err) return fmt.Errorf("failed to process template %s: %w", embeddedPath, err)
} }
@ -227,16 +234,23 @@ func updateFile(embeddedPath, targetPath, relativePath string, manifest *model.M
} }
// processTemplate processes a template file with the manifest context. // processTemplate processes a template file with the manifest context.
func processTemplate(embeddedPath string, manifest *model.Manifest) ([]byte, error) { func processTemplate(embeddedPath string, manifest *model.Manifest, pluginPath string) ([]byte, error) {
// Read the template content // Read the template content
templateContent, err := assetsFS.ReadFile(embeddedPath) templateContent, err := assetsFS.ReadFile(embeddedPath)
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to read embedded file %s: %w", embeddedPath, err) return nil, fmt.Errorf("failed to read embedded file %s: %w", embeddedPath, err)
} }
// Parse go.mod file to get module information
goMod, err := parseGoModule(pluginPath)
if err != nil {
return nil, fmt.Errorf("failed to parse go.mod file: %w", err)
}
// Create template context // Create template context
context := TemplateContext{ context := TemplateContext{
Manifest: manifest, Manifest: manifest,
GoModule: goMod,
} }
// Create and parse the template // Create and parse the template
@ -254,3 +268,37 @@ func processTemplate(embeddedPath string, manifest *model.Manifest) ([]byte, err
return buf.Bytes(), nil return buf.Bytes(), nil
} }
// parseGoModule parses the go.mod file to extract module information.
func parseGoModule(pluginPath string) (*GoModule, error) {
goModPath := filepath.Join(pluginPath, "go.mod")
content, err := os.ReadFile(goModPath)
if err != nil {
// If go.mod doesn't exist, return nil without error
if os.IsNotExist(err) {
return nil, nil
}
return nil, fmt.Errorf("failed to read go.mod file: %w", err)
}
goMod := &GoModule{}
lines := strings.Split(string(content), "\n")
for _, line := range lines {
line = strings.TrimSpace(line)
// Parse module line
if strings.HasPrefix(line, "module ") {
goMod.Module = strings.TrimSpace(strings.TrimPrefix(line, "module "))
}
// Parse go version line
if strings.HasPrefix(line, "go ") {
goMod.Version = strings.TrimSpace(strings.TrimPrefix(line, "go "))
}
}
return goMod, nil
}