Skip to content

Commit

Permalink
Build docker image.
Browse files Browse the repository at this point in the history
  • Loading branch information
monopole committed Aug 9, 2024
1 parent 7848a9a commit 09980e1
Show file tree
Hide file tree
Showing 7 changed files with 199 additions and 37 deletions.
5 changes: 3 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,10 @@ clean:
go clean -testcache

# Force serial execution of dependencies.
# This only really matters in the release target.
# This only matters for build targets that declare multiple dependencies,
# and it forces those dependencies to be built serially in the order that
# they appear in the dependencies list.
.NOTPARALLEL:

# Create a draft release and push it to github.
# Requires go, git, zip, tar, gh (github cli) and env var GH_TOKEN.
# Complains if workspace is dirty, tests fail, tags don't make sense, etc.
Expand Down
12 changes: 0 additions & 12 deletions releasing/Dockerfile

This file was deleted.

108 changes: 108 additions & 0 deletions releasing/internal/dockerrunner.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
package internal

import (
"log/slog"
"os"
"path/filepath"
"strings"
"time"
)

// DockerRunner runs some "docker" commands.
type DockerRunner struct {
rn *MyRunner
ldVars *LdVars
pgmName string
dirTmp string
}

const (
imageRegistry = "hub.docker.com"
imageRoot = "monopole"

dockerTemplate = `
# This file is generated; DO NOT EDIT.
FROM golang:1.22.5-bullseye
WORKDIR /go/src/github.com/monopole/{{PGMNAME}}
COPY go.mod .
COPY go.sum .
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 GOWORK=off \
go build -v -o /go/bin/{{PGMNAME}} \
-ldflags "{{LDFLAGS}}" \
.
ENTRYPOINT ["/go/bin/{{PGMNAME}}"]
`
)

func NewDockerRunner(dirSrc, dirTmp string, ldVars *LdVars) *DockerRunner {
return &DockerRunner{
rn: NewMyRunner("docker", dirSrc, DoIt, 3*time.Minute),
ldVars: ldVars,
dirTmp: dirTmp,
pgmName: filepath.Base(dirSrc),
}
}

func (dr *DockerRunner) Content() []byte {
content := strings.Replace(
dockerTemplate[1:], "{{LDFLAGS}}", dr.ldVars.MakeLdFlags(), -1)
content = strings.Replace(content, "{{PGMNAME}}", dr.pgmName, -1)
return []byte(content)
}

func (dr *DockerRunner) ImageName() string {
return imageRegistry + "/" + imageRoot + "/" + dr.pgmName + ":" + dr.ldVars.Version()
}

func (dr *DockerRunner) Build() error {
dr.rn.comment("building docker image at tag " + dr.ldVars.Version())
dockerFileName := filepath.Join(dr.dirTmp, "Dockerfile")
if err := os.WriteFile(dockerFileName, dr.Content(), 0644); err != nil {
return err
}
slog.Info("Wrote", "file", dockerFileName)
err := dr.rn.run(
NoHarmDone,
"build",
"--file", dockerFileName,
// "--platform", "linux/amd64,linux/arm64" (not using this yet)
"-t", dr.ImageName(),
".",
)
if err != nil {
slog.Error(err.Error())
slog.Error(dr.rn.Out())
return err
}
return nil
}

func (dr *DockerRunner) Push() error {
err := dr.rn.run(
UndoIsHard,
"push",
dr.ImageName(),
)
if err != nil {
slog.Error(err.Error())
slog.Error(dr.rn.Out())
}
return err
}

func (dr *DockerRunner) Login() error {
dur := dr.rn.duration
dr.rn.duration = 3 * time.Second
err := dr.rn.run(
NoHarmDone,
"login",
)
dr.rn.duration = dur
if err != nil {
slog.Error(err.Error())
slog.Error(dr.rn.Out())
}
return err
}
2 changes: 1 addition & 1 deletion releasing/internal/ghrunner.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import (
"time"
)

// GithubRunner runs some the "gh" commands.
// GithubRunner runs some "gh" commands.
type GithubRunner struct {
rn *MyRunner
}
Expand Down
8 changes: 4 additions & 4 deletions releasing/internal/gobuilder.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ func (gb *GoBuilder) Build(myOs EnumOs, myArch EnumArch) (string, error) {
if err := gb.goRun.run(NoHarmDone,
"build",
"-o", binary,
"-ldflags", gb.ldVars.makeLdFlags(),
"-ldflags", gb.ldVars.MakeLdFlags(),
".", // Using the "." is why we need HOME defined.
); err != nil {
return name, err
Expand All @@ -82,7 +82,7 @@ func (gb *GoBuilder) packageIt(
myOs EnumOs, myArch EnumArch, fileName string) (string, error) {
base := strings.Join([]string{
gb.pgmName,
gb.ldVars.version(),
gb.ldVars.Version(),
myOs.String(),
myArch.String(),
}, "_")
Expand Down Expand Up @@ -119,7 +119,7 @@ func (ldv *LdVars) makeDefinitions() []string {
return result
}

func (ldv *LdVars) makeLdFlags() string {
func (ldv *LdVars) MakeLdFlags() string {
result := []string{
"-s", // disable symbol table (small binary)
"-w", // disable DWARF generation (ditto)
Expand All @@ -131,7 +131,7 @@ func (ldv *LdVars) makeLdFlags() string {
return strings.Join(result, " ")
}

func (ldv *LdVars) version() string {
func (ldv *LdVars) Version() string {
v, ok := ldv.Kvs["version"]
if !ok {
panic("version not in ldFlags!")
Expand Down
31 changes: 31 additions & 0 deletions releasing/internal/gobuilder_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package internal

import (
"github.com/stretchr/testify/assert"
"testing"
)

func TestLdVars_MakeLdFlags(t *testing.T) {
tests := map[string]struct {
ImportPath string
Kvs map[string]string
want string
}{
"t1": {
ImportPath: "github.com/foo/bar/provenance",
Kvs: map[string]string{"fruit": "apple", "animal": "dog"},
want: `-s -w ` +
`-X github.com/foo/bar/provenance.fruit=apple ` +
`-X github.com/foo/bar/provenance.animal=dog`,
},
}
for name, tc := range tests {
t.Run(name, func(t *testing.T) {
ldv := &LdVars{
ImportPath: tc.ImportPath,
Kvs: tc.Kvs,
}
assert.Equalf(t, tc.want, ldv.MakeLdFlags(), "MakeLdFlags()")
})
}
}
70 changes: 52 additions & 18 deletions releasing/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,18 @@ import (
"github.com/monopole/mdrip/releasing/internal"
)

// This builds and releases a module to github.
// - While running, the process's working directory must be the
// same as the repo from which code is being released.
// - The repo should have one go.mod at the top; that's what's being released.
// - The desired release tag should have already been applied.
// This builds and releases a Go module to GitHub and dockerhub.
//
// In the old days I'd have done this with bash. Here I'm using Go
// since to make life easier and do a better job.
//
// While running, the process's working directory must be the
// same as the top of the repo from which code is being released.
// Further, the repo should have one go.mod at the top; that's what's
// being released.
//
// The desired release tag should have already been applied
// to the local repo.
func main() {
if os.Getenv("GH_TOKEN") == "" {
log.Fatal("GH_TOKEN not defined, so the gh tool won't work.")
Expand All @@ -30,6 +37,10 @@ func main() {
if !filepath.IsAbs(dirSrc) {
log.Fatal(dirSrc + " is not an absolute path.")
}
doIt(dirSrc)
}

func doIt(dirSrc string) {
var (
tag, commit, dirOut string
err error
Expand All @@ -56,10 +67,29 @@ func main() {
if err != nil {
log.Fatal(err)
}
assets, err = buildReleaseAssets(dirSrc, dirOut, tag, commit)
buildDate := time.Now().UTC()

ldVars := &internal.LdVars{
ImportPath: "github.com/monopole/mdrip/v2/internal/provenance",
Kvs: map[string]string{
"version": tag,
"gitCommit": commit,
"buildDate": buildDate.Format(time.RFC3339),
},
}
err = buildDockerImage(dirSrc, dirOut, ldVars)
if err != nil {
log.Fatal(err)
}

if stop := true; stop {
return
}
assets, err = buildReleaseAssetsForGitHub(dirSrc, dirOut, ldVars)
if err != nil {
log.Fatal(err)
}

gh := internal.NewGithubRunner(internal.DoIt, dirSrc, 3*time.Minute)
if err = gh.Release(tag, assets); err != nil {
slog.Error(gh.Out())
Expand Down Expand Up @@ -95,18 +125,9 @@ func findTag(git *internal.GitRunner) (string, string, error) {
return tag, commitHead, err
}

func buildReleaseAssets(
dirSrc, dirOut, tag, commitHash string) ([]string, error) {
goBuilder := internal.NewGoBuilder(
dirSrc, dirOut,
&internal.LdVars{
ImportPath: "github.com/monopole/mdrip/v2/internal/provenance",
Kvs: map[string]string{
"version": tag,
"gitCommit": commitHash,
"buildDate": time.Now().UTC().Format(time.RFC3339),
},
})
func buildReleaseAssetsForGitHub(
dirSrc, dirOut string, ldVars *internal.LdVars) ([]string, error) {
goBuilder := internal.NewGoBuilder(dirSrc, dirOut, ldVars)
var assetPaths []string
for _, pair := range []struct {
myOs internal.EnumOs
Expand All @@ -127,3 +148,16 @@ func buildReleaseAssets(
}
return assetPaths, nil
}

func buildDockerImage(
dirSrc, dirOut string, ldVars *internal.LdVars) error {
docker := internal.NewDockerRunner(dirSrc, dirOut, ldVars)

if err := docker.Login(); err != nil {
return err
}
if err := docker.Build(); err != nil {
return err
}
return docker.Push()
}

0 comments on commit 09980e1

Please sign in to comment.