Skip to content

Commit e504f9c

Browse files
authored
Merge pull request #257 from platformsh/cli-24-platformify-does-not-have-the-latest-runtime-versions
[CLI-24] Update service versions from the registry
2 parents 1f76794 + 2156164 commit e504f9c

File tree

7 files changed

+322
-30
lines changed

7 files changed

+322
-30
lines changed
Lines changed: 288 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,288 @@
1+
//go:build ignore
2+
3+
package main
4+
5+
import (
6+
"bytes"
7+
"encoding/json"
8+
"fmt"
9+
"go/format"
10+
"io"
11+
"log"
12+
"net/http"
13+
"os"
14+
"path/filepath"
15+
"sort"
16+
"strings"
17+
"text/template"
18+
)
19+
20+
const registryURL = "https://raw.githubusercontent.com/platformsh/platformsh-docs/main/shared/data/registry.json"
21+
22+
type Registry map[string]Service
23+
24+
type Service struct {
25+
Description string `json:"description"`
26+
Disk bool `json:"disk"`
27+
Runtime bool `json:"runtime"`
28+
Type string `json:"type"`
29+
Versions map[string][]string `json:"versions"`
30+
}
31+
32+
// Mapping from registry service names to our ServiceName constants
33+
var serviceMapping = map[string]string{
34+
"chrome-headless": "ChromeHeadless",
35+
"influxdb": "InfluxDB",
36+
"kafka": "Kafka",
37+
"mariadb": "MariaDB",
38+
"memcached": "Memcached",
39+
"mysql": "MySQL",
40+
"network-storage": "NetworkStorage",
41+
"opensearch": "OpenSearch",
42+
"oracle-mysql": "OracleMySQL",
43+
"postgresql": "PostgreSQL",
44+
"rabbitmq": "RabbitMQ",
45+
"redis": "Redis",
46+
"solr": "Solr",
47+
"varnish": "Varnish",
48+
"vault-kms": "VaultKMS",
49+
}
50+
51+
// Mapping from registry runtime names to our Runtime constants
52+
var runtimeMapping = map[string]string{
53+
"dotnet": "DotNet",
54+
"elixir": "Elixir",
55+
"golang": "Golang",
56+
"java": "Java",
57+
"nodejs": "NodeJS",
58+
"php": "PHP",
59+
"python": "Python",
60+
"ruby": "Ruby",
61+
"rust": "Rust",
62+
}
63+
64+
const versionTemplate = `//go:generate go run generate_versions.go
65+
66+
package models
67+
68+
var (
69+
LanguageTypeVersions = map[Runtime][]string{
70+
{{- range .Languages }}
71+
{{ .Name }}: {{ .Versions }},
72+
{{- end }}
73+
}
74+
75+
ServiceTypeVersions = map[ServiceName][]string{
76+
{{- range .Services }}
77+
{{ .Name }}: {{ .Versions }},
78+
{{- end }}
79+
}
80+
)
81+
82+
func DefaultVersionForRuntime(r Runtime) string {
83+
versions := LanguageTypeVersions[r]
84+
if len(versions) == 0 {
85+
return ""
86+
}
87+
return versions[0]
88+
}
89+
`
90+
91+
type TemplateData struct {
92+
Languages []TypeVersion
93+
Services []TypeVersion
94+
}
95+
96+
type TypeVersion struct {
97+
Name string
98+
Versions string
99+
}
100+
101+
func main() {
102+
// Fetch the registry data
103+
resp, err := http.Get(registryURL)
104+
if err != nil {
105+
log.Fatalf("Failed to fetch registry: %v", err)
106+
}
107+
defer resp.Body.Close()
108+
109+
body, err := io.ReadAll(resp.Body)
110+
if err != nil {
111+
log.Fatalf("Failed to read response: %v", err)
112+
}
113+
114+
var registry Registry
115+
if err := json.Unmarshal(body, &registry); err != nil {
116+
log.Fatalf("Failed to parse JSON: %v", err)
117+
}
118+
119+
var languages []TypeVersion
120+
var services []TypeVersion
121+
122+
// Process runtimes (languages)
123+
for serviceName, service := range registry {
124+
if !service.Runtime {
125+
continue
126+
}
127+
128+
constantName, exists := runtimeMapping[serviceName]
129+
if !exists {
130+
continue // Skip runtimes we don't support
131+
}
132+
133+
supported := service.Versions["supported"]
134+
if len(supported) == 0 {
135+
continue
136+
}
137+
138+
versions := formatVersionSlice(supported)
139+
languages = append(languages, TypeVersion{
140+
Name: constantName,
141+
Versions: versions,
142+
})
143+
}
144+
145+
// Process services
146+
for serviceName, service := range registry {
147+
if service.Runtime {
148+
continue
149+
}
150+
151+
constantName, exists := serviceMapping[serviceName]
152+
if !exists {
153+
continue // Skip services we don't support
154+
}
155+
156+
supported := service.Versions["supported"]
157+
if len(supported) == 0 {
158+
continue
159+
}
160+
161+
versions := formatVersionSlice(supported)
162+
services = append(services, TypeVersion{
163+
Name: constantName,
164+
Versions: versions,
165+
})
166+
167+
// Add RedisPersistent right after Redis
168+
if serviceName == "redis" {
169+
services = append(services, TypeVersion{
170+
Name: "RedisPersistent",
171+
Versions: versions,
172+
})
173+
}
174+
}
175+
176+
// Sort for consistent output
177+
sort.Slice(languages, func(i, j int) bool {
178+
return languages[i].Name < languages[j].Name
179+
})
180+
sort.Slice(services, func(i, j int) bool {
181+
return services[i].Name < services[j].Name
182+
})
183+
184+
// Generate the Go code
185+
tmpl, err := template.New("version").Parse(versionTemplate)
186+
if err != nil {
187+
log.Fatalf("Failed to parse template: %v", err)
188+
}
189+
190+
var buf bytes.Buffer
191+
data := TemplateData{
192+
Languages: languages,
193+
Services: services,
194+
}
195+
196+
if err := tmpl.Execute(&buf, data); err != nil {
197+
log.Fatalf("Failed to execute template: %v", err)
198+
}
199+
200+
// Format the generated Go code
201+
formatted, err := format.Source(buf.Bytes())
202+
if err != nil {
203+
log.Fatalf("Failed to format Go code: %v", err)
204+
}
205+
206+
// Write to version.go file
207+
dir, err := os.Getwd()
208+
if err != nil {
209+
log.Fatalf("Failed to get working directory: %v", err)
210+
}
211+
212+
outputPath := filepath.Join(dir, "version.go")
213+
if err := os.WriteFile(outputPath, formatted, 0644); err != nil {
214+
log.Fatalf("Failed to write version.go: %v", err)
215+
}
216+
217+
fmt.Printf("Successfully generated %s\n", outputPath)
218+
}
219+
220+
func formatVersionSlice(versions []string) string {
221+
if len(versions) == 0 {
222+
return "{}"
223+
}
224+
225+
// Sort versions from latest to oldest
226+
sortedVersions := make([]string, len(versions))
227+
copy(sortedVersions, versions)
228+
229+
sort.Slice(sortedVersions, func(i, j int) bool {
230+
return compareVersions(sortedVersions[i], sortedVersions[j])
231+
})
232+
233+
quoted := make([]string, len(sortedVersions))
234+
for i, v := range sortedVersions {
235+
quoted[i] = fmt.Sprintf(`"%s"`, v)
236+
}
237+
238+
return fmt.Sprintf("{%s}", strings.Join(quoted, ", "))
239+
}
240+
241+
// compareVersions returns true if version a is greater than version b
242+
func compareVersions(a, b string) bool {
243+
// Parse version parts
244+
aParts := parseVersion(a)
245+
bParts := parseVersion(b)
246+
247+
// Compare each part
248+
maxLen := len(aParts)
249+
if len(bParts) > maxLen {
250+
maxLen = len(bParts)
251+
}
252+
253+
for i := 0; i < maxLen; i++ {
254+
aVal := 0
255+
bVal := 0
256+
257+
if i < len(aParts) {
258+
aVal = aParts[i]
259+
}
260+
if i < len(bParts) {
261+
bVal = bParts[i]
262+
}
263+
264+
if aVal > bVal {
265+
return true
266+
}
267+
if aVal < bVal {
268+
return false
269+
}
270+
}
271+
272+
return false // versions are equal
273+
}
274+
275+
// parseVersion parses a version string into numeric parts
276+
func parseVersion(version string) []int {
277+
parts := strings.Split(version, ".")
278+
nums := make([]int, 0, len(parts))
279+
280+
for _, part := range parts {
281+
// Handle cases like "25.05" or "1.0" or just "1"
282+
num := 0
283+
fmt.Sscanf(part, "%d", &num)
284+
nums = append(nums, num)
285+
}
286+
287+
return nums
288+
}

internal/question/models/service_name.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88

99
const (
1010
ChromeHeadless ServiceName = "chrome-headless"
11+
ClickHouse ServiceName = "clickhouse"
1112
InfluxDB ServiceName = "influxdb"
1213
Kafka ServiceName = "kafka"
1314
MariaDB ServiceName = "mariadb"

internal/question/models/version.go

Lines changed: 24 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,37 @@
1+
//go:generate go run generate_versions.go
2+
13
package models
24

35
var (
46
LanguageTypeVersions = map[Runtime][]string{
5-
DotNet: {"6.0", "3.1"},
6-
Elixir: {"1.13", "1.12", "1.11"},
7-
Golang: {"1.22", "1.21", "1.20"},
8-
Java: {"19", "18", "17", "11", "8"},
9-
NodeJS: {"20", "18", "16"},
10-
PHP: {"8.2", "8.1", "8.0"},
11-
Python: {"3.11", "3.10", "3.9", "3.8", "3.7"},
12-
Ruby: {"3.3", "3.2", "3.1", "3.0", "2.7", "2.6", "2.5", "2.4", "2.3"},
7+
DotNet: {"8.0", "7.0", "6.0"},
8+
Elixir: {"1.18", "1.15", "1.14"},
9+
Golang: {"1.25", "1.24", "1.23", "1.22", "1.21", "1.20"},
10+
Java: {"21", "19", "18", "17", "11", "8"},
11+
NodeJS: {"24", "22", "20"},
12+
PHP: {"8.4", "8.3", "8.2", "8.1"},
13+
Python: {"3.13", "3.12", "3.11", "3.10", "3.9", "3.8"},
14+
Ruby: {"3.4", "3.3", "3.2", "3.1", "3.0"},
1315
Rust: {"1"},
1416
}
1517

1618
ServiceTypeVersions = map[ServiceName][]string{
17-
ChromeHeadless: {"95", "91", "86", "84", "83", "81", "80", "73"},
18-
InfluxDB: {"2.3"},
19-
Kafka: {"3.2"},
20-
MariaDB: {"11.0", "10.11", "10.6", "10.5", "10.4", "10.3"},
19+
ChromeHeadless: {"120", "113", "95", "91"},
20+
ClickHouse: {"25.3", "24.3", "23.8"},
21+
InfluxDB: {"2.7", "2.3"},
22+
Kafka: {"3.7", "3.6", "3.4", "3.2"},
23+
MariaDB: {"11.8", "11.4", "10.11", "10.6"},
2124
Memcached: {"1.6", "1.5", "1.4"},
22-
MySQL: {"10.6", "10.5", "10.4", "10.3"},
23-
NetworkStorage: {"2.0"},
24-
OpenSearch: {"2", "1.2", "1.1"},
25+
MySQL: {"11.8", "11.4", "10.11", "10.6"},
26+
NetworkStorage: {"1.0"},
27+
OpenSearch: {"3", "2"},
2528
OracleMySQL: {"8.0", "5.7"},
26-
PostgreSQL: {"15", "14", "13", "12", "11"},
27-
RabbitMQ: {"3.11", "3.10", "3.9"},
28-
Redis: {"7.0", "6.2"},
29-
RedisPersistent: {"7.0", "6.2"},
30-
Solr: {"9.1", "8.11"},
31-
Varnish: {"7.2", "7.1", "6.3", "6.0"},
29+
PostgreSQL: {"18", "17", "16", "15", "14", "13", "12"},
30+
RabbitMQ: {"4.1", "4.0", "3.13", "3.12"},
31+
Redis: {"8.0", "7.2"},
32+
RedisPersistent: {"8.0", "7.2"},
33+
Solr: {"9.9", "9.6", "9.4", "9.2", "9.1", "8.11"},
34+
Varnish: {"7.6", "7.3", "7.2", "6.0"},
3235
VaultKMS: {"1.12"},
3336
}
3437
)

platformifier/platformifier_test.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ var (
2121
Name: "django",
2222
Type: "python",
2323
Stack: Django,
24-
Runtime: "python-3.9",
24+
Runtime: "python-3.13",
2525
ApplicationRoot: "app",
2626
Environment: map[string]string{
2727
"DJANGO_SETTINGS_MODULE": "app.settings",
@@ -81,14 +81,14 @@ var (
8181
{
8282
Name: "db",
8383
Type: "postgres",
84-
TypeVersions: []string{"13", "14", "15"},
84+
TypeVersions: []string{"17", "16", "15", "14", "13", "12"},
8585
Disk: "1024",
8686
DiskSizes: []string{"1024", "2048"},
8787
},
8888
{
8989
Name: "mysql",
9090
Type: "mysql",
91-
TypeVersions: []string{"13", "14", "15"},
91+
TypeVersions: []string{"11.0", "10.11", "10.6", "10.5", "10.4", "10.3"},
9292
Disk: "1024",
9393
DiskSizes: []string{"1024", "2034"},
9494
},
@@ -141,7 +141,7 @@ var (
141141
Name: "Laravel",
142142
Type: "php",
143143
Stack: Laravel,
144-
Runtime: "php-8.2",
144+
Runtime: "php-8.4",
145145
ApplicationRoot: "app",
146146
Environment: map[string]string{},
147147
Root: "app",

platformifier/templates/generic/.platform/services.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,6 @@
1616
{{ else }}
1717
# relationships
1818
# db:
19-
# type: postgresql:14
19+
# type: postgresql:17
2020
# disk: 1024
2121
{{ end -}}

0 commit comments

Comments
 (0)