Skip to content

Commit 0ccb7a7

Browse files
Merge pull request #1 from featheredtoast/multi-container-compose
Support multi container builds on docker compose
2 parents f036a3f + 0574276 commit 0ccb7a7

File tree

9 files changed

+357
-105
lines changed

9 files changed

+357
-105
lines changed

.github/workflows/ci.yml

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ on:
99
pull_request:
1010

1111
jobs:
12-
lint:
12+
fmt:
1313
runs-on: ubuntu-latest
1414
timeout-minutes: 5
1515
strategy:
@@ -18,11 +18,24 @@ jobs:
1818
- uses: actions/checkout@v4
1919
- uses: actions/setup-go@v5
2020
with:
21-
go-version: '>=1.22.0'
21+
go-version: '>=1.23.0'
2222
- run: |
2323
if [ "$(gofmt -l . | wc -l)" -gt 0 ]; then
2424
exit 1
2525
fi
26+
27+
lint:
28+
runs-on: ubuntu-latest
29+
steps:
30+
- uses: actions/checkout@v4
31+
- uses: actions/setup-go@v5
32+
with:
33+
go-version: ">=1.23.0"
34+
- name: golangci-lint
35+
uses: golangci/golangci-lint-action@v8
36+
with:
37+
version: v2.1
38+
2639
test:
2740
runs-on: ubuntu-latest
2841
timeout-minutes: 5
@@ -32,7 +45,7 @@ jobs:
3245
- uses: actions/checkout@v4
3346
- uses: actions/setup-go@v5
3447
with:
35-
go-version: '>=1.22.0'
48+
go-version: '>=1.23.0'
3649
- run: go test ./...
3750

3851
create_release:
@@ -65,7 +78,7 @@ jobs:
6578
- uses: actions/checkout@v4
6679
- uses: actions/setup-go@v5
6780
with:
68-
go-version: ">=1.22.0"
81+
go-version: ">=1.23.0"
6982
- name: build and release
7083
env:
7184
GH_TOKEN: ${{ github.token }}

concourse.go

Lines changed: 35 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ package main
22

33
import (
44
"bytes"
5-
"errors"
65
"fmt"
76
"os"
87
"strings"
@@ -43,7 +42,7 @@ type ConcourseConfig struct {
4342
Config string
4443
}
4544

46-
func getConcourseTask(config config.Config) string {
45+
func getConcourseTask(config config.Config) (string, error) {
4746
content := []*yaml.Node{}
4847
for k, v := range config.Env {
4948
key := yaml.Node{
@@ -78,16 +77,19 @@ func getConcourseTask(config config.Config) string {
7877
var b bytes.Buffer
7978
encoder := yaml.NewEncoder(&b)
8079
encoder.SetIndent(2)
81-
encoder.Encode(&concourseTask)
80+
if err := encoder.Encode(&concourseTask); err != nil {
81+
return "", err
82+
}
83+
8284
yaml := b.Bytes()
83-
return string(yaml)
85+
return string(yaml), nil
8486
}
8587

8688
// generates a yaml file containing:
8789
// dockerfile, concoursetask, config
8890
// which may be used in a static concourse resource
8991
// to generate build jobs
90-
func GenConcourseConfig(config config.Config) string {
92+
func GenConcourseConfig(config config.Config) (string, error) {
9193

9294
const defaultBaseImage = "discourse/base:2.0.20240825-0027"
9395
parts := strings.Split(defaultBaseImage, ":")
@@ -97,25 +99,35 @@ func GenConcourseConfig(config config.Config) string {
9799
tag = parts[1]
98100
}
99101

102+
task, err := getConcourseTask(config)
103+
if err != nil {
104+
return "", err
105+
}
100106
concourseConfig := &ConcourseConfig{
101107
FromNamespace: namespace,
102108
FromTag: tag,
103-
Dockerfile: config.Dockerfile("--skip-tags=precompile,migrate,db", false),
104-
ConcourseTask: getConcourseTask(config),
109+
Dockerfile: config.Dockerfile("--skip-tags=precompile,migrate,db", "config.yaml"),
110+
ConcourseTask: task,
105111
Config: config.Yaml(),
106112
}
107113

108114
var b bytes.Buffer
109115
encoder := yaml.NewEncoder(&b)
110116
encoder.SetIndent(2)
111-
encoder.Encode(&concourseConfig)
117+
if err := encoder.Encode(&concourseConfig); err != nil {
118+
return "", err
119+
}
112120
yaml := b.Bytes()
113-
return string(yaml)
121+
return string(yaml), nil
114122
}
115123

116124
func WriteConcourseConfig(config config.Config, file string) error {
117-
if err := os.WriteFile(file, []byte(GenConcourseConfig(config)), 0660); err != nil {
118-
return errors.New("error writing concourse job config " + file)
125+
concourseConfig, err := GenConcourseConfig(config)
126+
if err != nil {
127+
return nil
128+
}
129+
if err := os.WriteFile(file, []byte(concourseConfig), 0660); err != nil {
130+
return err
119131
}
120132
return nil
121133
}
@@ -128,12 +140,21 @@ type ConcourseJobCmd struct {
128140
func (r *ConcourseJobCmd) Run(cli *Cli) error {
129141
loadedConfig, err := config.LoadConfig(cli.ConfDir, r.Config, true, cli.TemplatesDir)
130142
if err != nil {
131-
return errors.New("YAML syntax error. Please check your containers/*.yml config files.")
143+
return err
132144
}
133145
if r.Output == "" {
134-
fmt.Fprint(utils.Out, GenConcourseConfig(*loadedConfig))
146+
concourseConfig, err := GenConcourseConfig(*loadedConfig)
147+
if err != nil {
148+
return err
149+
}
150+
_, err = fmt.Fprint(utils.Out, concourseConfig)
151+
if err != nil {
152+
return err
153+
}
135154
} else {
136-
WriteConcourseConfig(*loadedConfig, r.Output)
155+
if err = WriteConcourseConfig(*loadedConfig, r.Output); err != nil {
156+
return err
157+
}
137158
}
138159
return nil
139160
}

docker_compose.go

Lines changed: 21 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -59,14 +59,14 @@ func DockerComposeService(config config.Config) ComposeService {
5959
}
6060
slices.Sort(volumes)
6161
ports := []string{}
62-
for _, v := range config.Expose {
63-
ports = append(ports, v)
64-
}
62+
ports = append(ports, config.Expose...)
6563
slices.Sort(ports)
6664

6765
args := []string{}
68-
for k, _ := range config.Env {
69-
args = append(args, k)
66+
for k := range config.Env {
67+
if !slices.Contains(utils.KnownSecrets, k) {
68+
args = append(args, k)
69+
}
7070
}
7171
slices.Sort(args)
7272

@@ -86,7 +86,7 @@ func DockerComposeService(config config.Config) ComposeService {
8686
}
8787
}
8888

89-
func WriteDockerCompose(configs []config.Config, dir string, bakeEnv bool) error {
89+
func WriteDockerCompose(configs []config.Config, dir string) error {
9090
if err := WriteEnvConfig(configs, dir); err != nil {
9191
return err
9292
}
@@ -95,14 +95,18 @@ func WriteDockerCompose(configs []config.Config, dir string, bakeEnv bool) error
9595
composeServices := map[string]ComposeService{}
9696
composeVolumes := map[string]*interface{}{}
9797
for _, config := range configs {
98-
if err := WriteDockerfile(config, dir, pupsArgs, bakeEnv); err != nil {
98+
if err := WriteDockerfile(config, dir, pupsArgs); err != nil {
9999
return err
100100
}
101101
composeServices[config.Name] = DockerComposeService(config)
102102

103+
regex, err := regexp.Compile(`^[A-Za-z]`)
104+
if err != nil {
105+
return err
106+
}
103107
for _, v := range config.Volumes {
104108
// if this is a docker volume (vs a bind mount), add to global volume list
105-
matched, _ := regexp.MatchString(`^[A-Za-z]`, v.Volume.Host)
109+
matched := regex.MatchString(v.Volume.Host)
106110
if matched {
107111
composeVolumes[v.Volume.Host] = nil
108112
}
@@ -128,13 +132,13 @@ func WriteDockerCompose(configs []config.Config, dir string, bakeEnv bool) error
128132
return nil
129133
}
130134

131-
func WriteDockerfile(config config.Config, dir string, pupsArgs string, bakeEnv bool) error {
132-
if err := config.WriteYamlConfig(dir); err != nil {
135+
func WriteDockerfile(config config.Config, dir string, pupsArgs string) error {
136+
if err := config.WriteYamlConfig(dir, config.Name+".yaml"); err != nil {
133137
return err
134138
}
135139

136140
file := strings.TrimRight(dir, "/") + "/" + config.Name + ".dockerfile"
137-
if err := os.WriteFile(file, []byte(config.Dockerfile(pupsArgs, bakeEnv)), 0660); err != nil {
141+
if err := os.WriteFile(file, []byte(config.Dockerfile(pupsArgs, config.Name+".yaml")), 0660); err != nil {
138142
return errors.New("error writing dockerfile Dockerfile " + file)
139143
}
140144
return nil
@@ -143,7 +147,7 @@ func WriteDockerfile(config config.Config, dir string, pupsArgs string, bakeEnv
143147
func WriteEnvConfig(configs []config.Config, dir string) error {
144148
file := strings.TrimRight(dir, "/") + "/.envrc"
145149
if err := os.WriteFile(file, []byte(ExportEnv(configs)), 0660); err != nil {
146-
return errors.New("error writing export env " + file)
150+
return err
147151
}
148152
return nil
149153
}
@@ -167,15 +171,13 @@ func ExportEnv(configs []config.Config) string {
167171
}
168172

169173
type DockerComposeCmd struct {
170-
OutputDir string `name:"output dir" default:"./compose" short:"o" help:"Output dir for docker compose files." predictor:"dir"`
171-
BakeEnv bool `short:"e" help:"Bake in the configured environment to image after build."`
172-
173-
Config []string `arg:"" name:"config" help:"config to include in the docker-compose. The first config is assuemd to be the main container, and will be the parent folder of the ouput project" predictor:"config"`
174+
OutputDir string `name:"output dir" default:"./compose" short:"o" help:"Output dir for docker compose files." predictor:"dir"`
175+
Config []string `arg:"" name:"config" help:"config to include in the docker-compose. The first config is assumed to be the main container, and will be the parent folder of the ouput project" predictor:"config"`
174176
}
175177

176178
func (r *DockerComposeCmd) Run(cli *Cli, ctx *context.Context) error {
177179
if len(r.Config) < 1 {
178-
return errors.New("No config given, need at least one container name.")
180+
return errors.New("empty config array")
179181
}
180182

181183
dir := r.OutputDir + "/" + r.Config[0]
@@ -187,11 +189,11 @@ func (r *DockerComposeCmd) Run(cli *Cli, ctx *context.Context) error {
187189
for _, configName := range r.Config {
188190
config, err := config.LoadConfig(cli.ConfDir, configName, true, cli.TemplatesDir)
189191
if err != nil {
190-
return errors.New("YAML syntax error. Please check your containers/*.yml config files.")
192+
return err
191193
}
192194
configs = append(configs, *config)
193195
}
194-
if err := WriteDockerCompose(configs, dir, r.BakeEnv); err != nil {
196+
if err := WriteDockerCompose(configs, dir); err != nil {
195197
return err
196198
}
197199
return nil

go.mod

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,20 @@
1-
module github.com/featheredtoast/launcher-extras
1+
module github.com/featheredtoast/discourse-launcher-extras
22

3-
go 1.22
4-
5-
toolchain go1.23.0
3+
go 1.23.0
64

75
require (
8-
github.com/alecthomas/kong v0.9.0
9-
github.com/discourse/launcher/v2 v2.0.0-20241115213408-1ca23f3608bc
6+
github.com/alecthomas/kong v1.12.0
7+
github.com/discourse/launcher/v2 v2.1.0
108
github.com/onsi/ginkgo/v2 v2.20.1
119
github.com/onsi/gomega v1.34.1
1210
github.com/posener/complete v1.2.3
1311
github.com/willabides/kongplete v0.4.0
14-
golang.org/x/sys v0.25.0
12+
golang.org/x/sys v0.34.0
1513
gopkg.in/yaml.v3 v3.0.1
1614
)
1715

1816
require (
19-
dario.cat/mergo v1.0.1 // indirect
17+
dario.cat/mergo v1.0.2 // indirect
2018
github.com/go-logr/logr v1.4.2 // indirect
2119
github.com/go-task/slim-sprig/v3 v3.0.0 // indirect
2220
github.com/google/go-cmp v0.6.0 // indirect
@@ -25,7 +23,7 @@ require (
2523
github.com/hashicorp/go-multierror v1.1.1 // indirect
2624
github.com/riywo/loginshell v0.0.0-20200815045211-7d26008be1ab // indirect
2725
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 // indirect
28-
golang.org/x/net v0.28.0 // indirect
29-
golang.org/x/text v0.17.0 // indirect
26+
golang.org/x/net v0.33.0 // indirect
27+
golang.org/x/text v0.21.0 // indirect
3028
golang.org/x/tools v0.24.0 // indirect
3129
)

go.sum

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,16 @@
1-
dario.cat/mergo v1.0.1 h1:Ra4+bf83h2ztPIQYNP99R6m+Y7KfnARDfID+a+vLl4s=
2-
dario.cat/mergo v1.0.1/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk=
3-
github.com/alecthomas/assert/v2 v2.6.0 h1:o3WJwILtexrEUk3cUVal3oiQY2tfgr/FHWiz/v2n4FU=
4-
github.com/alecthomas/assert/v2 v2.6.0/go.mod h1:Bze95FyfUr7x34QZrjL+XP+0qgp/zg8yS+TtBj1WA3k=
5-
github.com/alecthomas/kong v0.9.0 h1:G5diXxc85KvoV2f0ZRVuMsi45IrBgx9zDNGNj165aPA=
6-
github.com/alecthomas/kong v0.9.0/go.mod h1:Y47y5gKfHp1hDc7CH7OeXgLIpp+Q2m1Ni0L5s3bI8Os=
1+
dario.cat/mergo v1.0.2 h1:85+piFYR1tMbRrLcDwR18y4UKJ3aH1Tbzi24VRW1TK8=
2+
dario.cat/mergo v1.0.2/go.mod h1:E/hbnu0NxMFBjpMIE34DRGLWqDy0g5FuKDhCb31ngxA=
3+
github.com/alecthomas/assert/v2 v2.11.0 h1:2Q9r3ki8+JYXvGsDyBXwH3LcJ+WK5D0gc5E8vS6K3D0=
4+
github.com/alecthomas/assert/v2 v2.11.0/go.mod h1:Bze95FyfUr7x34QZrjL+XP+0qgp/zg8yS+TtBj1WA3k=
5+
github.com/alecthomas/kong v1.12.0 h1:oKd/0fHSdajj5PfGDd3ScvEvpVJf9mT2mb5r9xYadYM=
6+
github.com/alecthomas/kong v1.12.0/go.mod h1:p2vqieVMeTAnaC83txKtXe8FLke2X07aruPWXyMPQrU=
77
github.com/alecthomas/repr v0.4.0 h1:GhI2A8MACjfegCPVq9f1FLvIBS+DrQ2KQBFZP1iFzXc=
88
github.com/alecthomas/repr v0.4.0/go.mod h1:Fr0507jx4eOXV7AlPV6AVZLYrLIuIeSOWtW57eE/O/4=
99
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
1010
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
1111
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
12-
github.com/discourse/launcher/v2 v2.0.0-20241115213408-1ca23f3608bc h1:J+zauJkRI2CyDIEhLnsufmrEA6N+4wLFMcKYYNmFeZ8=
13-
github.com/discourse/launcher/v2 v2.0.0-20241115213408-1ca23f3608bc/go.mod h1:wZC/FJNwCDISasN4IqPJ6A8ciW9+8ppHDOmtJxJ5Yfc=
12+
github.com/discourse/launcher/v2 v2.1.0 h1:SeZgIPXijxSg4D2M3uWUHp+XguK2buTzQuTZE9I045M=
13+
github.com/discourse/launcher/v2 v2.1.0/go.mod h1:q/EVCRmMEPZSDrB36eoSWKeV8kv5g5qPNI3cA0DnW3c=
1414
github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
1515
github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
1616
github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI=
@@ -45,12 +45,12 @@ github.com/willabides/kongplete v0.4.0 h1:eivXxkp5ud5+4+NVN9e4goxC5mSh3n1RHov+gs
4545
github.com/willabides/kongplete v0.4.0/go.mod h1:0P0jtWD9aTsqPSUAl4de35DLghrr57XcayPyvqSi2X8=
4646
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 h1:2dVuKD2vS7b0QIHQbpyTISPd0LeHDbnYEryqj5Q1ug8=
4747
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY=
48-
golang.org/x/net v0.28.0 h1:a9JDOJc5GMUJ0+UDqmLT86WiEy7iWyIhz8gz8E4e5hE=
49-
golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg=
50-
golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34=
51-
golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
52-
golang.org/x/text v0.17.0 h1:XtiM5bkSOt+ewxlOE/aE/AKEHibwj/6gvWMl9Rsh0Qc=
53-
golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
48+
golang.org/x/net v0.33.0 h1:74SYHlV8BIgHIFC/LrYkOGIwL19eTYXQ5wc6TBuO36I=
49+
golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4=
50+
golang.org/x/sys v0.34.0 h1:H5Y5sJ2L2JRdyv7ROF1he/lPdvFsd0mJHFw2ThKHxLA=
51+
golang.org/x/sys v0.34.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
52+
golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo=
53+
golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
5454
golang.org/x/tools v0.24.0 h1:J1shsA93PJUEVaUSaay7UXAyE8aimq3GW0pjlolpa24=
5555
golang.org/x/tools v0.24.0/go.mod h1:YhNqVBIfWHdzvTLs0d8LCuMhkKUgSUKldakyV7W/WDQ=
5656
google.golang.org/protobuf v1.34.1 h1:9ddQBjfCyZPOHPUiPxpYESBLc+T8P3E+Vo4IbKZgFWg=

main.go

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,14 @@ package main
33
import (
44
"context"
55
"fmt"
6+
"os"
7+
"os/signal"
8+
69
"github.com/alecthomas/kong"
710
"github.com/discourse/launcher/v2/utils"
811
"github.com/posener/complete"
912
"github.com/willabides/kongplete"
1013
"golang.org/x/sys/unix"
11-
"os"
12-
"os/signal"
1314
)
1415

1516
type Cli struct {
@@ -50,7 +51,7 @@ func main() {
5051
go func() {
5152
select {
5253
case <-sigChan:
53-
fmt.Fprintln(utils.Out, "Command interrupted")
54+
fmt.Fprintln(utils.Out, "Command interrupted") //nolint:errcheck
5455
cancel()
5556
case <-done:
5657
}

0 commit comments

Comments
 (0)