Skip to content

Commit

Permalink
feat: generate shopware project config schema automatically
Browse files Browse the repository at this point in the history
  • Loading branch information
shyim committed Oct 1, 2024
1 parent b3daa1f commit 6db7601
Show file tree
Hide file tree
Showing 5 changed files with 556 additions and 312 deletions.
5 changes: 5 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,17 @@ require (
)

require (
github.com/bahlo/generic-list-go v0.2.0 // indirect
github.com/buger/jsonparser v1.1.1 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/invopop/jsonschema v0.12.0 // indirect
github.com/mailru/easyjson v0.7.7 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/tidwall/gjson v1.17.1 // indirect
github.com/tidwall/match v1.1.1 // indirect
github.com/tidwall/pretty v1.2.1 // indirect
github.com/tidwall/sjson v1.2.5 // indirect
github.com/wk8/go-ordered-map/v2 v2.1.8 // indirect
golang.org/x/sync v0.8.0 // indirect
)

Expand Down
11 changes: 11 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,12 @@ github.com/NYTimes/gziphandler v1.1.1 h1:ZUDjpQae29j0ryrS0u/B8HZfJBtBQHjqw2rQ2cq
github.com/NYTimes/gziphandler v1.1.1/go.mod h1:n/CVRwUEOgIxrgPvAQhUUr9oeUtvrhMomdKFjzJNB0c=
github.com/aymerick/douceur v0.2.0 h1:Mv+mAeH1Q+n9Fr+oyamOlAkUNPWPlA8PPGR0QAaYuPk=
github.com/aymerick/douceur v0.2.0/go.mod h1:wlT5vV2O3h55X9m7iVYN0TBM0NH/MmbLnd30/FjWUq4=
github.com/bahlo/generic-list-go v0.2.0 h1:5sz/EEAK+ls5wF+NeqDpk5+iNdMDXrh3z3nPnH1Wvgk=
github.com/bahlo/generic-list-go v0.2.0/go.mod h1:2KvAjgMlE5NNynlg/5iLrrCCZ2+5xWbdbCW3pNTGyYg=
github.com/bep/godartsass/v2 v2.1.0 h1:fq5Y1xYf4diu4tXABiekZUCA+5l/dmNjGKCeQwdy+s0=
github.com/bep/godartsass/v2 v2.1.0/go.mod h1:AcP8QgC+OwOXEq6im0WgDRYK7scDsmZCEW62o1prQLo=
github.com/buger/jsonparser v1.1.1 h1:2PnMjfWD7wBILjqQbt530v576A/cAbQvEW9gGIpYMUs=
github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0=
github.com/caarlos0/env/v9 v9.0.0 h1:SI6JNsOA+y5gj9njpgybykATIylrRMklbs5ch6wO6pc=
github.com/caarlos0/env/v9 v9.0.0/go.mod h1:ye5mlCVMYh6tZ+vCgrs/B95sj88cg5Tlnc0XIzgZ020=
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
Expand Down Expand Up @@ -56,16 +60,21 @@ github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWm
github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
github.com/invopop/jsonschema v0.12.0 h1:6ovsNSuvn9wEQVOyc72aycBMVQFKz7cPdMJn10CvzRI=
github.com/invopop/jsonschema v0.12.0/go.mod h1:ffZ5Km5SWWRAIN6wbDXItl95euhFz2uON45H2qjYt+0=
github.com/jaswdr/faker v1.19.1 h1:xBoz8/O6r0QAR8eEvKJZMdofxiRH+F0M/7MU9eNKhsM=
github.com/jaswdr/faker v1.19.1/go.mod h1:x7ZlyB1AZqwqKZgyQlnqEG8FDptmHlncA5u2zY/yi6w=
github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=
github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
github.com/klauspost/compress v1.17.10 h1:oXAz+Vh0PMUvJczoi+flxpnBEPxoER1IaAnU/NMPtT0=
github.com/klauspost/compress v1.17.10/go.mod h1:pMDklpSncoRMuLFrf1W9Ss9KT+0rH90U12bZKk7uwG0=
github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0=
github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
github.com/manifoldco/promptui v0.9.0 h1:3V4HzJk1TtXW1MTZMP7mdlwbBpIinw3HztaIlYthEiA=
github.com/manifoldco/promptui v0.9.0/go.mod h1:ka04sppxSGFAtxX0qhlYQjISsg9mR4GWtQEhdbn6Pgg=
github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
Expand Down Expand Up @@ -113,6 +122,8 @@ github.com/vulcand/oxy/v2 v2.0.0 h1:V+scHhd2xBjO8ojBRgxCM+OdZxRA/YTs8M70w5tdNy8=
github.com/vulcand/oxy/v2 v2.0.0/go.mod h1:uIAz3sYafO7i+V3SC8oDlMn/lt1i9aWcyXuXqVswKzE=
github.com/wI2L/jsondiff v0.6.0 h1:zrsH3FbfVa3JO9llxrcDy/XLkYPLgoMX6Mz3T2PP2AI=
github.com/wI2L/jsondiff v0.6.0/go.mod h1:D6aQ5gKgPF9g17j+E9N7aasmU1O+XvfmWm1y8UMmNpw=
github.com/wk8/go-ordered-map/v2 v2.1.8 h1:5h/BUHu93oj4gIdvHHHGsScSTMijfx5PeYkE/fJgbpc=
github.com/wk8/go-ordered-map/v2 v2.1.8/go.mod h1:5nJHM5DyteebpVlHnWMV0rPz6Zp7+xBAnxjb1X5vnTw=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
github.com/yuin/goldmark v1.7.4 h1:BDXOHExt+A7gwPCJgPIIq7ENvceR7we7rOS9TNoLZeg=
github.com/yuin/goldmark v1.7.4/go.mod h1:uzxRWxtg69N339t3louHJ7+O03ezfj6PlliRlaOzY1E=
Expand Down
38 changes: 38 additions & 0 deletions schema.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package main

import (
"encoding/json"
"github.com/FriendsOfShopware/shopware-cli/shop"
"github.com/invopop/jsonschema"
"os"
)

func generateProjectSchema() error {
r := new(jsonschema.Reflector)
r.FieldNameTag = "yaml"
r.RequiredFromJSONSchemaTags = true

if err := r.AddGoComments("github.com/FriendsOfShopware/shopware-cli", "./shop"); err != nil {
return err
}

schema := r.Reflect(&shop.Config{})

bytes, err := json.MarshalIndent(schema, "", " ")

if err != nil {
return err
}

if err := os.WriteFile("shop/shopware-project-schema.json", bytes, 0644); err != nil {
return err
}

return nil
}

func main() {

Check failure on line 34 in schema.go

View workflow job for this annotation

GitHub Actions / ubuntu-latest

main redeclared in this block

Check failure on line 34 in schema.go

View workflow job for this annotation

GitHub Actions / lint

main redeclared in this block

Check failure on line 34 in schema.go

View workflow job for this annotation

GitHub Actions / run

main redeclared in this block

Check failure on line 34 in schema.go

View workflow job for this annotation

GitHub Actions / macos-14

main redeclared in this block

Check failure on line 34 in schema.go

View workflow job for this annotation

GitHub Actions / windows-latest

main redeclared in this block
if err := generateProjectSchema(); err != nil {
panic(err)
}
}
160 changes: 135 additions & 25 deletions shop/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ package shop

import (
"fmt"
"github.com/invopop/jsonschema"
orderedmap "github.com/wk8/go-ordered-map/v2"
"os"
"strings"

Expand All @@ -14,38 +16,56 @@ import (
)

type Config struct {
AdditionalConfigs []string `yaml:"include,omitempty"`
URL string `yaml:"url"`
Build *ConfigBuild `yaml:"build,omitempty"`
AdminApi *ConfigAdminApi `yaml:"admin_api,omitempty"`
ConfigDump *ConfigDump `yaml:"dump,omitempty"`
Sync *ConfigSync `yaml:"sync,omitempty"`
foundConfig bool
AdditionalConfigs []string `yaml:"include,omitempty"`
// The URL of the Shopware instance
URL string `yaml:"url"`
Build *ConfigBuild `yaml:"build,omitempty"`
AdminApi *ConfigAdminApi `yaml:"admin_api,omitempty"`
ConfigDump *ConfigDump `yaml:"dump,omitempty"`
Sync *ConfigSync `yaml:"sync,omitempty"`
ConfigDeployment *ConfigDeployment `yaml:"deployment,omitempty"`
foundConfig bool
}

type ConfigBuild struct {
DisableAssetCopy bool `yaml:"disable_asset_copy,omitempty"`
RemoveExtensionAssets bool `yaml:"remove_extension_assets,omitempty"`
KeepExtensionSource bool `yaml:"keep_extension_source,omitempty"`
KeepSourceMaps bool `yaml:"keep_source_maps,omitempty"`
CleanupPaths []string `yaml:"cleanup_paths,omitempty"`
Browserslist string `yaml:"browserslist,omitempty"`
ExcludeExtensions []string `yaml:"exclude_extensions,omitempty"`
// When enabled, the assets will not be copied to the public folder
DisableAssetCopy bool `yaml:"disable_asset_copy,omitempty"`
// When enabled, the assets of extensions will be removed from the extension public folder. (Requires Shopware 6.5.2.0)
RemoveExtensionAssets bool `yaml:"remove_extension_assets,omitempty"`
// When enabled, the extensions source code will be keep in the final build
KeepExtensionSource bool `yaml:"keep_extension_source,omitempty"`
// When enabled, the source maps will not be removed from the final build
KeepSourceMaps bool `yaml:"keep_source_maps,omitempty"`
// Paths to delete for the final build
CleanupPaths []string `yaml:"cleanup_paths,omitempty"`
// Browserslist configuration for the Storefront build
Browserslist string `yaml:"browserslist,omitempty"`
// Extensions to exclude from the build
ExcludeExtensions []string `yaml:"exclude_extensions,omitempty"`
}

type ConfigAdminApi struct {
ClientId string `yaml:"client_id,omitempty"`
ClientSecret string `yaml:"client_secret,omitempty"`
Username string `yaml:"username,omitempty"`
Password string `yaml:"password,omitempty"`
DisableSSLCheck bool `yaml:"disable_ssl_check,omitempty"`
// Client ID of integration
ClientId string `yaml:"client_id,omitempty"`
// Client Secret of integration
ClientSecret string `yaml:"client_secret,omitempty"`
// Username of admin user
Username string `yaml:"username,omitempty"`
// Password of admin user
Password string `yaml:"password,omitempty"`
// Disable SSL certificate check
DisableSSLCheck bool `yaml:"disable_ssl_check,omitempty"`
}

type ConfigDump struct {
// Allows to rewrite single columns, perfect for GDPR compliance
Rewrite map[string]core.Rewrite `yaml:"rewrite,omitempty"`
NoData []string `yaml:"nodata,omitempty"`
Ignore []string `yaml:"ignore,omitempty"`
Where map[string]string `yaml:"where,omitempty"`
// Only export the schema of these tables
NoData []string `yaml:"nodata,omitempty"`
// Ignore these tables from export
Ignore []string `yaml:"ignore,omitempty"`
// Add an where condition to that table, schema is table name as key, and where statement as value
Where map[string]string `yaml:"where,omitempty"`
}

type ConfigSync struct {
Expand All @@ -55,9 +75,41 @@ type ConfigSync struct {
Entity []EntitySync `yaml:"entity"`
}

type ConfigDeployment struct {
Hooks struct {
// The pre hook will be executed before the deployment
Pre string `yaml:"pre"`
// The post hook will be executed after the deployment
Post string `yaml:"post"`
// The pre-install hook will be executed before the installation
PreInstall string `yaml:"pre-install"`
// The post-install hook will be executed after the installation
PostInstall string `yaml:"post-install"`
// The pre-update hook will be executed before the update
PreUpdate string `yaml:"pre-update"`
// The post-update hook will be executed after the update
PostUpdate string `yaml:"post-update"`
} `yaml:"hooks"`

// The extension management of the deployment
ExtensionManagement struct {
// When enabled, the extensions will be installed, updated, and removed
Enabled bool `yaml:"enabled"`
// Which extensions should not be managed
Exclude []string
} `yaml:"extension-management"`

OneTimeTasks []struct {
Id string `yaml:"id" jsonschema:"required"`
Script string `yaml:"script" jsonschema:"required"`
} `yaml:"one-time-tasks"`
}

type ConfigSyncConfig struct {
SalesChannel *string `yaml:"sales_channel,omitempty"`
Settings map[string]interface{} `yaml:"settings"`
// Sales Channel ID to apply
SalesChannel *string `yaml:"sales_channel,omitempty"`
// Configurations of that Sales Channel
Settings map[string]interface{} `yaml:"settings"`
}

type ThemeConfig struct {
Expand All @@ -72,10 +124,68 @@ type MailTemplate struct {

type EntitySync struct {
Entity string `yaml:"entity"`
Exists *[]interface{} `yaml:"exists"`
Exists *[]EntitySyncFilter `yaml:"exists,omitempty"`
Payload map[string]interface{} `yaml:"payload"`
}

type EntitySyncFilter struct {
// The type of filter
Type string `yaml:"type" jsonschema:"required,enum=equals,enum=multi,enum=contains,enum=prefix,enum=suffix,enum=not,enum=range,enum=until,enum=equalsAll,enum=equalsAny"`
// The field to filter on
Field string `yaml:"field" jsonschema:"required"`
// The actual filter value
Value interface{} `yaml:"value"`
// The operator to use for multiple filters
Operator *string `yaml:"operator,omitempty" jsonschema:"enum=AND,enum=OR,enum=XOR"`
// The filters to apply, when type set to multi
Queries *[]EntitySyncFilter `yaml:"queries,omitempty"`
}

func (s EntitySyncFilter) JSONSchema() *jsonschema.Schema {
properties := orderedmap.New[string, *jsonschema.Schema]()

properties.Set("type", &jsonschema.Schema{
Type: "string",
Enum: []interface{}{"equals", "multi", "contains", "prefix", "suffix", "not", "range", "until", "equalsAll", "equalsAny"},
})

properties.Set("field", &jsonschema.Schema{
Type: "string",
Description: "The field to filter on",
})

properties.Set("value", &jsonschema.Schema{
Description: "The actual filter value",
})

properties.Set("operator", &jsonschema.Schema{
Type: "string",
Enum: []interface{}{"AND", "OR", "XOR"},
})

ifProperties := orderedmap.New[string, *jsonschema.Schema]()
ifProperties.Set("type", &jsonschema.Schema{
Const: "multi",
})

return &jsonschema.Schema{
Type: "object",
Title: "Entity Sync Filter",
Properties: properties,
Required: []string{"type", "field"},
AllOf: []*jsonschema.Schema{
{
If: &jsonschema.Schema{
Properties: ifProperties,
Then: &jsonschema.Schema{
Required: []string{"type", "queries"},
},
},
},
},
}
}

type MailTemplateTranslation struct {
Language string `yaml:"language"`
SenderName string `yaml:"sender_name"`
Expand Down
Loading

0 comments on commit 6db7601

Please sign in to comment.