Skip to content

Commit fd93f81

Browse files
authored
get started (#1)
1 parent 64e37ff commit fd93f81

34 files changed

+3426
-0
lines changed

.github/workflows/pr.yml

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
name: Pull request
2+
on:
3+
pull_request:
4+
branches:
5+
- main
6+
jobs:
7+
vet:
8+
name: Vet
9+
runs-on: ubuntu-latest
10+
concurrency:
11+
group: ${{ github.head_ref }}-vet
12+
cancel-in-progress: true
13+
steps:
14+
- name: Checkout
15+
uses: actions/checkout@v4
16+
with:
17+
ref: ${{ github.event.pull_request.head.sha }}
18+
- name: Setup asdf
19+
uses: asdf-vm/actions/install@v3
20+
- name: Install dependencies
21+
run: go mod download
22+
- name: Add asdf shims to PATH
23+
run: |
24+
echo "${HOME}/.asdf/shims" >> $GITHUB_PATH
25+
- name: Lint
26+
run: go vet ./...
27+
- name: Run integration tests
28+
run: go test -v ./...

.github/workflows/release.yml

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
name: Release
2+
3+
on:
4+
push:
5+
6+
permissions:
7+
contents: write
8+
9+
jobs:
10+
release:
11+
if: startsWith(github.ref, 'refs/tags/')
12+
runs-on: ubuntu-latest
13+
steps:
14+
- name: Checkout
15+
uses: actions/checkout@v4
16+
with:
17+
fetch-depth: 0
18+
- name: Set up Go
19+
uses: actions/setup-go@v4
20+
- name: Run GoReleaser
21+
uses: goreleaser/goreleaser-action@v5
22+
with:
23+
distribution: goreleaser
24+
version: "~> v1"
25+
args: release --clean
26+
env:
27+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
node_modules
2+
dist/
3+
/Dockerfile

.goreleaser.yaml

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
version: 1
2+
3+
before:
4+
hooks:
5+
- go mod tidy
6+
7+
builds:
8+
- main: ./cmd/new-dockerfile
9+
env:
10+
- CGO_ENABLED=0
11+
goos:
12+
- linux
13+
- windows
14+
- darwin
15+
16+
archives:
17+
- format: tar.gz
18+
# this name template makes the OS and Arch compatible with the results of `uname`.
19+
name_template: >-
20+
{{ .ProjectName }}-
21+
{{- .Os }}-
22+
{{- if eq .Arch "amd64" }}x86_64
23+
{{- else if eq .Arch "386" }}i386
24+
{{- else }}{{ .Arch }}{{ end }}
25+
{{- if .Arm }}v{{ .Arm }}{{ end }}
26+
# use zip for windows archives
27+
format_overrides:
28+
- goos: windows
29+
format: zip
30+
31+
changelog:
32+
sort: asc
33+
filters:
34+
exclude:
35+
- "^docs:"
36+
- "^test:"

.tool-versions

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
golang 1.22.3

cmd/new-dockerfile/main.go

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
package main
2+
3+
import (
4+
"fmt"
5+
"log/slog"
6+
"os"
7+
"path/filepath"
8+
"strings"
9+
"time"
10+
11+
dockerfile "github.com/flexstack/new-dockerfile"
12+
"github.com/flexstack/new-dockerfile/runtime"
13+
"github.com/lmittmann/tint"
14+
flag "github.com/spf13/pflag"
15+
)
16+
17+
func main() {
18+
var path string
19+
flag.StringVar(&path, "path", ".", "Path to the project directory")
20+
var noColor bool
21+
flag.BoolVar(&noColor, "no-color", false, "Disable colorized output")
22+
var runtimeArg string
23+
flag.StringVar(&runtimeArg, "runtime", "", "Force a specific runtime")
24+
var quiet bool
25+
flag.BoolVar(&quiet, "quiet", false, "Disable all log output except errors")
26+
var write bool
27+
flag.BoolVar(&write, "write", false, "Write the Dockerfile to disk at ./Dockerfile")
28+
flag.Parse()
29+
30+
level := slog.LevelInfo
31+
if os.Getenv("DEBUG") != "" {
32+
level = slog.LevelDebug
33+
} else if quiet {
34+
level = slog.LevelError
35+
}
36+
37+
handler := tint.NewHandler(os.Stderr, &tint.Options{
38+
Level: level,
39+
TimeFormat: time.Kitchen,
40+
NoColor: noColor,
41+
})
42+
43+
log := slog.New(handler)
44+
df := dockerfile.New(log)
45+
46+
var (
47+
r runtime.Runtime
48+
err error
49+
)
50+
51+
if runtimeArg != "" {
52+
runtimes := df.ListRuntimes()
53+
54+
for _, rt := range runtimes {
55+
if strings.ToLower(string(rt.Name())) == strings.ToLower(runtimeArg) {
56+
r = rt
57+
break
58+
}
59+
}
60+
if r == nil {
61+
runtimeNames := make([]string, len(runtimes))
62+
for i, rt := range runtimes {
63+
runtimeNames[i] = string(rt.Name())
64+
}
65+
log.Error(fmt.Sprintf(`Runtime "%s" not found. Expected one of: %s`, runtimeArg, "\n - "+strings.Join(runtimeNames, "\n - ")))
66+
os.Exit(1)
67+
}
68+
}
69+
70+
if r == nil {
71+
r, err = df.MatchRuntime(path)
72+
if err != nil {
73+
log.Error("Fatal error: " + err.Error())
74+
os.Exit(1)
75+
}
76+
}
77+
78+
contents, err := r.GenerateDockerfile(path)
79+
if err != nil {
80+
os.Exit(1)
81+
}
82+
83+
if !write {
84+
fmt.Println(string(contents))
85+
return
86+
}
87+
88+
output := filepath.Join(path, "Dockerfile")
89+
if err = os.WriteFile(output, contents, 0644); err != nil {
90+
log.Error("Fatal error: " + err.Error())
91+
os.Exit(1)
92+
}
93+
94+
log.Info(fmt.Sprintf("Auto-generated Dockerfile for project using %s: %s", string(r.Name()), output))
95+
}

go.mod

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
module github.com/flexstack/new-dockerfile
2+
3+
go 1.22.3
4+
5+
require (
6+
github.com/lmittmann/tint v1.0.4
7+
github.com/pelletier/go-toml v1.9.5
8+
github.com/spf13/pflag v1.0.5
9+
)

go.sum

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
github.com/lmittmann/tint v1.0.4 h1:LeYihpJ9hyGvE0w+K2okPTGUdVLfng1+nDNVR4vWISc=
2+
github.com/lmittmann/tint v1.0.4/go.mod h1:HIS3gSy7qNwGCj+5oRjAutErFBl4BzdQP6cJZ0NfMwE=
3+
github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8=
4+
github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c=
5+
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
6+
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=

main.go

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
package dockerfile
2+
3+
import (
4+
"fmt"
5+
"log/slog"
6+
"os"
7+
"path/filepath"
8+
9+
"github.com/flexstack/new-dockerfile/runtime"
10+
)
11+
12+
// Creates a new Dockerfile generator.
13+
func New(log ...*slog.Logger) *Dockerfile {
14+
var logger *slog.Logger
15+
16+
if len(log) > 0 {
17+
logger = log[0]
18+
} else {
19+
logger = slog.New(slog.NewTextHandler(os.Stdout, nil))
20+
}
21+
22+
return &Dockerfile{
23+
log: logger,
24+
}
25+
}
26+
27+
type Dockerfile struct {
28+
log *slog.Logger
29+
}
30+
31+
// Generates a Dockerfile for the given path and writes it to the same directory.
32+
func (a *Dockerfile) Write(path string) error {
33+
runtime, err := a.MatchRuntime(path)
34+
if err != nil {
35+
return err
36+
}
37+
38+
contents, err := runtime.GenerateDockerfile(path)
39+
if err != nil {
40+
return err
41+
}
42+
43+
// Write the Dockerfile to the same directory
44+
if err = os.WriteFile(filepath.Join(path, "Dockerfile"), contents, 0644); err != nil {
45+
return err
46+
}
47+
48+
// a.log.Info("Auto-generated Dockerfile for project using " + string(lang.Name()) + "\n" + *contents)
49+
a.log.Info("Auto-generated Dockerfile for project using " + string(runtime.Name()))
50+
return nil
51+
}
52+
53+
func (a *Dockerfile) ListRuntimes() []runtime.Runtime {
54+
return []runtime.Runtime{
55+
&runtime.Golang{Log: a.log},
56+
&runtime.Rust{Log: a.log},
57+
&runtime.Ruby{Log: a.log},
58+
&runtime.Python{Log: a.log},
59+
&runtime.PHP{Log: a.log},
60+
&runtime.Java{Log: a.log},
61+
&runtime.Elixir{Log: a.log},
62+
&runtime.Deno{Log: a.log},
63+
&runtime.Bun{Log: a.log},
64+
&runtime.NextJS{Log: a.log},
65+
&runtime.Node{Log: a.log},
66+
&runtime.Static{Log: a.log},
67+
}
68+
}
69+
70+
func (a *Dockerfile) MatchRuntime(path string) (runtime.Runtime, error) {
71+
for _, r := range a.ListRuntimes() {
72+
if r.Match(path) {
73+
return r, nil
74+
}
75+
}
76+
77+
return nil, ErrRuntimeNotFound
78+
}
79+
80+
var ErrRuntimeNotFound = fmt.Errorf("A Dockerfile was not detected in the project and we could not auto-generate one for you.")

node/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
# Autogenerate a Dockerfile from your project source code

0 commit comments

Comments
 (0)