snapshot of https://github.com/mattermost/mattermost.git (master, 2026-09-16; blobs > 131072B omitted)
Some checks failed
Server CI / Postgres (shard 0) (push) Has been skipped
Server CI / Postgres (shard 3) (push) Has been skipped
BuildEnv Docker Image / build-image (push) Failing after 4s
BuildEnv Docker Image / build-image-fips (push) Failing after 4s
Migration Review & Release Notes / Generate migration review & release notes (push) Failing after 3s
Server CI / Build Environment (push) Failing after 3s
Server CI / Postgres (shard 1) (push) Has been skipped
Tools CI / check-style (mattermost-govet) (push) Failing after 4s
Server CI / Postgres (shard 2) (push) Has been skipped
Tools CI / check-style (mmgotool) (push) Failing after 3s
Server CI / Elasticsearch v8 Compatibility (push) Has been skipped
Server CI / OpenSearch v2 Compatibility (push) Has been skipped
Server CI / Postgres FIPS (shard 0) (push) Has been skipped
Tools CI / Test (mattermost-govet) (push) Failing after 3s
Server CI / Postgres FIPS (shard 1) (push) Has been skipped
Server CI / Postgres FIPS (shard 2) (push) Has been skipped
Tools CI / Test (mmgotool) (push) Failing after 3s
Server CI / Postgres FIPS (shard 3) (push) Has been skipped
Server CI / Run mmctl tests (push) Has been skipped
Server CI / Run mmctl tests (FIPS) (push) Has been skipped
Server CI / Merge Postgres Test Results (push) Has been skipped
Server CI / Merge Postgres FIPS Test Results (push) Has been skipped
Server CI / Check backport migrations (push) Has been skipped
Server CI / Check generated files (push) Has been skipped
Server CI / check-style (push) Has been skipped
Server CI / Vet API (push) Has been skipped
Server CI / Build mattermost server app (push) Has been skipped
Server CI / Server CI Complete (push) Failing after 2s
Server CI / Server CI Artifacts (push) Has been skipped
Server CI / Sentry Upload (push) Has been skipped
Server CI / Server CI Report (push) Failing after 5m1s
Server CI Nightly Race / Race Detector (push) Has been skipped
CodeQL / Analyze (go) (push) Has been cancelled
CodeQL / Analyze (javascript) (push) Has been cancelled
Webapp CI Cache Warm / Warm Webapp node_modules Cache (push) Has been cancelled
E2E CI Cache Warm / Warm E2E npm Registry Cache (push) Has been cancelled
API / build (push) Has been cancelled
Web App CI / check-types (push) Has been cancelled
Web App CI / check-lint (push) Has been cancelled
Web App CI / check-i18n (push) Has been cancelled
Web App CI / check-external-links (push) Has been cancelled
Web App CI / test (platform) (push) Has been cancelled
Web App CI / test (mattermost-redux) (push) Has been cancelled
Web App CI / test (channels shard 1/4) (push) Has been cancelled
Web App CI / test (channels shard 2/4) (push) Has been cancelled
Web App CI / test (channels shard 3/4) (push) Has been cancelled
Web App CI / test (channels shard 4/4) (push) Has been cancelled
Web App CI / upload-coverage (push) Has been cancelled
Web App CI / build (push) Has been cancelled
YAML Lint / yamllint (push) Has been cancelled
Push mirrored docker images / cd/Push mirrored docker images (push) Has been cancelled
docs-cd / Build and deploy docs (push) Has been cancelled
Docs CI / build (push) Has been cancelled
E2E Cache Warm: Cypress deps / Warm Cypress deps cache (push) Has been cancelled
Scorecards supply-chain security / Scorecard analysis (push) Has been cancelled
Server CI Weekly / Postgres FIPS (push) Has been skipped
Server CI Weekly / Run mmctl tests (FIPS) (push) Has been skipped
Server CI Weekly / Postgres with binary parameters (push) Has been skipped
Server CI Weekly / Build Environment (push) Failing after 1s
Server CI Cache Warm / Warm Go Module and Build Cache (push) Failing after 2s
Server CI Nightly Race / Build Environment (push) Failing after 1s
Some checks failed
Server CI / Postgres (shard 0) (push) Has been skipped
Server CI / Postgres (shard 3) (push) Has been skipped
BuildEnv Docker Image / build-image (push) Failing after 4s
BuildEnv Docker Image / build-image-fips (push) Failing after 4s
Migration Review & Release Notes / Generate migration review & release notes (push) Failing after 3s
Server CI / Build Environment (push) Failing after 3s
Server CI / Postgres (shard 1) (push) Has been skipped
Tools CI / check-style (mattermost-govet) (push) Failing after 4s
Server CI / Postgres (shard 2) (push) Has been skipped
Tools CI / check-style (mmgotool) (push) Failing after 3s
Server CI / Elasticsearch v8 Compatibility (push) Has been skipped
Server CI / OpenSearch v2 Compatibility (push) Has been skipped
Server CI / Postgres FIPS (shard 0) (push) Has been skipped
Tools CI / Test (mattermost-govet) (push) Failing after 3s
Server CI / Postgres FIPS (shard 1) (push) Has been skipped
Server CI / Postgres FIPS (shard 2) (push) Has been skipped
Tools CI / Test (mmgotool) (push) Failing after 3s
Server CI / Postgres FIPS (shard 3) (push) Has been skipped
Server CI / Run mmctl tests (push) Has been skipped
Server CI / Run mmctl tests (FIPS) (push) Has been skipped
Server CI / Merge Postgres Test Results (push) Has been skipped
Server CI / Merge Postgres FIPS Test Results (push) Has been skipped
Server CI / Check backport migrations (push) Has been skipped
Server CI / Check generated files (push) Has been skipped
Server CI / check-style (push) Has been skipped
Server CI / Vet API (push) Has been skipped
Server CI / Build mattermost server app (push) Has been skipped
Server CI / Server CI Complete (push) Failing after 2s
Server CI / Server CI Artifacts (push) Has been skipped
Server CI / Sentry Upload (push) Has been skipped
Server CI / Server CI Report (push) Failing after 5m1s
Server CI Nightly Race / Race Detector (push) Has been skipped
CodeQL / Analyze (go) (push) Has been cancelled
CodeQL / Analyze (javascript) (push) Has been cancelled
Webapp CI Cache Warm / Warm Webapp node_modules Cache (push) Has been cancelled
E2E CI Cache Warm / Warm E2E npm Registry Cache (push) Has been cancelled
API / build (push) Has been cancelled
Web App CI / check-types (push) Has been cancelled
Web App CI / check-lint (push) Has been cancelled
Web App CI / check-i18n (push) Has been cancelled
Web App CI / check-external-links (push) Has been cancelled
Web App CI / test (platform) (push) Has been cancelled
Web App CI / test (mattermost-redux) (push) Has been cancelled
Web App CI / test (channels shard 1/4) (push) Has been cancelled
Web App CI / test (channels shard 2/4) (push) Has been cancelled
Web App CI / test (channels shard 3/4) (push) Has been cancelled
Web App CI / test (channels shard 4/4) (push) Has been cancelled
Web App CI / upload-coverage (push) Has been cancelled
Web App CI / build (push) Has been cancelled
YAML Lint / yamllint (push) Has been cancelled
Push mirrored docker images / cd/Push mirrored docker images (push) Has been cancelled
docs-cd / Build and deploy docs (push) Has been cancelled
Docs CI / build (push) Has been cancelled
E2E Cache Warm: Cypress deps / Warm Cypress deps cache (push) Has been cancelled
Scorecards supply-chain security / Scorecard analysis (push) Has been cancelled
Server CI Weekly / Postgres FIPS (push) Has been skipped
Server CI Weekly / Run mmctl tests (FIPS) (push) Has been skipped
Server CI Weekly / Postgres with binary parameters (push) Has been skipped
Server CI Weekly / Build Environment (push) Failing after 1s
Server CI Cache Warm / Warm Go Module and Build Cache (push) Failing after 2s
Server CI Nightly Race / Build Environment (push) Failing after 1s
This commit is contained in:
3
docs/site/scripts/gen-plugin-manifest-docs/go.mod
Normal file
3
docs/site/scripts/gen-plugin-manifest-docs/go.mod
Normal file
@@ -0,0 +1,3 @@
|
||||
module github.com/mattermost/mattermost/docs/site/scripts/gen-plugin-manifest-docs
|
||||
|
||||
go 1.26
|
||||
278
docs/site/scripts/gen-plugin-manifest-docs/main.go
Normal file
278
docs/site/scripts/gen-plugin-manifest-docs/main.go
Normal file
@@ -0,0 +1,278 @@
|
||||
// Command gen-plugin-manifest-docs generates docs/site/data/plugin-manifest-docs.json, the data
|
||||
// source consumed by the <PluginManifestDocs /> component that renders the plugin manifest
|
||||
// reference (docs/develop/integrate/plugins/manifest-reference.md).
|
||||
//
|
||||
// It reads server/public/model directly from this monorepo, walking the AST with go/parser +
|
||||
// go/doc instead of type-checking with golang.org/x/tools/go/packages (see gen-plugin-godocs for
|
||||
// why: it avoids requiring a Go toolchain matching server/public/go.mod's declared version).
|
||||
// Because of that, type resolution only follows types declared inside the model package's own
|
||||
// source (which is all model.Manifest ever references) — it doesn't resolve identifiers to types
|
||||
// from other packages.
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"go/ast"
|
||||
"go/doc"
|
||||
"go/parser"
|
||||
"go/token"
|
||||
"log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
"runtime"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type SchemaType string
|
||||
|
||||
const (
|
||||
Array SchemaType = "array"
|
||||
Bool SchemaType = "bool"
|
||||
Dict SchemaType = "dict"
|
||||
Number SchemaType = "number"
|
||||
Object SchemaType = "object"
|
||||
String SchemaType = "string"
|
||||
Interface SchemaType = "interface"
|
||||
)
|
||||
|
||||
const modelImportPath = "github.com/mattermost/mattermost/server/public/model"
|
||||
|
||||
type ObjectProperty struct {
|
||||
Name string
|
||||
DocHTML string `json:"DocHTML,omitempty"`
|
||||
Schema *TypeDocs `json:"Schema,omitempty"`
|
||||
}
|
||||
|
||||
type TypeDocs struct {
|
||||
Type SchemaType
|
||||
DocHTML string `json:"DocHTML,omitempty"`
|
||||
ObjectProperties []*ObjectProperty `json:"ObjectProperties,omitempty"`
|
||||
ValueSchema *TypeDocs `json:"ValueSchema,omitempty"`
|
||||
}
|
||||
|
||||
type Docs struct {
|
||||
Schema *TypeDocs
|
||||
}
|
||||
|
||||
var basicTypeKinds = map[string]SchemaType{
|
||||
"string": String,
|
||||
"bool": Bool,
|
||||
"byte": Number,
|
||||
"rune": Number,
|
||||
"int": Number, "int8": Number, "int16": Number, "int32": Number, "int64": Number,
|
||||
"uint": Number, "uint8": Number, "uint16": Number, "uint32": Number, "uint64": Number,
|
||||
"float32": Number, "float64": Number,
|
||||
}
|
||||
|
||||
// fset and filesByPath let namedTypeDocs recover which file (and therefore which imports) a given
|
||||
// model package type was declared in, so SelectorExpr fields can be resolved against the model
|
||||
// package's imports rather than by identifier name alone. Populated once in generateDocs.
|
||||
var (
|
||||
fset *token.FileSet
|
||||
filesByPath map[string]*ast.File
|
||||
)
|
||||
|
||||
// importAliases maps the local identifier a file uses for an imported package (its alias, or the
|
||||
// last path segment when unaliased) to that package's full import path.
|
||||
func importAliases(file *ast.File) map[string]string {
|
||||
aliases := make(map[string]string)
|
||||
for _, imp := range file.Imports {
|
||||
path := strings.Trim(imp.Path.Value, `"`)
|
||||
alias := path[strings.LastIndex(path, "/")+1:]
|
||||
if imp.Name != nil {
|
||||
alias = imp.Name.Name
|
||||
}
|
||||
aliases[alias] = path
|
||||
}
|
||||
return aliases
|
||||
}
|
||||
|
||||
func importsForPos(pos token.Pos) map[string]string {
|
||||
file := filesByPath[fset.Position(pos).Filename]
|
||||
if file == nil {
|
||||
return nil
|
||||
}
|
||||
return importAliases(file)
|
||||
}
|
||||
|
||||
func modelPackageDir() string {
|
||||
_, thisFile, _, ok := runtime.Caller(0)
|
||||
if !ok {
|
||||
log.Fatal("unable to determine source file location")
|
||||
}
|
||||
repoRoot := filepath.Clean(filepath.Join(filepath.Dir(thisFile), "..", "..", "..", ".."))
|
||||
return filepath.Join(repoRoot, "server", "public", "model")
|
||||
}
|
||||
|
||||
func docHTML(text string) string {
|
||||
buf := &bytes.Buffer{}
|
||||
doc.ToHTML(buf, text, nil)
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
func typeSpecOf(t *doc.Type) *ast.TypeSpec {
|
||||
for _, spec := range t.Decl.Specs {
|
||||
if typeSpec, ok := spec.(*ast.TypeSpec); ok {
|
||||
return typeSpec
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func namedTypeDocs(t *doc.Type, typesByName map[string]*doc.Type) *TypeDocs {
|
||||
spec := typeSpecOf(t)
|
||||
if spec == nil {
|
||||
return nil
|
||||
}
|
||||
ret := exprTypeDocs(spec.Type, typesByName, importsForPos(spec.Pos()))
|
||||
if ret != nil {
|
||||
ret.DocHTML = docHTML(t.Doc)
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
// jsonFieldName returns the field's JSON key, mirroring encoding/json's own rules: unexported
|
||||
// fields and those tagged `json:"-"` are never included; otherwise the tag's name component wins
|
||||
// if present (including when a comma-only tag like `json:",omitempty"` leaves it empty, in which
|
||||
// case the Go field name is used, same as an absent tag).
|
||||
func jsonFieldName(field *ast.Field) string {
|
||||
if len(field.Names) == 0 {
|
||||
// Anonymous (embedded) fields aren't handled by this generator — none exist in the
|
||||
// reachable model.Manifest schema.
|
||||
return ""
|
||||
}
|
||||
fieldName := field.Names[0].Name
|
||||
if !ast.IsExported(fieldName) {
|
||||
return ""
|
||||
}
|
||||
|
||||
if field.Tag == nil {
|
||||
return fieldName
|
||||
}
|
||||
tagValue := strings.Trim(field.Tag.Value, "`")
|
||||
jsonTag := reflect.StructTag(tagValue).Get("json")
|
||||
if jsonTag == "-" {
|
||||
return ""
|
||||
}
|
||||
name := strings.SplitN(jsonTag, ",", 2)[0]
|
||||
if name == "" {
|
||||
return fieldName
|
||||
}
|
||||
return name
|
||||
}
|
||||
|
||||
func exprTypeDocs(expr ast.Expr, typesByName map[string]*doc.Type, imports map[string]string) *TypeDocs {
|
||||
switch x := expr.(type) {
|
||||
case *ast.StarExpr:
|
||||
return exprTypeDocs(x.X, typesByName, imports)
|
||||
case *ast.ArrayType:
|
||||
return &TypeDocs{
|
||||
Type: Array,
|
||||
ValueSchema: exprTypeDocs(x.Elt, typesByName, imports),
|
||||
}
|
||||
case *ast.MapType:
|
||||
return &TypeDocs{
|
||||
Type: Dict,
|
||||
ValueSchema: exprTypeDocs(x.Value, typesByName, imports),
|
||||
}
|
||||
case *ast.StructType:
|
||||
ret := &TypeDocs{Type: Object}
|
||||
for _, field := range x.Fields.List {
|
||||
name := jsonFieldName(field)
|
||||
if name == "" {
|
||||
continue
|
||||
}
|
||||
ret.ObjectProperties = append(ret.ObjectProperties, &ObjectProperty{
|
||||
Name: name,
|
||||
DocHTML: docHTML(field.Doc.Text()),
|
||||
Schema: exprTypeDocs(field.Type, typesByName, imports),
|
||||
})
|
||||
}
|
||||
return ret
|
||||
case *ast.SelectorExpr:
|
||||
pkgIdent, ok := x.X.(*ast.Ident)
|
||||
if !ok || imports[pkgIdent.Name] != modelImportPath {
|
||||
log.Printf("unrecognized qualified type %v (not a reference to the model package)", x)
|
||||
return nil
|
||||
}
|
||||
// A qualified reference to the model package's own import path (i.e. a self-import
|
||||
// alias) still names a type declared in this same package, so resolve it the same way
|
||||
// an unqualified identifier would be.
|
||||
return exprTypeDocs(x.Sel, typesByName, imports)
|
||||
case *ast.InterfaceType:
|
||||
return &TypeDocs{Type: Interface}
|
||||
case *ast.Ident:
|
||||
if x.Name == "any" {
|
||||
return &TypeDocs{Type: Interface}
|
||||
}
|
||||
if kind, ok := basicTypeKinds[x.Name]; ok {
|
||||
return &TypeDocs{Type: kind}
|
||||
}
|
||||
if t, ok := typesByName[x.Name]; ok {
|
||||
return namedTypeDocs(t, typesByName)
|
||||
}
|
||||
log.Printf("unrecognized identifier %q (not a builtin or a model package type)", x.Name)
|
||||
return nil
|
||||
}
|
||||
|
||||
log.Printf("unrecognized ast.Expr: %T", expr)
|
||||
return nil
|
||||
}
|
||||
|
||||
func generateDocs() (*Docs, error) {
|
||||
modelDir := modelPackageDir()
|
||||
|
||||
fset = token.NewFileSet()
|
||||
notTest := func(info os.FileInfo) bool { return !strings.HasSuffix(info.Name(), "_test.go") }
|
||||
pkgs, err := parser.ParseDir(fset, modelDir, notTest, parser.ParseComments)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
modelPkg, ok := pkgs["model"]
|
||||
if !ok {
|
||||
return nil, os.ErrNotExist
|
||||
}
|
||||
|
||||
filesByPath = make(map[string]*ast.File, len(modelPkg.Files))
|
||||
for path, file := range modelPkg.Files {
|
||||
filesByPath[path] = file
|
||||
}
|
||||
|
||||
godocs := doc.New(modelPkg, "github.com/mattermost/mattermost/server/public/model", doc.Mode(0))
|
||||
|
||||
typesByName := make(map[string]*doc.Type, len(godocs.Types))
|
||||
for _, t := range godocs.Types {
|
||||
typesByName[t.Name] = t
|
||||
}
|
||||
|
||||
manifestType, ok := typesByName["Manifest"]
|
||||
if !ok {
|
||||
return nil, os.ErrNotExist
|
||||
}
|
||||
|
||||
return &Docs{
|
||||
Schema: namedTypeDocs(manifestType, typesByName),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func main() {
|
||||
docs, err := generateDocs()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
b, err := json.MarshalIndent(docs, "", " ")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
if _, err := os.Stdout.Write(b); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
if _, err := os.Stdout.Write([]byte("\n")); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user