Skip to content

Commit 363a6bd

Browse files
authored
Introduce the upsun convert command
1 parent 66c8201 commit 363a6bd

File tree

5 files changed

+210
-0
lines changed

5 files changed

+210
-0
lines changed

commands/list.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,13 @@ func newListCommand(cnf *config.Config) *cobra.Command {
5353
list.AddCommand(&appConfigValidateCommand)
5454
}
5555

56+
appProjectConvertCommand := innerProjectConvertCommand(cnf)
57+
58+
if cnf.Service.ProjectConfigFlavor == "upsun" &&
59+
(!list.DescribesNamespace() || list.Namespace == appProjectConvertCommand.Name.Namespace) {
60+
list.AddCommand(&appProjectConvertCommand)
61+
}
62+
5663
format := viper.GetString("format")
5764
raw := viper.GetBool("raw")
5865

commands/project_convert.go

Lines changed: 189 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,189 @@
1+
package commands
2+
3+
import (
4+
"fmt"
5+
"io"
6+
"log"
7+
"os"
8+
"path/filepath"
9+
10+
"github.com/spf13/cobra"
11+
"github.com/spf13/viper"
12+
"github.com/symfony-cli/terminal"
13+
"github.com/upsun/lib-sun/detector"
14+
"github.com/upsun/lib-sun/entity"
15+
"github.com/upsun/lib-sun/readers"
16+
utils "github.com/upsun/lib-sun/utility"
17+
"github.com/upsun/lib-sun/writers"
18+
orderedmap "github.com/wk8/go-ordered-map/v2"
19+
20+
"github.com/platformsh/cli/internal/config"
21+
)
22+
23+
// innerProjectConvertCommand returns the Command struct for the convert config command.
24+
func innerProjectConvertCommand(cnf *config.Config) Command {
25+
noInteractionOption := NoInteractionOption(cnf)
26+
providerOption := Option{
27+
Name: "--provider",
28+
Shortcut: "-p",
29+
IsValueRequired: false,
30+
Default: Any{"platformsh"},
31+
Description: "The provider from which to convert the configuration. Currently, only 'platformsh' is supported.",
32+
}
33+
34+
return Command{
35+
Name: CommandName{
36+
Namespace: "project",
37+
Command: "convert",
38+
},
39+
Usage: []string{
40+
cnf.Application.Executable + " convert",
41+
},
42+
Aliases: []string{
43+
"convert",
44+
},
45+
Description: "Generate an Upsun compatible configuration based on the configuration from another provider.",
46+
Help: "",
47+
Examples: []Example{
48+
{
49+
Commandline: "--provider=platformsh",
50+
Description: "Convert the Platform.sh project configuration files in your current directory",
51+
},
52+
},
53+
Definition: Definition{
54+
Arguments: &orderedmap.OrderedMap[string, Argument]{},
55+
Options: orderedmap.New[string, Option](orderedmap.WithInitialData[string, Option](
56+
orderedmap.Pair[string, Option]{
57+
Key: HelpOption.GetName(),
58+
Value: HelpOption,
59+
},
60+
orderedmap.Pair[string, Option]{
61+
Key: VerboseOption.GetName(),
62+
Value: VerboseOption,
63+
},
64+
orderedmap.Pair[string, Option]{
65+
Key: VersionOption.GetName(),
66+
Value: VersionOption,
67+
},
68+
orderedmap.Pair[string, Option]{
69+
Key: YesOption.GetName(),
70+
Value: YesOption,
71+
},
72+
orderedmap.Pair[string, Option]{
73+
Key: noInteractionOption.GetName(),
74+
Value: noInteractionOption,
75+
},
76+
orderedmap.Pair[string, Option]{
77+
Key: "provider",
78+
Value: providerOption,
79+
},
80+
)),
81+
},
82+
Hidden: false,
83+
}
84+
}
85+
86+
// newProjectConvertCommand creates the cobra command for converting config.
87+
func newProjectConvertCommand(cnf *config.Config) *cobra.Command {
88+
cmd := &cobra.Command{
89+
Use: "project:convert",
90+
Short: "Generate locally Upsun configuration from another provider",
91+
Aliases: []string{"convert"},
92+
RunE: runProjectConvert,
93+
}
94+
95+
cmd.Flags().StringP(
96+
"provider",
97+
"p",
98+
"platformsh",
99+
"The provider from which to convert the configuration. Currently, only 'platformsh' is supported.",
100+
)
101+
102+
_ = viper.BindPFlag("provider", cmd.Flags().Lookup("provider"))
103+
cmd.SetHelpFunc(func(_ *cobra.Command, _ []string) {
104+
internalCmd := innerProjectConvertCommand(cnf)
105+
fmt.Println(internalCmd.HelpPage(cnf))
106+
})
107+
return cmd
108+
}
109+
110+
// runProjectConvert is the entry point for the convert config command.
111+
func runProjectConvert(cmd *cobra.Command, _ []string) error {
112+
if viper.GetString("provider") != "platformsh" {
113+
return fmt.Errorf("only the 'platformsh' provider is currently supported")
114+
}
115+
return runPlatformShConvert(cmd)
116+
}
117+
118+
// runPlatformShConvert performs the conversion from Platform.sh config to Upsun config.
119+
func runPlatformShConvert(cmd *cobra.Command) error {
120+
cwd, err := os.Getwd()
121+
if err != nil {
122+
return fmt.Errorf("could not get current working directory: %w", err)
123+
}
124+
125+
cwd, err = filepath.Abs(filepath.Clean(cwd))
126+
if err != nil {
127+
return fmt.Errorf("could not normalize project workspace path: %w", err)
128+
}
129+
130+
// Disable log for lib-sun
131+
log.Default().SetOutput(io.Discard)
132+
133+
// Find config files
134+
configFiles, err := detector.FindConfig(cwd)
135+
if err != nil {
136+
return fmt.Errorf("could not detect configuration files: %w", err)
137+
}
138+
139+
// Read PSH application config files
140+
var metaConfig entity.MetaConfig
141+
readers.ReadApplications(&metaConfig, configFiles[entity.PSH_APPLICATION], cwd)
142+
readers.ReadPlatforms(&metaConfig, configFiles[entity.PSH_PLATFORM], cwd)
143+
if metaConfig.Applications.IsZero() {
144+
return fmt.Errorf("no Platform.sh applications found")
145+
}
146+
147+
// Read PSH services and routes config files
148+
readers.ReadServices(&metaConfig, configFiles[entity.PSH_SERVICE])
149+
readers.ReadRoutes(&metaConfig, configFiles[entity.PSH_ROUTE])
150+
151+
// Remove size and resources entries
152+
readers.RemoveAllEntry(&metaConfig.Services, "size")
153+
readers.RemoveAllEntry(&metaConfig.Applications, "size")
154+
readers.RemoveAllEntry(&metaConfig.Services, "resources")
155+
readers.RemoveAllEntry(&metaConfig.Applications, "resources")
156+
157+
// Fix storage to match Upsun format
158+
readers.ReplaceAllEntry(&metaConfig.Applications, "local", "instance")
159+
readers.ReplaceAllEntry(&metaConfig.Applications, "shared", "storage")
160+
readers.RemoveAllEntry(&metaConfig.Applications, "disk")
161+
162+
upsunDir := filepath.Join(cwd, ".upsun")
163+
if err := os.MkdirAll(upsunDir, os.ModePerm); err != nil {
164+
return fmt.Errorf("could not create .upsun directory: %w", err)
165+
}
166+
167+
configPath := filepath.Join(upsunDir, "config.yaml")
168+
stat, err := os.Stat(configPath)
169+
if err == nil && !stat.IsDir() {
170+
cmd.Printf("The file %v already exists.\n", configPath)
171+
if !viper.GetBool("yes") {
172+
if viper.GetBool("no-interaction") {
173+
return fmt.Errorf("use the -y option to overwrite the file")
174+
}
175+
176+
if !terminal.AskConfirmation("Do you want to overwrite it?", true) {
177+
return nil
178+
}
179+
}
180+
}
181+
writers.GenerateUpsunConfigFile(metaConfig, configPath)
182+
183+
// Move extra config
184+
utils.TransferConfigCustom(cwd, upsunDir)
185+
186+
cmd.Println("Your configuration was successfully converted to the Upsun format.")
187+
cmd.Printf("Check the generated files in %v\n", upsunDir)
188+
return nil
189+
}

commands/root.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,7 @@ func newRootCommand(cnf *config.Config, assets *vendorization.VendorAssets) *cob
123123
cmd.PersistentFlags().BoolP("version", "V", false, fmt.Sprintf("Displays the %s version", cnf.Application.Name))
124124
cmd.PersistentFlags().Bool("debug", false, "Enable debug logging")
125125
cmd.PersistentFlags().Bool("no-interaction", false, "Enable non-interactive mode")
126+
cmd.PersistentFlags().BoolP("yes", "y", false, "Assume 'yes' to all prompts")
126127
cmd.PersistentFlags().BoolP("verbose", "v", false, "Enable verbose output")
127128
cmd.PersistentFlags().BoolP("quiet", "q", false,
128129
"Suppress any messages and errors (stderr), while continuing to display necessary output (stdout)."+
@@ -153,6 +154,9 @@ func newRootCommand(cnf *config.Config, assets *vendorization.VendorAssets) *cob
153154
validateCmd,
154155
versionCommand,
155156
)
157+
if cnf.Service.ProjectConfigFlavor == "upsun" {
158+
cmd.AddCommand(newProjectConvertCommand(cnf))
159+
}
156160

157161
//nolint:errcheck
158162
viper.BindPFlags(cmd.PersistentFlags())

go.mod

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ require (
1414
github.com/spf13/viper v1.21.0
1515
github.com/stretchr/testify v1.11.1
1616
github.com/symfony-cli/terminal v1.0.7
17+
github.com/upsun/lib-sun v0.3.16
1718
github.com/wk8/go-ordered-map/v2 v2.1.8
1819
golang.org/x/crypto v0.42.0
1920
golang.org/x/oauth2 v0.31.0
@@ -31,6 +32,7 @@ require (
3132
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
3233
github.com/fsnotify/fsnotify v1.9.0 // indirect
3334
github.com/gabriel-vasile/mimetype v1.4.10 // indirect
35+
github.com/getsentry/sentry-go v0.28.1 // indirect
3436
github.com/go-playground/locales v0.14.1 // indirect
3537
github.com/go-playground/universal-translator v0.18.1 // indirect
3638
github.com/go-viper/mapstructure/v2 v2.4.0 // indirect

go.sum

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,12 @@ github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S
3030
github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=
3131
github.com/gabriel-vasile/mimetype v1.4.10 h1:zyueNbySn/z8mJZHLt6IPw0KoZsiQNszIpU+bX4+ZK0=
3232
github.com/gabriel-vasile/mimetype v1.4.10/go.mod h1:d+9Oxyo1wTzWdyVUPMmXFvp4F9tea18J8ufA774AB3s=
33+
github.com/getsentry/sentry-go v0.28.1 h1:zzaSm/vHmGllRM6Tpx1492r0YDzauArdBfkJRtY6P5k=
34+
github.com/getsentry/sentry-go v0.28.1/go.mod h1:1fQZ+7l7eeJ3wYi82q5Hg8GqAPgefRq+FP/QhafYVgg=
3335
github.com/go-chi/chi/v5 v5.2.3 h1:WQIt9uxdsAbgIYgid+BpYc+liqQZGMHRaUwp0JUcvdE=
3436
github.com/go-chi/chi/v5 v5.2.3/go.mod h1:L2yAIGWB3H+phAw1NxKwWM+7eUH/lU8pOMm5hHcoops=
37+
github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA=
38+
github.com/go-errors/errors v1.4.2/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og=
3539
github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s=
3640
github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
3741
github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA=
@@ -88,6 +92,8 @@ github.com/oklog/ulid/v2 v2.1.1/go.mod h1:rcEKHmBBKfef9DhnvX7y1HZBYxjXb0cP5ExxNs
8892
github.com/pborman/getopt v0.0.0-20170112200414-7148bc3a4c30/go.mod h1:85jBQOZwpVEaDAr341tbn15RS4fCAsIst0qp7i8ex1o=
8993
github.com/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0t5Ec4=
9094
github.com/pelletier/go-toml/v2 v2.2.4/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY=
95+
github.com/pingcap/errors v0.11.4 h1:lFuQV/oaUMGcD2tqt+01ROSmJs75VG1ToEOkZIZ4nE4=
96+
github.com/pingcap/errors v0.11.4/go.mod h1:Oi8TUi2kEtXXLMJk9l1cGmz20kV3TaQ0usTwv5KuLY8=
9197
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
9298
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
9399
github.com/platformsh/platformify v0.4.1 h1:SJCcCDjIF13KVUNdZtm3SC1uy6iWFhtvJIljqAuIbXQ=
@@ -127,6 +133,8 @@ github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8
127133
github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU=
128134
github.com/symfony-cli/terminal v1.0.7 h1:57L9PUTE2cHfQtP8Ti8dyiiPEYlQ1NBIDpMJ3RPEGPc=
129135
github.com/symfony-cli/terminal v1.0.7/go.mod h1:Etv22IyeGiMoIQPPj51hX31j7xuYl1njyuAFkrvybqU=
136+
github.com/upsun/lib-sun v0.3.16 h1:46QTFurVKJZ/E4sGdJ+2Zi/MVAQKbTMMcdOxMaty/UQ=
137+
github.com/upsun/lib-sun v0.3.16/go.mod h1:LRs+1TttogDkbvpnz2sxcAPdePld1BuxSjRUs4fW4UM=
130138
github.com/wk8/go-ordered-map/v2 v2.1.8 h1:5h/BUHu93oj4gIdvHHHGsScSTMijfx5PeYkE/fJgbpc=
131139
github.com/wk8/go-ordered-map/v2 v2.1.8/go.mod h1:5nJHM5DyteebpVlHnWMV0rPz6Zp7+xBAnxjb1X5vnTw=
132140
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=

0 commit comments

Comments
 (0)