Skip to content

Commit ef20200

Browse files
committed
Reference implemetation for SCORE v1b1
1 parent 47f0815 commit ef20200

File tree

15 files changed

+843
-1
lines changed

15 files changed

+843
-1
lines changed

.github/workflows/release.yaml

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
name: goreleaser
2+
3+
on:
4+
push:
5+
tags:
6+
- '*'
7+
8+
permissions:
9+
contents: write
10+
11+
jobs:
12+
goreleaser:
13+
runs-on: ubuntu-latest
14+
steps:
15+
-
16+
name: Checkout
17+
uses: actions/checkout@v3
18+
with:
19+
fetch-depth: 0
20+
-
21+
name: Fetch all tags
22+
run: git fetch --force --tags
23+
-
24+
name: Set up Go
25+
uses: actions/setup-go@v3
26+
with:
27+
go-version: 1.19
28+
-
29+
name: Run GoReleaser
30+
uses: goreleaser/goreleaser-action@v3
31+
with:
32+
distribution: goreleaser
33+
version: latest
34+
args: release --rm-dist
35+
env:
36+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
# VS Code workspace configuration
2+
.vscode/
3+
14
# Binaries for programs and plugins
25
*.exe
36
*.exe~

.goreleaser.yaml

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
# Check the documentation at https://goreleaser.com
2+
before:
3+
hooks:
4+
- go mod tidy
5+
builds:
6+
- id: score-compose
7+
binary: score-compose
8+
main: ./cli
9+
ldflags:
10+
- -X github.com/score-spec/score-compose/internal/version.Version={{ .Version }}
11+
- -X github.com/score-spec/score-compose/internal/version.BuildTime={{ .CommitDate }}
12+
- -X github.com/score-spec/score-compose/internal/version.GitSHA={{ .FullCommit }}
13+
env:
14+
- CGO_ENABLED=0
15+
targets:
16+
- linux_amd64_v1
17+
- linux_arm64
18+
- windows_amd64_v1
19+
- darwin_amd64_v1
20+
- darwin_arm64
21+
archives:
22+
- format_overrides:
23+
- goos: windows
24+
format: zip
25+
checksum:
26+
name_template: 'checksums.txt'
27+
snapshot:
28+
name_template: "{{ incpatch .Version }}-next"
29+
changelog:
30+
sort: asc
31+
filters:
32+
exclude:
33+
- '^docs:'
34+
- '^test:'

README.md

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,13 @@
11
# score-compose
2-
Reference implementation for docker-compose target platform support
2+
3+
This tool produces a `docker-compose` configuration file from the `SCORE` specification.
4+
5+
## Usage
6+
```
7+
score-compose run
8+
```
9+
10+
## Help
11+
```
12+
score-compose --help
13+
```

cli/cmd/root.go

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
package cmd
2+
3+
import (
4+
"fmt"
5+
6+
"github.com/spf13/cobra"
7+
8+
"github.com/score-spec/score-compose/internal/version"
9+
)
10+
11+
var (
12+
rootCmd = &cobra.Command{
13+
Use: "score-compose",
14+
Short: "SCORE to docker-compose translator",
15+
Long: `SCORE is a specification for defining environment agnostic configuration for cloud based workloads.
16+
This tool produces a docker-compose configuration file from the SCORE specification.
17+
Complete documentation is available at https://score.sh.`,
18+
Version: fmt.Sprintf("%s (build: %s; sha: %s)", version.Version, version.BuildTime, version.GitSHA),
19+
}
20+
)
21+
22+
func init() {
23+
rootCmd.SetVersionTemplate(`{{with .Name}}{{printf "%s " .}}{{end}}{{printf "%s" .Version}}
24+
`)
25+
}
26+
27+
func Execute() error {
28+
return rootCmd.Execute()
29+
}

cli/cmd/run.go

Lines changed: 167 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,167 @@
1+
package cmd
2+
3+
import (
4+
"fmt"
5+
"io"
6+
"log"
7+
"os"
8+
9+
"github.com/compose-spec/compose-go/types"
10+
"github.com/imdario/mergo"
11+
"github.com/spf13/cobra"
12+
13+
"github.com/score-spec/score-compose/internal/compose"
14+
15+
loader "github.com/score-spec/score-go/loader"
16+
score "github.com/score-spec/score-go/types"
17+
)
18+
19+
const (
20+
scoreFileDefault = "./score.yaml"
21+
overridesFileDefault = "./overrides.score.yaml"
22+
)
23+
24+
var (
25+
scoreFile string
26+
overridesFile string
27+
outFile string
28+
envFile string
29+
buildCtx string
30+
31+
verbose bool
32+
)
33+
34+
func init() {
35+
runCmd.Flags().StringVarP(&scoreFile, "file", "f", scoreFileDefault, "Source SCORE file")
36+
runCmd.Flags().StringVar(&overridesFile, "overrides", overridesFileDefault, "Overrides SCORE file")
37+
runCmd.Flags().StringVarP(&outFile, "output", "o", "", "Output file")
38+
runCmd.Flags().StringVar(&envFile, "env-file", "", "Location to store sample .env file")
39+
runCmd.Flags().StringVar(&buildCtx, "build", "", "Replaces 'image' name with compose 'build' instruction")
40+
41+
runCmd.Flags().BoolVar(&verbose, "verbose", false, "Enable diagnostic messages (written to STDERR)")
42+
43+
rootCmd.AddCommand(runCmd)
44+
}
45+
46+
var runCmd = &cobra.Command{
47+
Use: "run",
48+
Short: "Translate the SCORE file to docker-compose configuration",
49+
RunE: run,
50+
}
51+
52+
func run(cmd *cobra.Command, args []string) error {
53+
if !verbose {
54+
log.SetOutput(io.Discard)
55+
}
56+
57+
// Open source file
58+
//
59+
log.Printf("Reading '%s'...\n", scoreFile)
60+
var err error
61+
var src []byte
62+
if src, err = os.ReadFile(scoreFile); err != nil {
63+
return err
64+
}
65+
66+
// Parse SCORE spec
67+
//
68+
log.Print("Parsing SCORE spec...\n")
69+
var srcMap map[string]interface{}
70+
if err = loader.ParseYAML(src, &srcMap); err != nil {
71+
return err
72+
}
73+
74+
// Apply overrides (optional)
75+
//
76+
if overridesFile != "" {
77+
var ovr []byte
78+
log.Printf("Checking '%s'...\n", overridesFile)
79+
if ovr, err = os.ReadFile(overridesFile); err == nil {
80+
log.Print("Applying SCORE overrides...\n")
81+
var ovrMap map[string]interface{}
82+
if err = loader.ParseYAML(ovr, &ovrMap); err != nil {
83+
return err
84+
}
85+
if err := mergo.MergeWithOverwrite(&srcMap, ovrMap); err != nil {
86+
return fmt.Errorf("applying overrides fom '%s': %w", overridesFile, err)
87+
}
88+
} else if !os.IsNotExist(err) || overridesFile != overridesFileDefault {
89+
return err
90+
}
91+
}
92+
93+
// Validate SCORE spec
94+
//
95+
log.Print("Validating SCORE spec...\n")
96+
var spec score.WorkloadSpec
97+
if err = loader.MapSpec(srcMap, &spec); err != nil {
98+
return fmt.Errorf("validating workload spec: %w", err)
99+
}
100+
101+
// Build docker-compose configuration
102+
//
103+
log.Print("Building docker-compose configuration...\n")
104+
proj, vars, err := compose.ConvertSpec(&spec)
105+
if err != nil {
106+
return fmt.Errorf("building docker-compose configuration: %w", err)
107+
}
108+
109+
// Override 'image' reference with 'build' instructions
110+
//
111+
if buildCtx != "" {
112+
log.Printf("Applying build instructions: '%s'...\n", buildCtx)
113+
for idx := range proj.Services {
114+
if proj.Services[idx].Name == spec.Metadata.Name {
115+
proj.Services[idx].Build = &types.BuildConfig{Context: buildCtx}
116+
proj.Services[idx].Image = ""
117+
}
118+
}
119+
}
120+
121+
// Open output file (optional)
122+
//
123+
var dest = io.Writer(os.Stdout)
124+
if outFile != "" {
125+
log.Printf("Creating '%s'...\n", outFile)
126+
destFile, err := os.Create(outFile)
127+
if err != nil {
128+
return err
129+
}
130+
defer destFile.Close()
131+
132+
dest = io.MultiWriter(dest, destFile)
133+
}
134+
135+
// Write docker-compose spec
136+
//
137+
log.Print("Writing docker-compose configuration...\n")
138+
if err = compose.WriteYAML(proj, dest); err != nil {
139+
return err
140+
}
141+
142+
if envFile != "" {
143+
// Open .env file
144+
//
145+
log.Printf("Creating '%s'...\n", envFile)
146+
dest, err := os.Create(envFile)
147+
if err != nil {
148+
return err
149+
}
150+
defer dest.Close()
151+
152+
// Write .env file
153+
//
154+
log.Print("Writing .env file template...\n")
155+
for key, val := range vars {
156+
if val == nil {
157+
val = ""
158+
}
159+
var envVar = fmt.Sprintf("%s=%v\n", key, val)
160+
if _, err := dest.WriteString(envVar); err != nil {
161+
return err
162+
}
163+
}
164+
}
165+
166+
return nil
167+
}

cli/main.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
package main
2+
3+
import (
4+
"fmt"
5+
"os"
6+
7+
"github.com/score-spec/score-compose/cli/cmd"
8+
)
9+
10+
func main() {
11+
12+
if err := cmd.Execute(); err != nil {
13+
fmt.Fprintln(os.Stderr, err)
14+
os.Exit(1)
15+
}
16+
}

go.mod

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
module github.com/score-spec/score-compose
2+
3+
go 1.19
4+
5+
require (
6+
github.com/compose-spec/compose-go v1.6.0
7+
github.com/imdario/mergo v0.3.13
8+
github.com/score-spec/score-go v0.0.0-20221017023139-9c41abd6e1ee
9+
github.com/spf13/cobra v1.6.0
10+
github.com/stretchr/testify v1.8.0
11+
gopkg.in/yaml.v3 v3.0.1
12+
)
13+
14+
require (
15+
github.com/davecgh/go-spew v1.1.1 // indirect
16+
github.com/distribution/distribution/v3 v3.0.0-20220725133111-4bf3547399eb // indirect
17+
github.com/docker/go-connections v0.4.0 // indirect
18+
github.com/inconshreveable/mousetrap v1.0.1 // indirect
19+
github.com/mitchellh/mapstructure v1.5.0 // indirect
20+
github.com/opencontainers/go-digest v1.0.0 // indirect
21+
github.com/pmezard/go-difflib v1.0.0 // indirect
22+
github.com/spf13/pflag v1.0.5 // indirect
23+
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4 // indirect
24+
)

go.sum

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
github.com/compose-spec/compose-go v1.6.0 h1:7Ol/UULMUtbPmB0EYrETASRoum821JpOh/XaEf+hN+Q=
2+
github.com/compose-spec/compose-go v1.6.0/go.mod h1:os+Ulh2jlZxY1XT1hbciERadjSUU/BtZ6+gcN7vD7J0=
3+
github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
4+
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
5+
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
6+
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
7+
github.com/distribution/distribution/v3 v3.0.0-20220725133111-4bf3547399eb h1:oCCuuU3kMO3sjZH/p7LamvQNW9SWoT4yQuMGcdSxGAE=
8+
github.com/distribution/distribution/v3 v3.0.0-20220725133111-4bf3547399eb/go.mod h1:28YO/VJk9/64+sTGNuYaBjWxrXTPrj0C0XmgTIOjxX4=
9+
github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ=
10+
github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec=
11+
github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg=
12+
github.com/imdario/mergo v0.3.13 h1:lFzP57bqS/wsqKssCGmtLAb8A0wKjLGrve2q3PPVcBk=
13+
github.com/imdario/mergo v0.3.13/go.mod h1:4lJ1jqUDcsbIECGy0RUJAXNIhg+6ocWgb1ALK2O4oXg=
14+
github.com/inconshreveable/mousetrap v1.0.1 h1:U3uMjPSQEBMNp1lFxmllqCPM6P5u/Xq7Pgzkat/bFNc=
15+
github.com/inconshreveable/mousetrap v1.0.1/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
16+
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
17+
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
18+
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
19+
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
20+
github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
21+
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
22+
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
23+
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
24+
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
25+
github.com/score-spec/score-go v0.0.0-20221017023139-9c41abd6e1ee h1:3NnLILMT7goeA3nZ5oxuA5wPW1SALPK+EhzElslyQG8=
26+
github.com/score-spec/score-go v0.0.0-20221017023139-9c41abd6e1ee/go.mod h1:eNU0evgibNfV6ESUfRKjWcfGPmd92dI8dsUN/GBouZs=
27+
github.com/spf13/cobra v1.6.0 h1:42a0n6jwCot1pUmomAp4T7DeMD+20LFv4Q54pxLf2LI=
28+
github.com/spf13/cobra v1.6.0/go.mod h1:IOw/AERYS7UzyrGinqmz6HLUo219MORXGxhbaJUqzrY=
29+
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
30+
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
31+
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
32+
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
33+
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
34+
github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk=
35+
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
36+
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4 h1:uVc8UZUe6tr40fFVnUP5Oj+veunVezqYl9z7DYw9xzw=
37+
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
38+
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
39+
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
40+
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
41+
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
42+
gopkg.in/yaml.v3 v3.0.0/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
43+
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
44+
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
45+
gotest.tools/v3 v3.3.0 h1:MfDY1b1/0xN1CyMlQDac0ziEy9zJQd9CXBRRDHw2jJo=

0 commit comments

Comments
 (0)