Add manifest apply command to generate server and webapp manifest files

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

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Felipe M 2025-07-28 18:00:41 +02:00
parent 0bc6d51b24
commit 6403d1a51d
No known key found for this signature in database
GPG key ID: 52E5D65FCF99808A
2 changed files with 91 additions and 3 deletions

View file

@ -131,7 +131,7 @@ Commands:
reset Reset plugin from current directory (disable then enable)
deploy Upload and enable plugin bundle to Mattermost server
updateassets Update plugin files from embedded assets
manifest Get plugin manifest information using templates (get {{.field}}, check)
manifest Get plugin manifest information using templates (get {{.field}}, apply, check)
logs View plugin logs (use --watch to follow logs in real-time)
create-plugin Create a new plugin from the starter template (supports --name and --module flags)
help Show this help message
@ -147,6 +147,7 @@ Examples:
pluginctl deploy --bundle-path ./bundle.tar.gz # Deploy specific bundle file
pluginctl updateassets # Update plugin files from embedded assets
pluginctl manifest get '{{.id}}' # Get any manifest field using templates
pluginctl manifest apply # Generate manifest files for server/webapp
pluginctl manifest check # Validate plugin manifest
pluginctl logs # View recent plugin logs
pluginctl logs --watch # Watch plugin logs in real-time

View file

@ -2,15 +2,97 @@ package pluginctl
import (
"bytes"
"encoding/json"
"fmt"
"os"
"path/filepath"
"text/template"
"github.com/mattermost/mattermost/server/public/model"
)
const (
// File permissions for generated directories and files.
manifestDirPerm = 0o750
manifestFilePerm = 0o600
)
const pluginIDGoFileTemplate = `// This file is automatically generated. Do not modify it manually.
package main
import (
"encoding/json"
"strings"
"github.com/mattermost/mattermost/server/public/model"
)
var manifest *model.Manifest
const manifestStr = ` + "`%s`" + `
func init() {
_ = json.NewDecoder(strings.NewReader(manifestStr)).Decode(&manifest)
}
`
const pluginIDJSFileTemplate = `// This file is automatically generated. Do not modify it manually.
const manifest = JSON.parse(` + "`%s`" + `);
export default manifest;
`
// applyManifest generates manifest files for server and webapp components.
func applyManifest(manifest *model.Manifest, pluginPath string) error {
manifestBytes, err := json.Marshal(manifest)
if err != nil {
return fmt.Errorf("failed to marshal manifest: %w", err)
}
manifestStr := string(manifestBytes)
// Generate server manifest file if server exists
if HasServerCode(manifest) {
serverDir := filepath.Join(pluginPath, "server")
if err := os.MkdirAll(serverDir, manifestDirPerm); err != nil {
return fmt.Errorf("failed to create server directory: %w", err)
}
serverManifestPath := filepath.Join(serverDir, "manifest.go")
serverContent := fmt.Sprintf(pluginIDGoFileTemplate, manifestStr)
if err := os.WriteFile(serverManifestPath, []byte(serverContent), manifestFilePerm); err != nil {
return fmt.Errorf("failed to write server manifest: %w", err)
}
Logger.Info("Generated server manifest", "path", serverManifestPath)
}
// Generate webapp manifest file if webapp exists
if HasWebappCode(manifest) {
webappDir := filepath.Join(pluginPath, "webapp", "src")
if err := os.MkdirAll(webappDir, manifestDirPerm); err != nil {
return fmt.Errorf("failed to create webapp directory: %w", err)
}
webappManifestPath := filepath.Join(webappDir, "manifest.ts")
webappContent := fmt.Sprintf(pluginIDJSFileTemplate, manifestStr)
if err := os.WriteFile(webappManifestPath, []byte(webappContent), manifestFilePerm); err != nil {
return fmt.Errorf("failed to write webapp manifest: %w", err)
}
Logger.Info("Generated webapp manifest", "path", webappManifestPath)
}
return nil
}
// RunManifestCommand implements the 'manifest' command functionality with subcommands.
func RunManifestCommand(args []string, pluginPath string) error {
if len(args) == 0 {
return fmt.Errorf("manifest command requires a subcommand: get {{.field_name}}, check")
return fmt.Errorf("manifest command requires a subcommand: get {{.field_name}}, apply, check")
}
// Convert to absolute path
@ -45,6 +127,10 @@ func RunManifestCommand(args []string, pluginPath string) error {
}
fmt.Print(buf.String())
case "apply":
if err := applyManifest(manifest, absPath); err != nil {
return fmt.Errorf("failed to apply manifest: %w", err)
}
case "check":
if err := manifest.IsValid(); err != nil {
Logger.Error("Plugin manifest validation failed", "error", err)
@ -53,7 +139,8 @@ func RunManifestCommand(args []string, pluginPath string) error {
}
Logger.Info("Plugin manifest is valid")
default:
return fmt.Errorf("unknown subcommand: %s. Available subcommands: get {{.field_name}}, check", subcommand)
return fmt.Errorf("unknown subcommand: %s. Available subcommands: get {{.field_name}}, apply, check",
subcommand)
}
return nil