From 48ee4a8b63179487689f40599df74396579c8f2e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A1nos=20Mik=C3=B3?= Date: Thu, 9 Jan 2025 13:41:28 +0100 Subject: [PATCH] feat: rework bootstrapping to fix #90 --- CHANGELOG.md | 5 + VERSION.txt | 2 +- cmd/bootstrap/bootstrap.go | 2 +- cmd/sync/sync.go | 8 - internal/config/config.go | 141 +++---- internal/config/config_test.go | 92 +++-- internal/logic/bootstrap.go | 295 ++++++-------- internal/logic/bootstrapMagento1.go | 112 +++--- internal/logic/bootstrapMagento2.go | 558 +++++++++++++++------------ internal/logic/bootstrapShopware.go | 261 ++++++++----- internal/logic/bootstrapWordpress.go | 39 +- internal/logic/install.go | 1 + sonar-project.properties | 2 +- 13 files changed, 816 insertions(+), 702 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 46312037..cf3af072 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,11 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [0.7.3] - 2025-01-09 +### Fixed + +- Rework bootstrap handling + ## [0.7.2] - 2025-01-08 ### Fixed diff --git a/VERSION.txt b/VERSION.txt index 2c0a9c7b..3d105a6f 100644 --- a/VERSION.txt +++ b/VERSION.txt @@ -1 +1 @@ -v0.7.2 +v0.7.3 diff --git a/cmd/bootstrap/bootstrap.go b/cmd/bootstrap/bootstrap.go index 7871809b..50b1c28a 100644 --- a/cmd/bootstrap/bootstrap.go +++ b/cmd/bootstrap/bootstrap.go @@ -71,7 +71,7 @@ func NewBootstrapCmd(conf *config.Config) *cmdpkg.Command { // --magento-version cmd.Flags().String( - "magento-version", version.Must(conf.MagentoVersion()).String(), "magento version", + "magento-version", conf.MagentoVersionFromConfig().String(), "magento version", ) _ = cmd.Config.BindPFlag(fmt.Sprintf("%s_magento_version", conf.AppName()), cmd.Flags().Lookup("magento-version")) diff --git a/cmd/sync/sync.go b/cmd/sync/sync.go index 82b72a13..54b75e4d 100644 --- a/cmd/sync/sync.go +++ b/cmd/sync/sync.go @@ -23,14 +23,6 @@ func NewCmdSync(conf *config.Config) *cmdpkg.Command { PreRun: func(syncCheckCmd *cobra.Command, args []string) {}, Args: cobra.ExactArgs(0), PersistentPreRunE: func(cmd *cobra.Command, args []string) error { - // TODO; Check if this is needed - // err := reward.SyncCheck() - // if err != nil { - // return err - // } - // - // reward.SetSyncSettings() - return nil }, Run: func(cmd *cobra.Command, args []string) { diff --git a/internal/config/config.go b/internal/config/config.go index e73d088d..090a271a 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -8,7 +8,6 @@ import ( "os" "path" "path/filepath" - "regexp" "runtime" "strings" @@ -28,11 +27,6 @@ import ( "github.com/rewardenv/reward/pkg/util" ) -const ( - // https://semver.org/#is-there-a-suggested-regular-expression-regex-to-check-a-semver-string - SemverRegexp = `^(?P0|[1-9]\d*)\.(?P0|[1-9]\d*)\.(?P0|[1-9]\d*)(?:-(?P(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+(?P[0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$` -) - var ( // ErrEnvNameIsInvalid occurs when the environment name is invalid. It should be a valid hostname. ErrEnvNameIsInvalid = errors.New("environment name is invalid, it should match RFC1178") @@ -55,6 +49,9 @@ var ( // ErrUnknownEnvType occurs when an unknown environment type is specified. ErrUnknownEnvType = errors.New("unknown env type") + + ErrMagentoVersionIsNotSemver = errors.New("version string is not semver") + ErrMagentoVersionIsInvalid = errors.New("version string is invalid") ) // FS is the implementation of Afero Filesystem. It's a filesystem wrapper and used for testing. @@ -872,93 +869,99 @@ func (c *Config) ShopwareMode() string { return c.GetString(fmt.Sprintf("%s_shopware_mode", c.AppName())) } -// MagentoVersion returns a *version.Version object which contains the Magento version. -func (c *Config) MagentoVersion() (*version.Version, error) { - log.Debugln("Looking up Magento version...") - - magentoVersion := new(version.Version) - - type ComposerJSON struct { +func (c *Config) MagentoVersionFromComposerJSON() (*version.Version, error) { + var composerJSON struct { Name string `json:"name"` Version string `json:"version"` Require map[string]string `json:"require"` } - var composerJSON ComposerJSON + data, err := FS.ReadFile("composer.json") + if err != nil { + log.Debugln("...cannot read composer.json. Using .env settings.") - if util.FileExists("composer.json") { - data, err := FS.ReadFile("composer.json") - if err != nil { - log.Debugln("...cannot read composer.json. Using .env settings.") + return c.MagentoVersionFromConfig(), nil + } - magentoVersion = c.MagentoVersionFromConfig() - } + if err := json.Unmarshal(data, &composerJSON); err != nil { + log.Debugln("...cannot unmarshal composer.json. Using .env settings.") + + return c.MagentoVersionFromConfig(), nil + } - if err := json.Unmarshal(data, &composerJSON); err != nil { - log.Debugln("...cannot unmarshal composer.json. Using .env settings.") + // Search for old format of Magento package name. + if util.CheckRegexInString(`^magento/magento2(ce|ee)$`, composerJSON.Name) && + composerJSON.Version != "" { + log.Debugf( + "...using magento/magento2(ce|ee) package version from composer.json. Found version: %s.", + composerJSON.Version, + ) - magentoVersion = c.MagentoVersionFromConfig() + magentoVersion, err := version.NewVersion(composerJSON.Version) + if err != nil { + return nil, ErrMagentoVersionIsNotSemver } - if util.CheckRegexInString( - `^magento/magento2(ce|ee)$`, - composerJSON.Name, - ) && composerJSON.Version != "" { - re := regexp.MustCompile(SemverRegexp) - ver := re.Find([]byte(composerJSON.Version)) + return magentoVersion, nil + } + + // Search for new format of Magento package name. + for key, val := range composerJSON.Require { + if util.CheckRegexInString(`^magento/product-(enterprise|community)-edition$`, key) { + log.Debugf( + "...using magento/product-(enterprise-community)-edition "+ + "package version from composer.json. Found version: %s.", + val, + ) + + magentoVersion, err := version.NewVersion(val) + if err != nil { + return nil, ErrMagentoVersionIsNotSemver + } + return magentoVersion, nil + } + + if util.CheckRegexInString(`^magento/magento-cloud-metapackage$`, key) { log.Debugf( - "...using magento/magento2(ce|ee) package version from composer.json. Found version: %s.", - ver, + "...using magento/magento-cloud-metapackage package version from composer.json. Found version: %s.", + val, ) - magentoVersion, err = version.NewVersion(string(ver)) + magentoVersion, err := version.NewVersion(val) if err != nil { - return nil, errors.Wrap(err, "cannot parse Magento version from composer.json") + return nil, ErrMagentoVersionIsNotSemver } + + return magentoVersion, nil } + } - if magentoVersion.String() == "" { - for key, val := range composerJSON.Require { - if util.CheckRegexInString(`^magento/product-(enterprise|community)-edition$`, key) { - re := regexp.MustCompile(SemverRegexp) - ver := re.Find([]byte(val)) - - log.Debugf( - "...using magento/product-(enterprise-community)-edition "+ - "package version from composer.json. Found version: %s.", - ver, - ) - - magentoVersion, err = version.NewVersion(string(ver)) - if err != nil { - return nil, errors.Wrap( - err, "cannot parse Magento version from composer.json", - ) - } - } else if util.CheckRegexInString(`^magento/magento-cloud-metapackage$`, key) { - re := regexp.MustCompile(SemverRegexp) - ver := re.Find([]byte(val)) - - log.Debugf( - "...using magento/magento-cloud-metapackage package version from composer.json. Found version: %s.", - ver, - ) - - magentoVersion, err = version.NewVersion(string(ver)) - if err != nil { - return nil, errors.Wrap( - err, "cannot parse Magento version from composer.json", - ) - } - } + return nil, ErrMagentoVersionIsInvalid +} + +// MagentoVersion returns a *version.Version object which contains the Magento version. +func (c *Config) MagentoVersion() (*version.Version, error) { + log.Debugln("Looking up Magento version...") + + if util.FileExists("composer.json") { + magentoVersion, err := c.MagentoVersionFromComposerJSON() + if err != nil { + if errors.Is(err, ErrMagentoVersionIsNotSemver) { + log.Debugln("Cannot parse exact Magento version from composer.json.") + + return version.Must(version.NewVersion("0.0.0+undefined")), nil } + + return nil, errors.Wrap(err, "getting Magento version from composer.json") } + log.Debugf("...found Magento version in composer.json. Version: %s.", magentoVersion.String()) + return magentoVersion, nil } - magentoVersion = c.MagentoVersionFromConfig() + magentoVersion := c.MagentoVersionFromConfig() log.Debugf( "...cannot find Magento version in composer.json, using .env settings. Version: %s.", @@ -1209,7 +1212,7 @@ func (c *Config) ElasticsearchVersion() *version.Version { return version.Must(version.NewVersion(c.GetString("elasticsearch_version"))) } - return version.Must(version.NewVersion("0.0")) + return version.Must(version.NewVersion("0.0.0+undefined")) } // ServiceEnabled returns true if service is enabled in Config settings. diff --git a/internal/config/config_test.go b/internal/config/config_test.go index a18b0485..f4230731 100644 --- a/internal/config/config_test.go +++ b/internal/config/config_test.go @@ -4,7 +4,6 @@ import ( "os" "testing" - "github.com/hashicorp/go-version" "github.com/spf13/afero" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/suite" @@ -29,7 +28,7 @@ func TestConfigTestSuite(t *testing.T) { } func (suite *ConfigTestSuite) TestConfigMagentoVersion() { - c := New("reward", "0.0.1").Init() + config := New("reward", "0.0.1").Init() type fields struct { composerJSON string @@ -37,13 +36,13 @@ func (suite *ConfigTestSuite) TestConfigMagentoVersion() { tests := []struct { name string fields fields - want *version.Version + want string wantErr bool }{ { name: "empty composer.json", fields: fields{}, - want: version.Must(version.NewVersion("2.4.7-p2")), + want: "2.4.7-p2", wantErr: false, }, { @@ -51,7 +50,7 @@ func (suite *ConfigTestSuite) TestConfigMagentoVersion() { fields: fields{ composerJSON: `{]`, }, - want: version.Must(version.NewVersion("2.4.7-p2")), + want: "2.4.7-p2", wantErr: false, }, { @@ -61,10 +60,33 @@ func (suite *ConfigTestSuite) TestConfigMagentoVersion() { { "name": "magento/magento2ce", "version": "2.3.8-p9" -} -`, +}`, + }, + want: "2.3.8-p9", + wantErr: false, + }, + { + name: "composer.json with valid version constraint (old format)", + fields: fields{ + composerJSON: ` +{ + "name": "magento/magento2ce", + "version": ">=2.4.6 <2.4.7" +}`, }, - want: version.Must(version.NewVersion("2.3.8-p9")), + want: "0.0.0+undefined", + wantErr: false, + }, + { + name: "composer.json with valid version constraint (old format)", + fields: fields{ + composerJSON: ` +{ + "name": "magento/magento2ce", + "version": "dev-master" +}`, + }, + want: "0.0.0+undefined", wantErr: false, }, { @@ -74,11 +96,10 @@ func (suite *ConfigTestSuite) TestConfigMagentoVersion() { { "name": "magento/magento2ce", "version": "invalid version" -} -`, +}`, }, - want: nil, - wantErr: true, + want: "0.0.0+undefined", + wantErr: false, }, { name: "composer.json with valid version (new format)", @@ -90,10 +111,23 @@ func (suite *ConfigTestSuite) TestConfigMagentoVersion() { "require": { "magento/product-community-edition": "2.4.4-p1" } -} -`, +}`, }, - want: version.Must(version.NewVersion("2.4.4-p1")), + want: "2.4.4-p1", + wantErr: false, + }, + { + name: "composer.json with valid constraint", + fields: fields{ + composerJSON: ` +{ + "name": "magento/project-community-edition", + "require": { + "magento/product-community-edition": ">=2.4.6 <2.4.7" + } +}`, + }, + want: "0.0.0+undefined", wantErr: false, }, { @@ -105,11 +139,10 @@ func (suite *ConfigTestSuite) TestConfigMagentoVersion() { "require": { "magento/product-community-edition": "invalid version" } -} -`, +}`, }, - want: nil, - wantErr: true, + want: "0.0.0+undefined", + wantErr: false, }, { name: "composer.json with valid version for cloud metapackage", @@ -120,10 +153,9 @@ func (suite *ConfigTestSuite) TestConfigMagentoVersion() { "require": { "magento/magento-cloud-metapackage": "2.4.5-p8" } -} -`, +}`, }, - want: version.Must(version.NewVersion("2.4.5-p8")), + want: "2.4.5-p8", wantErr: false, }, { @@ -135,27 +167,27 @@ func (suite *ConfigTestSuite) TestConfigMagentoVersion() { "require": { "magento/magento-cloud-metapackage": "invalid version" } -} -`, +}`, }, - want: nil, - wantErr: true, + want: "0.0.0+undefined", + wantErr: false, }, } + for _, tt := range tests { suite.T().Run(tt.name, func(t *testing.T) { if tt.fields.composerJSON != "" { _ = FS.WriteFile("composer.json", []byte(tt.fields.composerJSON), os.FileMode(0o644)) } - got, err := c.MagentoVersion() - + v, err := config.MagentoVersion() if tt.wantErr { - assert.NotNil(suite.T(), err) - assert.Nil(suite.T(), got) + assert.Error(suite.T(), err) + return } + got := v.String() assert.Equal(suite.T(), tt.want, got) }) } diff --git a/internal/logic/bootstrap.go b/internal/logic/bootstrap.go index be66103e..f624bbe5 100644 --- a/internal/logic/bootstrap.go +++ b/internal/logic/bootstrap.go @@ -2,53 +2,63 @@ package logic import ( "fmt" - "path/filepath" "github.com/hashicorp/go-version" "github.com/pkg/errors" + "github.com/sethvargo/go-password/password" log "github.com/sirupsen/logrus" - - "github.com/rewardenv/reward/pkg/util" ) type bootstrapper struct { *Client - composerVerbosityFlag string - debug bool } func newBootstrapper(c *Client) *bootstrapper { - composerVerbosityFlag := "--verbose" - if c.IsDebug() { - composerVerbosityFlag = "-vvv" - } - return &bootstrapper{ - Client: c, - composerVerbosityFlag: composerVerbosityFlag, - debug: c.IsDebug(), + Client: c, } } +type magento1 struct { + *bootstrapper +} +type magento2 struct { + *bootstrapper +} +type wordpress struct { + *bootstrapper +} +type shopware struct { + *bootstrapper +} + // RunCmdBootstrap represents the bootstrap command. func (c *Client) RunCmdBootstrap() error { switch c.EnvType() { case "magento2": - if err := newBootstrapper(c).bootstrapMagento2(); err != nil { + b := magento2{newBootstrapper(c)} + if err := b.bootstrap(); err != nil { return errors.Wrap(err, "bootstrapping magento2") } + case "magento1": - if err := newBootstrapper(c).bootstrapMagento1(); err != nil { + b := magento1{newBootstrapper(c)} + if err := b.bootstrap(); err != nil { return errors.Wrap(err, "bootstrapping magento1") } + case "wordpress": - if err := newBootstrapper(c).bootstrapWordpress(); err != nil { + b := wordpress{newBootstrapper(c)} + if err := b.bootstrap(); err != nil { return errors.Wrap(err, "bootstrapping wordpress") } + case "shopware": - if err := newBootstrapper(c).bootstrapShopware(); err != nil { + b := shopware{newBootstrapper(c)} + if err := b.bootstrap(); err != nil { return errors.Wrap(err, "bootstrapping shopware") } + default: return errors.New("currently not supported for bootstrapping") } @@ -97,116 +107,6 @@ func (c *bootstrapper) prepare() error { return nil } -func (c *bootstrapper) download() (bool, error) { - if c.SkipComposerInstall() { - return false, nil - } - - var ( - freshInstall = false - composerVerbosityFlag = "--verbose" - rsyncVerbosityFlag = "-v" - ) - - if c.IsDebug() { - composerVerbosityFlag = "-vvv" - rsyncVerbosityFlag = "-v" - } - - switch c.EnvType() { - case "magento2": - if !util.FileExists(filepath.Join(c.Cwd(), c.WebRoot(), "composer.json")) { - log.Println("Creating Magento 2 composer project...") - - magentoVersion, err := c.MagentoVersion() - if err != nil { - return false, errors.Wrap(err, "determining magento version") - } - - freshInstall = true - - if err = c.RunCmdEnvExec( - fmt.Sprintf( - "composer create-project %s --profile --no-install "+ - "--repository-url=https://repo.magento.com/ "+ - "magento/project-%s-edition=%s /tmp/magento-tmp/", - composerVerbosityFlag, - c.MagentoType(), - magentoVersion.String(), - ), - ); err != nil { - return false, errors.Wrap(err, "creating composer magento project") - } - - if err = c.RunCmdEnvExec( - fmt.Sprintf( - `rsync %s -au --remove-source-files --chmod=D2775,F644 /tmp/magento-tmp/ /var/www/html/`, - rsyncVerbosityFlag, - ), - ); err != nil { - return false, errors.Wrap(err, "moving magento project install files") - } - - log.Println("...Magento 2 composer project created.") - } - - case "wordpress": - if !util.FileExists(filepath.Join(c.Cwd(), c.WebRoot(), "index.php")) { - log.Println("Downloading and installing WordPress...") - - freshInstall = true - - if err := c.RunCmdEnvExec("wget -qO /tmp/wordpress.tar.gz https://wordpress.org/latest.tar.gz"); err != nil { - return false, errors.Wrap(err, "downloading wordpress") - } - - if err := c.RunCmdEnvExec("tar -zxf /tmp/wordpress.tar.gz --strip-components=1 -C /var/www/html"); err != nil { - return false, errors.Wrap(err, "extracting wordpress") - } - - if err := c.RunCmdEnvExec("rm -f /tmp/wordpress.tar.gz"); err != nil { - return false, errors.Wrap(err, "removing wordpress archive") - } - - log.Println("...WordPress downloaded.") - } - - case "shopware": - if !util.FileExists(filepath.Join(c.Cwd(), c.WebRoot(), "composer.json")) { - log.Println("Downloading and installing Shopware...") - - freshInstall = true - - path := "production" - if c.ShopwareMode() == "dev" || c.ShopwareMode() == "development" { - path = "development" - } - - if err := c.RunCmdEnvExec( - fmt.Sprintf( - "wget -qO /tmp/shopware.tar.gz https://github.com/shopware/%s/archive/refs/tags/v%s.tar.gz", - path, - version.Must(c.ShopwareVersion()).String(), - ), - ); err != nil { - return false, errors.Wrap(err, "downloading shopware") - } - - if err := c.RunCmdEnvExec("tar -zxf /tmp/shopware.tar.gz --strip-components=1 -C /var/www/html"); err != nil { - return false, errors.Wrap(err, "extracting shopware") - } - - if err := c.RunCmdEnvExec("rm -f /tmp/shopware.tar.gz"); err != nil { - return false, errors.Wrap(err, "removing shopware archive") - } - - log.Println("...Shopware downloaded.") - } - } - - return freshInstall, nil -} - func (c *bootstrapper) composerInstall() error { if c.SkipComposerInstall() { return nil @@ -214,12 +114,8 @@ func (c *bootstrapper) composerInstall() error { log.Println("Installing composer dependencies...") - if err := c.RunCmdEnvExec( - fmt.Sprintf( - "composer install %s --profile", - c.composerVerbosityFlag, - ), - ); err != nil { + command := fmt.Sprintf("%s install --profile", c.composerCommand()) + if err := c.RunCmdEnvExec(command); err != nil { return errors.Wrap(err, "installing composer dependencies") } @@ -235,51 +131,71 @@ func (c *bootstrapper) composerPreInstall() error { log.Println("Configuring composer...") - composerVersion := 2 if c.ComposerVersion().LessThan(version.Must(version.NewVersion("2.0.0"))) { - composerVersion = 1 + if err := c.setComposer1(); err != nil { + return err + } + } else { + if err := c.setComposer2(); err != nil { + return err + } } - if composerVersion == 1 { - log.Println("Setting default composer version to 1.x") + log.Println("...composer configured.") - // Change default Composer Version - //nolint:lll - if err := c.RunCmdEnvExec(fmt.Sprintf("%s alternatives %s --set composer %s/composer1", c.SudoCommand(), c.AlternativesArgs(), c.LocalBinPath())); err != nil { - return errors.Wrap(err, "changing default composer version") - } - } else { - log.Println("Setting default composer version to 2.x") + return nil +} + +func (c *bootstrapper) setComposer2() error { + log.Println("Setting default composer version to 2.x") - // Change default Composer Version - //nolint:lll - if err := c.RunCmdEnvExec(fmt.Sprintf("%s alternatives %s --set composer %s/composer2", c.SudoCommand(), c.AlternativesArgs(), c.LocalBinPath())); err != nil { + // Change default Composer Version + command := fmt.Sprintf("%s alternatives %s --set composer %s/composer2", + c.SudoCommand(), + c.AlternativesArgs(), + c.LocalBinPath(), + ) + if err := c.RunCmdEnvExec(command); err != nil { + return errors.Wrap(err, "changing default composer version") + } + + // Specific Composer Version + if !c.ComposerVersion().Equal(version.Must(version.NewVersion("2.0.0"))) { + command = fmt.Sprintf("%s %s self-update %s", + c.SudoCommand(), + c.composerCommand(), + c.ComposerVersion().String(), + ) + if err := c.RunCmdEnvExec(command); err != nil { return errors.Wrap(err, "changing default composer version") } + } - // Specific Composer Version - if !c.ComposerVersion().Equal(version.Must(version.NewVersion("2.0.0"))) { - if err := c.RunCmdEnvExec( - fmt.Sprintf("%s composer self-update %s", c.SudoCommand(), c.ComposerVersion().String()), - ); err != nil { - return errors.Wrap(err, "changing default composer version") - } - } + return nil +} + +func (c *bootstrapper) setComposer1() error { + log.Println("Setting default composer version to 1.x") + + // Change default Composer Version + command := fmt.Sprintf("%s alternatives %s --set composer %s/composer1", + c.SudoCommand(), + c.AlternativesArgs(), + c.LocalBinPath(), + ) + if err := c.RunCmdEnvExec(command); err != nil { + return errors.Wrap(err, "changing default composer version") } // Configure parallelism for composer 1 using hirak/prestissimo - if c.Parallel() && composerVersion < 2 { - if err := c.RunCmdEnvExec( - fmt.Sprintf( - "composer global require %s --profile hirak/prestissimo", - c.composerVerbosityFlag, - ), - ); err != nil { - return errors.Wrap(err, "installing hirak/prestissimo composer module") - } + if !c.Parallel() { + return nil } - log.Println("...composer configured.") + command = fmt.Sprintf("%s global require --profile hirak/prestissimo", c.composerCommand()) + if err := c.RunCmdEnvExec(command); err != nil { + return errors.Wrap(err, "installing hirak/prestissimo composer module") + } return nil } @@ -289,31 +205,46 @@ func (c *bootstrapper) composerPostInstall() error { return nil } - composerVersion := 2 if c.ComposerVersion().LessThan(version.Must(version.NewVersion("2.0.0"))) { - composerVersion = 1 - } - - if !c.SkipComposerInstall() { - if c.Parallel() && composerVersion != 2 { - log.Println("Removing hirak/prestissimo composer module...") + if !c.Parallel() { + return nil + } - if err := c.RunCmdEnvExec( - fmt.Sprintf( - "composer global remove %s --profile hirak/prestissimo", - c.composerVerbosityFlag, - ), - ); err != nil { - return errors.Wrap(err, "removing hirak/prestissimo module") - } + log.Println("Removing hirak/prestissimo composer module...") - log.Println("...hirak/prestissimo composer module removed.") + command := fmt.Sprintf("%s global remove --profile hirak/prestissimo", c.composerCommand()) + if err := c.RunCmdEnvExec(command); err != nil { + return errors.Wrap(err, "removing hirak/prestissimo module") } + + log.Println("...hirak/prestissimo composer module removed.") } return nil } -func (c *Client) RunCmdEnvExec(args string) error { +func (c *bootstrapper) RunCmdEnvExec(args string) error { return c.RunCmdEnv(append([]string{"exec", "-T", c.DefaultSyncedContainer(c.EnvType()), "bash", "-c"}, args)) } + +func (c *bootstrapper) generatePassword() string { + return password.MustGenerate(16, 2, 0, false, false) +} + +func (c *bootstrapper) composerCommand() string { + verbosity := "--verbose" + if c.IsDebug() { + verbosity = "-vvv" + } + + return "composer " + verbosity +} + +func (c *bootstrapper) rsyncCommand() string { + verbosity := "-v" + if c.IsDebug() { + verbosity = "-vv" + } + + return "rsync " + verbosity +} diff --git a/internal/logic/bootstrapMagento1.go b/internal/logic/bootstrapMagento1.go index 4ace228d..43689277 100644 --- a/internal/logic/bootstrapMagento1.go +++ b/internal/logic/bootstrapMagento1.go @@ -8,60 +8,48 @@ import ( "text/template" "github.com/pkg/errors" - "github.com/sethvargo/go-password/password" log "github.com/sirupsen/logrus" "github.com/rewardenv/reward/internal/templates" "github.com/rewardenv/reward/pkg/util" ) -// bootstrapMagento1 runs a full Magento 1 bootstrap process. +// bootstrap runs a full Magento 1 bootstrap process. // Note: it will not install Magento 1 from zero, but only configures Magento 1's local.xml. -func (c *bootstrapper) bootstrapMagento1() error { +func (c *magento1) bootstrap() error { magentoVersion, err := c.MagentoVersion() if err != nil { return errors.Wrap(err, "getting magento version") } - log.Printf("Bootstrapping Magento %s...", magentoVersion.String()) - if !util.AskForConfirmation("Would you like to bootstrap Magento v" + magentoVersion.String() + "?") { return nil } + log.Printf("Bootstrapping Magento %s...", magentoVersion.String()) + if err := c.prepare(); err != nil { return errors.Wrap(err, "error during bootstrap preparation") } - // Composer Install - if util.FileExists(filepath.Join(c.Cwd(), c.WebRoot(), "composer.json")) { - if err := c.composerPreInstall(); err != nil { - return errors.Wrap(err, "configuring composer") - } - - if err := c.composerInstall(); err != nil { - return errors.Wrap(err, "running composer install") - } - - if err := c.composerPostInstall(); err != nil { - return errors.Wrap(err, "running composer post install configuration") - } + if err := c.composerInstall(); err != nil { + return errors.Wrap(err, "installing composer") } - if err := c.installMagento1GenerateLocalXML(); err != nil { + if err := c.generateLocalXML(); err != nil { return err } - if err := c.installMagento1ConfigureBasic(); err != nil { + if err := c.configureBasicSettings(); err != nil { return err } - adminPassword, err := c.installMagento1ConfigureAdminUser() + adminPassword, err := c.configureAdminUser() if err != nil { return err } - if err := c.installMagento1FlushCache(); err != nil { + if err := c.flushCache(); err != nil { return err } @@ -74,7 +62,27 @@ func (c *bootstrapper) bootstrapMagento1() error { return nil } -func (c *bootstrapper) installMagento1GenerateLocalXML() error { +func (c *magento1) composerInstall() error { + if !util.FileExists(filepath.Join(c.Cwd(), c.WebRoot(), "composer.json")) { + return nil + } + + if err := c.composerPreInstall(); err != nil { + return errors.Wrap(err, "configuring composer") + } + + if err := c.bootstrapper.composerInstall(); err != nil { + return errors.Wrap(err, "running composer install") + } + + if err := c.composerPostInstall(); err != nil { + return errors.Wrap(err, "running composer post install configuration") + } + + return nil +} + +func (c *magento1) generateLocalXML() error { log.Println("Generating local.xml...") var ( @@ -88,9 +96,9 @@ func (c *bootstrapper) installMagento1GenerateLocalXML() error { return errors.New("cannot create magento local.xml file") } - if err := templates.New().AppendTemplatesFromPathsStatic(localXMLTemplate, tmpList, []string{ - filepath.Join("templates", "magento1", "local.xml"), - }); err != nil { + if err := templates.New().AppendTemplatesFromPathsStatic( + localXMLTemplate, tmpList, []string{filepath.Join("templates", "magento1", "local.xml")}, + ); err != nil { return errors.Wrap(err, "loading magento local.xml template") } @@ -111,32 +119,26 @@ func (c *bootstrapper) installMagento1GenerateLocalXML() error { return nil } -func (c *bootstrapper) installMagento1ConfigureBasic() error { +func (c *magento1) configureBasicSettings() error { log.Println("Configuring Magento basic settings...") - if err := c.RunCmdEnvExec( - fmt.Sprintf( - "n98-magerun config:set web/unsecure/base_url http://%s/", - c.TraefikFullDomain(), - ), - ); err != nil { + command := fmt.Sprintf("%s config:set web/unsecure/base_url http://%s/", c.magerunCommand(), c.TraefikFullDomain()) + if err := c.RunCmdEnvExec(command); err != nil { return errors.Wrap(err, "setting magento base url") } - if err := c.RunCmdEnvExec( - fmt.Sprintf( - "n98-magerun config:set web/secure/base_url https://%s/", - c.TraefikFullDomain(), - ), - ); err != nil { + command = fmt.Sprintf("%s config:set web/secure/base_url https://%s/", c.magerunCommand(), c.TraefikFullDomain()) + if err := c.RunCmdEnvExec(command); err != nil { return errors.Wrap(err, "setting magento secure base url") } - if err := c.RunCmdEnvExec("n98-magerun config:set web/secure/use_in_frontend 1"); err != nil { + command = fmt.Sprintf("%s config:set web/secure/use_in_frontend 1", c.magerunCommand()) + if err := c.RunCmdEnvExec(command); err != nil { return errors.Wrap(err, "setting magento to use https on frontend") } - if err := c.RunCmdEnvExec("n98-magerun config:set web/secure/use_in_adminhtml 1"); err != nil { + command = fmt.Sprintf("%s config:set web/secure/use_in_adminhtml 1", c.magerunCommand()) + if err := c.RunCmdEnvExec(command); err != nil { return errors.Wrap(err, "setting magento to use https on admin") } @@ -145,20 +147,17 @@ func (c *bootstrapper) installMagento1ConfigureBasic() error { return nil } -func (c *bootstrapper) installMagento1ConfigureAdminUser() (string, error) { +func (c *magento1) configureAdminUser() (string, error) { log.Println("Creating admin user...") - adminPassword, err := password.Generate(16, 2, 0, false, false) - if err != nil { - return "", errors.Wrap(err, "generating magento admin password") - } + adminPassword := c.generatePassword() - if err := c.RunCmdEnvExec( - fmt.Sprintf( - "n98-magerun admin:user:create localadmin admin@example.com %s Local Admin", - adminPassword, - ), - ); err != nil { + command := fmt.Sprintf( + "%s admin:user:create localadmin admin@example.com %s Local Admin", + c.magerunCommand(), + adminPassword, + ) + if err := c.RunCmdEnvExec(command); err != nil { return "", errors.Wrap(err, "creating magento admin user") } @@ -167,10 +166,11 @@ func (c *bootstrapper) installMagento1ConfigureAdminUser() (string, error) { return adminPassword, nil } -func (c *bootstrapper) installMagento1FlushCache() error { +func (c *magento1) flushCache() error { log.Println("Flushing cache...") - if err := c.RunCmdEnvExec("n98-magerun cache:flush"); err != nil { + command := fmt.Sprintf("%s cache:flush", c.magerunCommand()) + if err := c.RunCmdEnvExec(command); err != nil { return errors.Wrap(err, "flushing magento cache") } @@ -178,3 +178,7 @@ func (c *bootstrapper) installMagento1FlushCache() error { return nil } + +func (c *magento1) magerunCommand() string { + return "n98-magerun" +} diff --git a/internal/logic/bootstrapMagento2.go b/internal/logic/bootstrapMagento2.go index 36b7a72a..41217f06 100644 --- a/internal/logic/bootstrapMagento2.go +++ b/internal/logic/bootstrapMagento2.go @@ -2,28 +2,28 @@ package logic import ( "fmt" + "path/filepath" "strings" "github.com/hashicorp/go-version" "github.com/pkg/errors" - "github.com/sethvargo/go-password/password" log "github.com/sirupsen/logrus" "github.com/rewardenv/reward/pkg/util" ) -// bootstrapMagento2 runs a full Magento 2 bootstrap process. -func (c *bootstrapper) bootstrapMagento2() error { - if !util.AskForConfirmation( - fmt.Sprintf( - "Would you like to bootstrap Magento v%s?", - c.magento2Version().String(), - ), - ) { +// bootstrap runs a full Magento 2 bootstrap process. +func (c *magento2) bootstrap() error { + m2versionString := c.semver().String() + if m2versionString == "0.0.0+undefined" { + m2versionString = "from existing composer.json" + } + + if !util.AskForConfirmation(fmt.Sprintf("Would you like to bootstrap Magento %s?", m2versionString)) { return nil } - log.Printf("Bootstrapping Magento %s...", c.magento2Version().String()) + log.Printf("Bootstrapping Magento %s...", m2versionString) if err := c.prepare(); err != nil { return errors.Wrap(err, "running preparation") @@ -46,7 +46,7 @@ func (c *bootstrapper) bootstrapMagento2() error { return errors.Wrap(err, "running composer post install configuration") } - adminPassword, err := c.installMagento2(freshInstall) + adminPassword, err := c.install(freshInstall) if err != nil { return errors.Wrap(err, "installing magento 2") } @@ -60,7 +60,7 @@ func (c *bootstrapper) bootstrapMagento2() error { return nil } -func (c *bootstrapper) magento2Version() *version.Version { +func (c *magento2) version() *version.Version { v, err := c.MagentoVersion() if err != nil { log.Panicln(err) @@ -69,67 +69,97 @@ func (c *bootstrapper) magento2Version() *version.Version { return v } -func (c *bootstrapper) magento2SemVer() *version.Version { - v := c.magento2Version() +func (c *magento2) semver() *version.Version { + v := c.version() return util.ConvertVersionPrereleaseToMetadata(v) } -func (c *bootstrapper) magento2VerbosityFlag() string { - magentoVerbosityFlag := "-v" +func (c *magento2) download() (downloaded bool, err error) { + if c.SkipComposerInstall() { + return false, nil + } - if c.IsDebug() { - magentoVerbosityFlag += "vv" + if util.FileExists(filepath.Join(c.Cwd(), c.WebRoot(), "composer.json")) { + return false, nil } - return magentoVerbosityFlag + log.Println("Creating Magento 2 composer project...") + + magentoVersion, err := c.MagentoVersion() + if err != nil { + return false, errors.Wrap(err, "determining magento version") + } + + command := fmt.Sprintf("%s create-project --profile --no-install "+ + "--repository-url=https://repo.magento.com/ "+ + "magento/project-%s-edition=%s /tmp/magento-tmp/", + c.composerCommand(), + c.MagentoType(), + magentoVersion.String(), + ) + if err = c.RunCmdEnvExec(command); err != nil { + return false, errors.Wrap(err, "creating composer magento project") + } + + command = fmt.Sprintf( + `%s -au --remove-source-files --chmod=D2775,F644 /tmp/magento-tmp/ /var/www/html/`, + c.rsyncCommand(), + ) + if err = c.RunCmdEnvExec(command); err != nil { + return false, errors.Wrap(err, "moving magento project install files") + } + + log.Println("...Magento 2 composer project created.") + + return true, nil } -func (c *bootstrapper) installMagento2(freshInstall bool) (string, error) { +func (c *magento2) install(freshInstall bool) (string, error) { log.Println("Installing Magento...") - if err := c.installMagento2SetupInstall(); err != nil { + if err := c.setupInstall(); err != nil { return "", err } - if err := c.installMagento2ConfigureBasic(); err != nil { + if err := c.configureBasicSettings(); err != nil { return "", err } - if err := c.installMagento2ConfigureVarnish(); err != nil { + if err := c.configureVarnish(); err != nil { return "", err } - if err := c.installMagento2ConfigureSearch(); err != nil { + if err := c.configureSearch(); err != nil { return "", err } - if err := c.installMagento2ConfigureDeployMode(); err != nil { + if err := c.configureDeployMode(); err != nil { return "", err } - if err := c.installMagento2ConfigureTFA(); err != nil { + if err := c.disableTFA(); err != nil { return "", err } - adminPassword, err := c.installMagento2ConfigureAdminUser() + adminPassword, err := c.configureAdminUser() if err != nil { return "", err } - if err := c.installMagento2DeploySampleData(freshInstall); err != nil { + if err := c.deploySampleData(freshInstall); err != nil { return "", err } - if err := c.installMagento2Reindex(); err != nil { + if err := c.reindex(); err != nil { return "", err } - if err := c.installMagento2ResetAdminURL(); err != nil { + if err := c.resetAdminURL(); err != nil { return "", err } - if err := c.installMagento2FlushCache(); err != nil { + if err := c.flushCache(); err != nil { return "", err } @@ -138,15 +168,11 @@ func (c *bootstrapper) installMagento2(freshInstall bool) (string, error) { return adminPassword, nil } -func (c *bootstrapper) installMagento2SetupInstall() error { +func (c *magento2) setupInstall() error { log.Println("Running Magento setup:install...") - if err := c.RunCmdEnvExec( - fmt.Sprintf( - "bin/magento setup:install %s", - strings.Join(c.buildMagento2InstallCommand(), " "), - ), - ); err != nil { + command := fmt.Sprintf("%s setup:install %s", c.magentoCommand(), c.setupInstallArgs()) + if err := c.RunCmdEnvExec(command); err != nil { return errors.Wrap(err, "running bin/magento setup:install") } @@ -155,15 +181,11 @@ func (c *bootstrapper) installMagento2SetupInstall() error { return nil } -func (c *bootstrapper) installMagento2ConfigureDeployMode() error { +func (c *magento2) configureDeployMode() error { log.Println("Setting Magento deploy mode...") - if err := c.RunCmdEnvExec( - fmt.Sprintf( - "bin/magento deploy:mode:set -s %s", - c.MagentoMode(), - ), - ); err != nil { + command := fmt.Sprintf("%s deploy:mode:set -s %s", c.magentoCommand(), c.MagentoMode()) + if err := c.RunCmdEnvExec(command); err != nil { return errors.Wrap(err, "running bin/magento deploy:mode:set") } @@ -172,10 +194,11 @@ func (c *bootstrapper) installMagento2ConfigureDeployMode() error { return nil } -func (c *bootstrapper) installMagento2FlushCache() error { +func (c *magento2) flushCache() error { log.Println("Flushing cache...") - if err := c.RunCmdEnvExec("bin/magento cache:flush"); err != nil { + command := fmt.Sprintf("%s cache:flush", c.magentoCommand()) + if err := c.RunCmdEnvExec(command); err != nil { return errors.Wrap(err, "running bin/magento cache:flush") } @@ -184,53 +207,57 @@ func (c *bootstrapper) installMagento2FlushCache() error { return nil } -func (c *bootstrapper) installMagento2ResetAdminURL() error { - if c.ResetAdminURL() { - log.Println("Resetting admin URL...") +func (c *magento2) resetAdminURL() error { + if !c.ResetAdminURL() { + return nil + } - if err := c.RunCmdEnvExec("bin/magento config:set admin/url/use_custom 0"); err != nil { - return errors.Wrap(err, "resetting admin url") - } + log.Println("Resetting admin URL...") - if err := c.RunCmdEnvExec("bin/magento config:set admin/url/use_custom_path 0"); err != nil { - return errors.Wrap(err, "resetting admin url path") - } + command := fmt.Sprintf("%s config:set admin/url/use_custom 0", c.magentoCommand()) + if err := c.RunCmdEnvExec(command); err != nil { + return errors.Wrap(err, "resetting admin url") + } - log.Println("...admin URL reset.") + command = fmt.Sprintf("%s config:set admin/url/use_custom_path 0", c.magentoCommand()) + if err := c.RunCmdEnvExec(command); err != nil { + return errors.Wrap(err, "resetting admin url path") } + log.Println("...admin URL reset.") + return nil } -func (c *bootstrapper) installMagento2Reindex() error { - if c.FullBootstrap() { - log.Println("Reindexing...") +func (c *magento2) reindex() error { + if !c.FullBootstrap() { + return nil + } - if err := c.RunCmdEnvExec("bin/magento indexer:reindex"); err != nil { - return errors.Wrap(err, "running bin/magento indexer:reindex") - } + log.Println("Reindexing...") - log.Println("...reindexing complete.") + command := fmt.Sprintf("%s indexer:reindex", c.magentoCommand()) + if err := c.RunCmdEnvExec(command); err != nil { + return errors.Wrap(err, "running bin/magento indexer:reindex") } + log.Println("...reindexing complete.") + return nil } -func (c *bootstrapper) installMagento2ConfigureAdminUser() (string, error) { +func (c *magento2) configureAdminUser() (string, error) { log.Println("Creating admin user...") - adminPassword, err := password.Generate(16, 2, 0, false, false) - if err != nil { - return "", errors.Wrap(err, "generating admin password") - } + adminPassword := c.generatePassword() - if err := c.RunCmdEnvExec( - fmt.Sprintf( - `bin/magento admin:user:create --admin-password=%s `+ - `--admin-user=localadmin --admin-firstname=Local --admin-lastname=Admin --admin-email="admin@example.com"`, - adminPassword, - ), - ); err != nil { + command := fmt.Sprintf(`%s admin:user:create --admin-password=%s `+ + `--admin-user=localadmin --admin-firstname=Local `+ + `--admin-lastname=Admin --admin-email="admin@example.com"`, + c.magentoCommand(), + adminPassword, + ) + if err := c.RunCmdEnvExec(command); err != nil { return "", errors.Wrap(err, "creating admin user") } @@ -239,232 +266,257 @@ func (c *bootstrapper) installMagento2ConfigureAdminUser() (string, error) { return adminPassword, nil } -func (c *bootstrapper) installMagento2ConfigureTFA() error { - mfaConstraints := version.MustConstraints(version.NewConstraint(">=2.4")) - // For Magento 2.4.6 and above, we need to disable the Adobe IMS module as well - adobeImsConstraints := version.MustConstraints(version.NewConstraint(">=2.4.6")) +func (c *magento2) disableTFA() error { + if !c.MagentoDisableTFA() { + return nil + } - if mfaConstraints.Check(c.magento2SemVer()) && c.MagentoDisableTFA() { - log.Println("Disabling TFA for local development...") + force := false - modules := "Magento_TwoFactorAuth" - if adobeImsConstraints.Check(c.magento2SemVer()) { - modules = "{Magento_AdminAdobeImsTwoFactorAuth,Magento_TwoFactorAuth}" + if c.semver().String() == "0.0.0+undefined" { + if !util.AskForConfirmation("Magento version cannot be determined. Would you like to disable TFA?") { + return nil } + force = true + } - if err := c.RunCmdEnvExec("bin/magento module:disable " + modules); err != nil { - return errors.Wrapf(err, "running bin/magento module:disable %v", modules) - } + mfaConstraints := version.MustConstraints(version.NewConstraint(">=2.4")) + if !(force || mfaConstraints.Check(c.semver())) { + return nil + } + + log.Println("Disabling TFA for local development...") - log.Println("...TFA disabled.") + modules := c.tfaModules() + + command := fmt.Sprintf("%s module:disable %s", c.magentoCommand(), modules) + if err := c.RunCmdEnvExec(command); err != nil { + return errors.Wrapf(err, "running bin/magento module:disable %v", modules) } + log.Println("...TFA disabled.") + return nil } -func (c *bootstrapper) installMagento2DeploySampleData(freshInstall bool) error { - if freshInstall && (c.WithSampleData() || c.FullBootstrap()) { - log.Println("Installing sample data...") - - if err := c.RunCmdEnvExec( - "mkdir -p /var/www/html/var/composer_home/ && " + - "cp -va ~/.composer/auth.json /var/www/html/var/composer_home/auth.json", - ); err != nil { - return errors.Wrap(err, "copying auth.json") +func (c *magento2) tfaModules() string { + // For Magento 2.4.6 and above, we need to disable the Adobe IMS module as well + if c.semver().String() == "0.0.0+undefined" { + if util.AskForConfirmation("Magento version cannot be determined. " + + "Would you like to disable Adobe IMS module (this is usually required for Magento >=2.4.6)?", + ) { + return "{Magento_AdminAdobeImsTwoFactorAuth,Magento_TwoFactorAuth}" } + } - if err := c.RunCmdEnvExec( - fmt.Sprintf( - `php bin/magento %s sampledata:deploy`, - c.magento2VerbosityFlag(), - ), - ); err != nil { - return errors.Wrap(err, "running bin/magento sampledata:deploy") - } + adobeImsConstraints := version.MustConstraints(version.NewConstraint(">=2.4.6")) + if adobeImsConstraints.Check(c.semver()) { + return "{Magento_AdminAdobeImsTwoFactorAuth,Magento_TwoFactorAuth}" + } - if err := c.RunCmdEnvExec( - fmt.Sprintf( - `bin/magento setup:upgrade %s`, - c.magento2VerbosityFlag(), - ), - ); err != nil { - return errors.Wrap(err, "running bin/magento setup:upgrade") - } + return "Magento_TwoFactorAuth" +} + +func (c *magento2) deploySampleData(freshInstall bool) error { + if !(freshInstall && (c.WithSampleData() || c.FullBootstrap())) { + return nil + } + + log.Println("Installing sample data...") + + command := `mkdir -p /var/www/html/var/composer_home/ && ` + + `cp -va ~/.composer/auth.json /var/www/html/var/composer_home/auth.json` - log.Println("...sample data installed successfully.") + if err := c.RunCmdEnvExec(command); err != nil { + return errors.Wrap(err, "copying auth.json") } + command = fmt.Sprintf(`%s sampledata:deploy`, c.magentoCommand()) + if err := c.RunCmdEnvExec(command); err != nil { + return errors.Wrap(err, "running bin/magento sampledata:deploy") + } + + command = fmt.Sprintf(`%s setup:upgrade`, c.magentoCommand()) + if err := c.RunCmdEnvExec(command); err != nil { + return errors.Wrap(err, "running bin/magento setup:upgrade") + } + + log.Println("...sample data installed successfully.") + return nil } -func (c *bootstrapper) installMagento2ConfigureSearch() error { +func (c *magento2) configureSearch() error { + if !c.ServiceEnabled("elasticsearch") && !c.ServiceEnabled("opensearch") { + return nil + } + + log.Println("Configuring Elasticsearch/OpenSearch...") + + command := c.magentoCommand() + " config:set --lock-env catalog/search/enable_eav_indexer 1" + if err := c.RunCmdEnvExec(command); err != nil { + return errors.Wrap(err, "enabling eav indexer") + } + + searchHost, searchEngine := c.magentoSearchHost() + force := false + + if c.semver().String() == "0.0.0+undefined" { + if util.AskForConfirmation("Magento version cannot be determined. " + + "Would you like to disable Adobe IMS module (this is usually required for Magento >=2.4.6)?", + ) { + force = true + } + } + + enabled := false if c.ServiceEnabled("elasticsearch") || c.ServiceEnabled("opensearch") { - log.Println("Configuring Elasticsearch/OpenSearch...") + enabled = true + } + + // Above Magento 2.4 the search engine must be configured + constraints := version.MustConstraints(version.NewConstraint(">=2.4")) + if !(force || enabled || constraints.Check(c.semver())) { + return nil + } + + command = fmt.Sprintf("%s config:set --lock-env catalog/search/engine %s", c.magentoCommand(), searchEngine) + if err := c.RunCmdEnvExec(command); err != nil { + return errors.Wrap(err, "setting magento search engine") + } + + command = fmt.Sprintf("%s config:set --lock-env catalog/search/%s_server_hostname %s", + c.magentoCommand(), + searchEngine, + searchHost, + ) + if err := c.RunCmdEnvExec(command); err != nil { + return errors.Wrap(err, "setting magento search engine server") + } + + command = fmt.Sprintf("%s config:set --lock-env catalog/search/%s_server_port 9200", + c.magentoCommand(), + searchEngine, + ) + if err := c.RunCmdEnvExec(command); err != nil { + return errors.Wrap(err, "setting magento search engine port") + } - if err := c.RunCmdEnvExec("bin/magento config:set --lock-env catalog/search/enable_eav_indexer 1"); err != nil { - return errors.Wrap(err, "enabling eav indexer") + command = fmt.Sprintf("%s config:set --lock-env catalog/search/%s_index_prefix magento2", + c.magentoCommand(), + searchEngine, + ) + if err := c.RunCmdEnvExec(command); err != nil { + return errors.Wrap(err, "setting magento search engine index prefix") + } + + // Enable auth if OpenSearch is enabled and version is 2.12.0 or above + openSearchInitialAdminPassword := c.GetString("OPENSEARCH_INITIAL_ADMIN_PASSWORD") + if openSearchInitialAdminPassword != "" { + command = fmt.Sprintf("%s config:set --lock-env catalog/search/%s_enable_auth 1", + c.magentoCommand(), + searchEngine, + ) + if err := c.RunCmdEnvExec(command); err != nil { + return errors.Wrap(err, "disabling magento search engine auth") } - searchHost, searchEngine := c.buildMagentoSearchHost() + command = fmt.Sprintf("%s config:set --lock-env catalog/search/%s_username admin", + c.magentoCommand(), + searchEngine, + ) + if err := c.RunCmdEnvExec(command); err != nil { + return errors.Wrap(err, "disabling magento search engine auth") + } - // Above Magento 2.4 the search engine must be configured - constraints := version.MustConstraints(version.NewConstraint(">=2.4")) - if constraints.Check(c.magento2SemVer()) { - if err := c.RunCmdEnvExec( - fmt.Sprintf( - "bin/magento config:set --lock-env catalog/search/engine %s", - searchEngine, - ), - ); err != nil { - return errors.Wrap(err, "setting magento search engine") - } - - if err := c.RunCmdEnvExec( - fmt.Sprintf( - "bin/magento config:set --lock-env catalog/search/%s_server_hostname %s", - searchEngine, - searchHost, - ), - ); err != nil { - return errors.Wrap(err, "setting magento search engine server") - } - - if err := c.RunCmdEnvExec( - fmt.Sprintf( - "bin/magento config:set --lock-env catalog/search/%s_server_port 9200", - searchEngine, - ), - ); err != nil { - return errors.Wrap(err, "setting magento search engine port") - } - - if err := c.RunCmdEnvExec( - fmt.Sprintf( - "bin/magento config:set --lock-env catalog/search/%s_index_prefix magento2", - searchEngine, - ), - ); err != nil { - return errors.Wrap(err, "setting magento search engine index prefix") - } - - // Enable auth if OpenSearch is enabled and version is 2.12.0 or above - openSearchInitialAdminPassword := c.GetString("OPENSEARCH_INITIAL_ADMIN_PASSWORD") - if openSearchInitialAdminPassword != "" { - if err := c.RunCmdEnvExec( - fmt.Sprintf( - "bin/magento config:set --lock-env catalog/search/%s_enable_auth 1", - searchEngine, - ), - ); err != nil { - return errors.Wrap(err, "disabling magento search engine auth") - } - - if err := c.RunCmdEnvExec( - fmt.Sprintf( - "bin/magento config:set --lock-env catalog/search/%s_username admin", - searchEngine, - ), - ); err != nil { - return errors.Wrap(err, "disabling magento search engine auth") - } - - if err := c.RunCmdEnvExec( - fmt.Sprintf( - "bin/magento config:set --lock-env catalog/search/%s_password %s", - searchEngine, - openSearchInitialAdminPassword, - ), - ); err != nil { - return errors.Wrap(err, "disabling magento search engine auth") - } - } else { - if err := c.RunCmdEnvExec( - fmt.Sprintf( - "bin/magento config:set --lock-env catalog/search/%s_enable_auth 0", - searchEngine, - ), - ); err != nil { - return errors.Wrap(err, "disabling magento search engine auth") - } - } - - if err := c.RunCmdEnvExec( - fmt.Sprintf( - "bin/magento config:set --lock-env catalog/search/%s_server_timeout 15", - searchEngine, - ), - ); err != nil { - return errors.Wrap(err, "setting magento search engine timeout") - } + command = fmt.Sprintf("%s config:set --lock-env catalog/search/%s_password %s", + c.magentoCommand(), + searchEngine, + openSearchInitialAdminPassword, + ) + if err := c.RunCmdEnvExec(command); err != nil { + return errors.Wrap(err, "disabling magento search engine auth") } + } else { + command = fmt.Sprintf("%s config:set --lock-env catalog/search/%s_enable_auth 0", + c.magentoCommand(), + searchEngine, + ) + if err := c.RunCmdEnvExec(command); err != nil { + return errors.Wrap(err, "disabling magento search engine auth") + } + } - log.Println("...Elasticsearch/Opensearch configured.") + command = fmt.Sprintf("%s config:set --lock-env catalog/search/%s_server_timeout 15", + c.magentoCommand(), + searchEngine, + ) + if err := c.RunCmdEnvExec(command); err != nil { + return errors.Wrap(err, "setting magento search engine timeout") } + log.Println("...Elasticsearch/Opensearch configured.") + return nil } -func (c *Client) installMagento2ConfigureVarnish() error { - if c.ServiceEnabled("varnish") { - log.Println("Configuring Varnish...") +func (c *magento2) configureVarnish() error { + if !c.ServiceEnabled("varnish") { + return nil + } - if err := c.RunCmdEnvExec( - "bin/magento config:set --lock-env system/full_page_cache/caching_application 2", - ); err != nil { - return errors.Wrap(err, "configuring magento varnish") - } + log.Println("Configuring Varnish...") - if err := c.RunCmdEnvExec("bin/magento config:set --lock-env system/full_page_cache/ttl 604800"); err != nil { - return errors.Wrap(err, "configuring magento varnish cache ttl") - } + command := fmt.Sprintf("%s config:set --lock-env system/full_page_cache/caching_application 2", c.magentoCommand()) + if err := c.RunCmdEnvExec(command); err != nil { + return errors.Wrap(err, "configuring magento varnish") + } - log.Println("...Varnish configured.") + command = fmt.Sprintf("%s config:set --lock-env system/full_page_cache/ttl 604800", c.magentoCommand()) + if err := c.RunCmdEnvExec(command); err != nil { + return errors.Wrap(err, "configuring magento varnish cache ttl") } + log.Println("...Varnish configured.") + return nil } -func (c *bootstrapper) installMagento2ConfigureBasic() error { +func (c *magento2) configureBasicSettings() error { log.Println("Configuring Magento basic settings...") - if err := c.RunCmdEnvExec( - fmt.Sprintf( - "bin/magento config:set web/unsecure/base_url http://%s/", - c.TraefikFullDomain(), - ), - ); err != nil { + command := fmt.Sprintf("%s config:set web/unsecure/base_url http://%s/", c.magentoCommand(), c.TraefikFullDomain()) + if err := c.RunCmdEnvExec(command); err != nil { return errors.Wrap(err, "setting magento base URL") } // Set secure base URL - if err := c.RunCmdEnvExec( - fmt.Sprintf( - "bin/magento config:set web/secure/base_url https://%s/", - c.TraefikFullDomain(), - ), - ); err != nil { + command = fmt.Sprintf("%s config:set web/secure/base_url https://%s/", c.magentoCommand(), c.TraefikFullDomain()) + if err := c.RunCmdEnvExec(command); err != nil { return errors.Wrap(err, "setting magento secure base URL") } // Set offload header - if err := c.RunCmdEnvExec( - "bin/magento config:set --lock-env web/secure/offloader_header X-Forwarded-Proto", - ); err != nil { + command = fmt.Sprintf("%s config:set --lock-env web/secure/offloader_header X-Forwarded-Proto", c.magentoCommand()) + if err := c.RunCmdEnvExec(command); err != nil { return errors.Wrap(err, "setting magento offload header") } // Set use https in frontend - if err := c.RunCmdEnvExec("bin/magento config:set web/secure/use_in_frontend 1"); err != nil { + command = fmt.Sprintf("%s config:set web/secure/use_in_frontend 1", c.magentoCommand()) + if err := c.RunCmdEnvExec(command); err != nil { return errors.Wrap(err, "setting magento use https on frontend") } // Set use https in admin - if err := c.RunCmdEnvExec("bin/magento config:set web/secure/use_in_adminhtml 1"); err != nil { + command = fmt.Sprintf("%s config:set web/secure/use_in_adminhtml 1", c.magentoCommand()) + if err := c.RunCmdEnvExec(command); err != nil { return errors.Wrap(err, "setting magento use https on admin") } // Set seo rewrites - if err := c.RunCmdEnvExec("bin/magento config:set web/seo/use_rewrites 1"); err != nil { + command = fmt.Sprintf("%s config:set web/seo/use_rewrites 1", c.magentoCommand()) + if err := c.RunCmdEnvExec(command); err != nil { return errors.Wrap(err, "setting magento seo rewrites") } @@ -473,7 +525,7 @@ func (c *bootstrapper) installMagento2ConfigureBasic() error { return nil } -func (c *bootstrapper) buildMagento2InstallCommand() []string { +func (c *magento2) setupInstallArgs() string { magentoCmdParams := []string{ "--backend-frontname=" + c.MagentoBackendFrontname(), "--db-host=db", @@ -529,12 +581,12 @@ func (c *bootstrapper) buildMagento2InstallCommand() []string { // --consumers-wait-for-messages option is only available above Magento 2.4 constraints := version.MustConstraints(version.NewConstraint(">=2.4")) - if constraints.Check(c.magento2SemVer()) { + if constraints.Check(c.semver()) { magentoCmdParams = append(magentoCmdParams, "--consumers-wait-for-messages=0") } } - searchHost, searchEngine := c.buildMagentoSearchHost() + searchHost, searchEngine := c.magentoSearchHost() searchEngineFlag := "opensearch" if strings.HasPrefix(searchEngine, "elasticsearch") { @@ -542,7 +594,7 @@ func (c *bootstrapper) buildMagento2InstallCommand() []string { } constraints := version.MustConstraints(version.NewConstraint(">=2.4")) - if c.ServiceEnabled("elasticsearch") || c.ServiceEnabled("opensearch") && constraints.Check(c.magento2SemVer()) { + if c.ServiceEnabled("elasticsearch") || c.ServiceEnabled("opensearch") && constraints.Check(c.semver()) { magentoCmdParams = append( magentoCmdParams, fmt.Sprintf("--search-engine=%s", searchEngine), @@ -554,10 +606,10 @@ func (c *bootstrapper) buildMagento2InstallCommand() []string { ) } - return magentoCmdParams + return strings.Join(magentoCmdParams, " ") } -func (c *bootstrapper) buildMagentoSearchHost() (string, string) { +func (c *magento2) magentoSearchHost() (string, string) { // Elasticsearch/OpenSearch configuration searchHost, searchEngine := "", "" @@ -568,7 +620,7 @@ func (c *bootstrapper) buildMagentoSearchHost() (string, string) { // Need to specify elasticsearch7 for opensearch as Magento 2.4.6 and below // https://devdocs.magento.com/guides/v2.4/install-gde/install/cli/install-cli.html constraints := version.MustConstraints(version.NewConstraint(">=2.4.7")) - if constraints.Check(c.magento2SemVer()) { + if constraints.Check(c.semver()) { log.Println("Setting search engine to openSearch") searchEngine = "opensearch" } else { @@ -590,3 +642,13 @@ func (c *bootstrapper) buildMagentoSearchHost() (string, string) { return searchHost, searchEngine } + +func (c *magento2) magentoCommand() string { + verbosity := "-v" + + if c.IsDebug() { + verbosity += "vv" + } + + return fmt.Sprintf("php bin/magento %s", verbosity) +} diff --git a/internal/logic/bootstrapShopware.go b/internal/logic/bootstrapShopware.go index 5bb0d4d6..72f77bb0 100644 --- a/internal/logic/bootstrapShopware.go +++ b/internal/logic/bootstrapShopware.go @@ -8,22 +8,24 @@ import ( "path/filepath" "text/template" + "github.com/hashicorp/go-version" "github.com/pkg/errors" - "github.com/sethvargo/go-password/password" log "github.com/sirupsen/logrus" "github.com/rewardenv/reward/internal/templates" "github.com/rewardenv/reward/pkg/util" ) -func (c *bootstrapper) bootstrapShopware() error { +func (c *shopware) bootstrap() error { shopwareVersion, err := c.ShopwareVersion() if err != nil { return errors.Wrap(err, "determining shopware version") } if !util.AskForConfirmation(fmt.Sprintf("Would you like to bootstrap Shopware v%s?", - shopwareVersion.String())) { + shopwareVersion.String(), + ), + ) { return nil } @@ -54,7 +56,7 @@ func (c *bootstrapper) bootstrapShopware() error { return err } - adminPassword, err := c.installShopware(freshInstall) + adminPassword, err := c.install(freshInstall) if err != nil { return err } @@ -68,47 +70,91 @@ func (c *bootstrapper) bootstrapShopware() error { return nil } -func (c *bootstrapper) installShopware(freshInstall bool) (string, error) { +func (c *shopware) download() (downloaded bool, err error) { + if c.SkipComposerInstall() { + return false, nil + } + + if util.FileExists(filepath.Join(c.Cwd(), c.WebRoot(), "composer.json")) { + return false, nil + } + + log.Println("Downloading and installing Shopware...") + + path := "production" if c.ShopwareMode() == "dev" || c.ShopwareMode() == "development" { - if err := c.installShopwareDevConfig(); err != nil { + path = "development" + } + + command := fmt.Sprintf("wget -qO /tmp/shopware.tar.gz https://github.com/shopware/%s/archive/refs/tags/v%s.tar.gz", + path, + version.Must(c.ShopwareVersion()).String(), + ) + if err := c.RunCmdEnvExec(command); err != nil { + return false, errors.Wrap(err, "downloading shopware") + } + + command = "tar -zxf /tmp/shopware.tar.gz --strip-components=1 -C /var/www/html" + if err := c.RunCmdEnvExec(command); err != nil { + return false, errors.Wrap(err, "extracting shopware") + } + + command = "rm -f /tmp/shopware.tar.gz" + if err := c.RunCmdEnvExec(command); err != nil { + return false, errors.Wrap(err, "removing shopware archive") + } + + log.Println("...Shopware downloaded.") + + return true, nil +} + +func (c *shopware) install(freshInstall bool) (string, error) { + if c.ShopwareMode() == "dev" || c.ShopwareMode() == "development" { + if err := c.devConfig(); err != nil { return "", err } - if err := c.installShopwareDevSetup(); err != nil { + if err := c.devSetup(); err != nil { return "", err } } else { - if err := c.installShopwareProdSetup(freshInstall); err != nil { + if err := c.prodSetup(freshInstall); err != nil { return "", err } - if err := c.installShopwareDemoData(freshInstall); err != nil { + if err := c.deployDemoData(freshInstall); err != nil { return "", err } } - adminPassword, err := c.installShopwareConfigureAdminUser() + adminPassword, err := c.configureAdminUser() if err != nil { return "", err } - if err := c.installShopwareClearCache(); err != nil { + if err := c.clearCache(); err != nil { return "", err } return adminPassword, nil } -func (c *bootstrapper) installShopwareDemoData(freshInstall bool) error { +func (c *shopware) deployDemoData(freshInstall bool) error { + if !(freshInstall && (c.WithSampleData() || c.FullBootstrap())) { + return nil + } + log.Println("Deploying Shopware demo data...") - if freshInstall && (c.WithSampleData() || c.FullBootstrap()) { - if err := c.RunCmdEnvExec("mkdir -p custom/plugins && " + - "php bin/console store:download -p SwagPlatformDemoData && " + - "php bin/console plugin:install SwagPlatformDemoData --activate", - ); err != nil { - return errors.Wrap(err, "installing demo data") - } + command := fmt.Sprintf("mkdir -p custom/plugins && "+ + "%s store:download -p SwagPlatformDemoData && "+ + "%s plugin:install SwagPlatformDemoData --activate", + c.consoleCommand(), c.consoleCommand(), + ) + + if err := c.RunCmdEnvExec(command); err != nil { + return errors.Wrap(err, "installing demo data") } log.Println("...demo data deployed.") @@ -116,33 +162,33 @@ func (c *bootstrapper) installShopwareDemoData(freshInstall bool) error { return nil } -func (c *bootstrapper) installShopwareProdSetup(freshInstall bool) error { +func (c *shopware) prodSetup(freshInstall bool) error { log.Println("Setting up Shopware production template...") - searchEnabled, searchHost := c.installShopwareConfigureSearch() - - if err := c.RunCmdEnvExec( - fmt.Sprintf( - "bin/console system:setup "+ - "--no-interaction --force "+ - "--app-env dev --app-url https://%s "+ - "--database-url mysql://app:app@db:3306/shopware "+ - "--es-enabled=%d --es-hosts=%s --es-indexing-enabled=%d "+ - "--cdn-strategy=physical_filename "+ - "--mailer-url=native://default", - c.TraefikFullDomain(), - searchEnabled, - searchHost, - searchEnabled, - ), - ); err != nil { + searchEnabled, searchHost := c.configureSearch() + + command := fmt.Sprintf( + "%s system:setup "+ + "--no-interaction --force "+ + "--app-env dev --app-url https://%s "+ + "--database-url mysql://app:app@db:3306/shopware "+ + "--es-enabled=%d --es-hosts=%s --es-indexing-enabled=%d "+ + "--cdn-strategy=physical_filename "+ + "--mailer-url=native://default", + c.consoleCommand(), + c.TraefikFullDomain(), + searchEnabled, + searchHost, + searchEnabled, + ) + + if err := c.RunCmdEnvExec(command); err != nil { return errors.Wrap(err, "running shopware system:setup") } // Add LOCK_DSN to .env - if err := c.RunCmdEnvExec( - `echo 'LOCK_DSN="flock://var/lock"' >> .env`, - ); err != nil { + command = `echo 'LOCK_DSN="flock://var/lock"' >> .env` + if err := c.RunCmdEnvExec(command); err != nil { return errors.Wrap(err, "adding LOCK_DSN to .env") } @@ -151,34 +197,32 @@ func (c *bootstrapper) installShopwareProdSetup(freshInstall bool) error { params = "--basic-setup" } - if err := c.RunCmdEnvExec( - fmt.Sprintf( - "bin/console system:install --no-interaction --force %s", params, - ), - ); err != nil { + command = fmt.Sprintf("%s system:install --no-interaction --force %s", c.consoleCommand(), params) + if err := c.RunCmdEnvExec(command); err != nil { return errors.Wrap(err, "running shopware system:install") } - if err := c.RunCmdEnvExec("export CI=1 && bin/console bundle:dump"); err != nil { + command = fmt.Sprintf("export CI=1 && %s bundle:dump", c.consoleCommand()) + if err := c.RunCmdEnvExec(command); err != nil { return errors.Wrap(err, "running shopware bundle:dump") } // Ignore if themes cannot be dumped. - _ = c.RunCmdEnvExec("export CI=1 && bin/console theme:dump") + command = fmt.Sprintf("export CI=1 && %s theme:dump", c.consoleCommand()) + _ = c.RunCmdEnvExec(command) - if err := c.RunCmdEnvExec( - "export PUPPETEER_SKIP_CHROMIUM_DOWNLOAD=1 && if [ -f 'bin/build.sh' ]; then bin/build.sh; fi", - ); err != nil { + command = "export PUPPETEER_SKIP_CHROMIUM_DOWNLOAD=1 && if [ -f 'bin/build.sh' ]; then bin/build.sh; fi" + if err := c.RunCmdEnvExec(command); err != nil { return errors.Wrap(err, "running shopware bin/build.sh") } - if err := c.RunCmdEnvExec( - "export PUPPETEER_SKIP_CHROMIUM_DOWNLOAD=1 && if [ -f 'bin/build-js.sh']; then bin/build-js.sh; fi", - ); err != nil { + command = "export PUPPETEER_SKIP_CHROMIUM_DOWNLOAD=1 && if [ -f 'bin/build-js.sh']; then bin/build-js.sh; fi" + if err := c.RunCmdEnvExec(command); err != nil { return errors.Wrap(err, "running shopware bin/build-js.sh") } - if err := c.RunCmdEnvExec("bin/console system:update:finish --no-interaction"); err != nil { + command = fmt.Sprintf("%s system:update:finish --no-interaction", c.consoleCommand()) + if err := c.RunCmdEnvExec(command); err != nil { return errors.Wrap(err, "running shopware system:update:finish") } @@ -187,14 +231,16 @@ func (c *bootstrapper) installShopwareProdSetup(freshInstall bool) error { return nil } -func (c *bootstrapper) installShopwareDevSetup() error { +func (c *shopware) devSetup() error { log.Println("Setting up Shopware development template...") - if err := c.RunCmdEnvExec("chmod +x psh.phar bin/console bin/setup"); err != nil { + command := fmt.Sprintf("chmod +x psh.phar %s bin/setup", c.consoleCommand()) + if err := c.RunCmdEnvExec(command); err != nil { return errors.Wrap(err, "setting permissions") } - if err := c.RunCmdEnvExec("export PUPPETEER_SKIP_CHROMIUM_DOWNLOAD=1 && ./psh.phar install"); err != nil { + command = "export PUPPETEER_SKIP_CHROMIUM_DOWNLOAD=1 && ./psh.phar install" + if err := c.RunCmdEnvExec(command); err != nil { return errors.Wrap(err, "running shopware ./psh.phar install") } @@ -203,59 +249,55 @@ func (c *bootstrapper) installShopwareDevSetup() error { return nil } -func (c *bootstrapper) installShopwareConfigureSearch() (int, string) { +func (c *shopware) configureSearch() (int, string) { // Elasticsearch/OpenSearch configuration searchEnabled, searchHost := 0, "" - { - switch { - case c.ServiceEnabled("opensearch"): - searchEnabled = 1 - searchHost = "http://opensearch:9200" - - c.Set("SHOPWARE_SEARCH_ENABLED", 1) - c.Set("SHOPWARE_SEARCH_INDEXING_ENABLED", 1) - c.Set("SHOPWARE_SEARCH_HOST", "opensearch") - - openSearchInitialAdminPassword := c.GetString("OPENSEARCH_INITIAL_ADMIN_PASSWORD") - if openSearchInitialAdminPassword != "" { - c.Set("SHOPWARE_SEARCH_USERNAME", "admin") - c.Set("SHOPWARE_SEARCH_PASSWORD", openSearchInitialAdminPassword) - searchHost = "http://admin:" + url.PathEscape(openSearchInitialAdminPassword) + "@opensearch:9200" - } - - case c.ServiceEnabled("elasticsearch"): - searchEnabled = 1 - searchHost = "elasticsearch" - - c.Set("SHOPWARE_SEARCH_ENABLED", 1) - c.Set("SHOPWARE_SEARCH_INDEXING_ENABLED", 1) - c.Set("SHOPWARE_SEARCH_HOST", "elasticsearch") + + switch { + case c.ServiceEnabled("opensearch"): + searchEnabled = 1 + searchHost = "http://opensearch:9200" + + c.Set("SHOPWARE_SEARCH_ENABLED", 1) + c.Set("SHOPWARE_SEARCH_INDEXING_ENABLED", 1) + c.Set("SHOPWARE_SEARCH_HOST", "opensearch") + + openSearchInitialAdminPassword := c.GetString("OPENSEARCH_INITIAL_ADMIN_PASSWORD") + if openSearchInitialAdminPassword != "" { + c.Set("SHOPWARE_SEARCH_USERNAME", "admin") + c.Set("SHOPWARE_SEARCH_PASSWORD", openSearchInitialAdminPassword) + searchHost = "http://admin:" + url.PathEscape(openSearchInitialAdminPassword) + "@opensearch:9200" } + + case c.ServiceEnabled("elasticsearch"): + searchEnabled = 1 + searchHost = "elasticsearch" + + c.Set("SHOPWARE_SEARCH_ENABLED", 1) + c.Set("SHOPWARE_SEARCH_INDEXING_ENABLED", 1) + c.Set("SHOPWARE_SEARCH_HOST", "elasticsearch") } return searchEnabled, searchHost } -func (c *bootstrapper) installShopwareConfigureAdminUser() (string, error) { +func (c *shopware) configureAdminUser() (string, error) { log.Println("Creating admin user...") - adminPassword, err := password.Generate(16, 2, 0, false, false) - if err != nil { - return "", errors.Wrap(err, "generating admin password") - } - - if err = c.RunCmdEnvExec( - fmt.Sprintf( - `php bin/console user:create --no-interaction `+ - `--admin `+ - `--email="admin@example.com" `+ - `--firstName="Admin" `+ - `--lastName="Local" `+ - `--password="%s" `+ - `localadmin`, - adminPassword, - ), - ); err != nil { + adminPassword := c.generatePassword() + + command := fmt.Sprintf( + `%s user:create --no-interaction `+ + `--admin `+ + `--email="admin@example.com" `+ + `--firstName="Admin" `+ + `--lastName="Local" `+ + `--password="%s" `+ + `localadmin`, + c.consoleCommand(), + adminPassword, + ) + if err := c.RunCmdEnvExec(command); err != nil { return "", errors.Wrap(err, "creating admin user") } @@ -264,10 +306,11 @@ func (c *bootstrapper) installShopwareConfigureAdminUser() (string, error) { return adminPassword, nil } -func (c *bootstrapper) installShopwareClearCache() error { +func (c *shopware) clearCache() error { log.Println("Clearing cache...") - if err := c.RunCmdEnvExec("php bin/console cache:clear"); err != nil { + command := fmt.Sprintf("%s cache:clear", c.consoleCommand()) + if err := c.RunCmdEnvExec(command); err != nil { return errors.Wrap(err, "clearing cache") } @@ -276,8 +319,8 @@ func (c *bootstrapper) installShopwareClearCache() error { return nil } -func (c *bootstrapper) installShopwareDevConfig() error { - _, _ = c.installShopwareConfigureSearch() +func (c *shopware) devConfig() error { + _, _ = c.configureSearch() var ( bs bytes.Buffer @@ -311,3 +354,13 @@ func (c *bootstrapper) installShopwareDevConfig() error { return nil } + +func (c *shopware) consoleCommand() string { + verbosity := "-v" + + if c.IsDebug() { + verbosity += "vv" + } + + return fmt.Sprintf("php bin/console %s", verbosity) +} diff --git a/internal/logic/bootstrapWordpress.go b/internal/logic/bootstrapWordpress.go index 426b81b4..b8321671 100644 --- a/internal/logic/bootstrapWordpress.go +++ b/internal/logic/bootstrapWordpress.go @@ -14,8 +14,8 @@ import ( "github.com/rewardenv/reward/pkg/util" ) -// bootstrapWordpress runs a full WordPress bootstrap process. -func (c *bootstrapper) bootstrapWordpress() error { +// bootstrap runs a full WordPress bootstrap process. +func (c *wordpress) bootstrap() error { if !util.AskForConfirmation("Would you like to bootstrap Wordpress?") { return nil } @@ -30,7 +30,7 @@ func (c *bootstrapper) bootstrapWordpress() error { return errors.Wrap(err, "downloading wordpress") } - if err := c.installWordpressConfig(); err != nil { + if err := c.installWPConfig(); err != nil { return errors.Wrap(err, "configuring wordpress") } @@ -40,7 +40,38 @@ func (c *bootstrapper) bootstrapWordpress() error { return nil } -func (c *bootstrapper) installWordpressConfig() error { +func (c *wordpress) download() (downloaded bool, err error) { + if c.SkipComposerInstall() { + return false, nil + } + + if util.FileExists(filepath.Join(c.Cwd(), c.WebRoot(), "index.php")) { + return false, nil + } + + log.Println("Downloading and installing WordPress...") + + command := "wget -qO /tmp/wordpress.tar.gz https://wordpress.org/latest.tar.gz" + if err := c.RunCmdEnvExec(command); err != nil { + return false, errors.Wrap(err, "downloading wordpress") + } + + command = "tar -zxf /tmp/wordpress.tar.gz --strip-components=1 -C /var/www/html" + if err := c.RunCmdEnvExec(command); err != nil { + return false, errors.Wrap(err, "extracting wordpress") + } + + command = "rm -f /tmp/wordpress.tar.gz" + if err := c.RunCmdEnvExec(command); err != nil { + return false, errors.Wrap(err, "removing wordpress archive") + } + + log.Println("...WordPress downloaded.") + + return true, nil +} + +func (c *wordpress) installWPConfig() error { var ( bs bytes.Buffer configFilePath = filepath.Join(c.Cwd(), c.WebRoot(), "wp-config.php") diff --git a/internal/logic/install.go b/internal/logic/install.go index e55a162d..8798f29e 100644 --- a/internal/logic/install.go +++ b/internal/logic/install.go @@ -424,6 +424,7 @@ func (c *installer) installSSHConfigFlag() bool { // installModeFlag returns an int which represents the app home directory permissions. func (c *installer) installModeFlag() *os.FileMode { + //nolint:gosec m := os.FileMode(c.GetInt(fmt.Sprintf("%s_install_app_home_mode", c.AppName()))) return &m diff --git a/sonar-project.properties b/sonar-project.properties index 5c0715da..180d5dc8 100644 --- a/sonar-project.properties +++ b/sonar-project.properties @@ -2,7 +2,7 @@ sonar.projectKey=rewardenv_reward sonar.organization=rewardenv # This is the name and version displayed in the SonarCloud UI. sonar.projectName=reward -sonar.projectVersion=0.7.2 +sonar.projectVersion=0.7.3 # Path is relative to the sonar-project.properties file. Replace "\" by "/" on Windows. #sonar.sources=. # Encoding of the source code. Default is default system encoding