diff --git a/.github/workflows/docker-publish.yml b/.github/workflows/docker-publish.yml index 4da4ba7..84bf372 100644 --- a/.github/workflows/docker-publish.yml +++ b/.github/workflows/docker-publish.yml @@ -46,12 +46,23 @@ jobs: type=sha,format=short flavor: latest=auto + - name: Build date + id: date + run: echo "value=$(date -u +%Y-%m-%dT%H:%M:%SZ)" >> "$GITHUB_OUTPUT" + - name: Build and push uses: docker/build-push-action@v6 with: context: . file: ${{ matrix.dockerfile }} push: true + # Stamps internal/version so `ignis -version` reports the release. + # meta.version is the tag without the leading v (0.5.0), matching + # the published image tag. + build-args: | + VERSION=${{ steps.meta.outputs.version }} + COMMIT=${{ github.sha }} + DATE=${{ steps.date.outputs.value }} tags: ${{ steps.meta.outputs.tags }} labels: ${{ steps.meta.outputs.labels }} cache-from: type=gha,scope=${{ matrix.name }} diff --git a/cmd/build_db/main.go b/cmd/build_db/main.go index 8f67023..3909a90 100644 --- a/cmd/build_db/main.go +++ b/cmd/build_db/main.go @@ -6,6 +6,7 @@ import ( "github.com/thd-spatial-ai/ignis/internal/config" importer "github.com/thd-spatial-ai/ignis/internal/db" "github.com/thd-spatial-ai/ignis/internal/utils" + "github.com/thd-spatial-ai/ignis/internal/version" "log" "time" @@ -16,6 +17,7 @@ func main() { startTime := time.Now() fmt.Println("============================================================") fmt.Println("=== ignis Database Rebuild Tool ===") + fmt.Printf("=== %s\n", version.String()) fmt.Println("============================================================") fmt.Println("") diff --git a/cmd/ignis/main.go b/cmd/ignis/main.go index 260ed23..a4a7222 100644 --- a/cmd/ignis/main.go +++ b/cmd/ignis/main.go @@ -11,10 +11,6 @@ import ( "github.com/thd-spatial-ai/ignis/internal/version" ) -func versionString() string { - return fmt.Sprintf("%s (commit %s, built %s)", version.Version, version.Commit, version.Date) -} - // parseVersionFlag reports whether args request the version string, so the // flag-handling decision can be tested without starting a server or exiting. func parseVersionFlag(args []string) bool { @@ -28,7 +24,7 @@ func parseVersionFlag(args []string) bool { // Setup app server and routes func main() { if parseVersionFlag(os.Args[1:]) { - fmt.Println(versionString()) + fmt.Println(version.String()) os.Exit(0) } diff --git a/cmd/ignis/main_test.go b/cmd/ignis/main_test.go index 7f57ee6..d85d794 100644 --- a/cmd/ignis/main_test.go +++ b/cmd/ignis/main_test.go @@ -1,21 +1,9 @@ package main import ( - "strings" "testing" - - "github.com/thd-spatial-ai/ignis/internal/version" ) -func TestVersionString(t *testing.T) { - got := versionString() - for _, want := range []string{version.Version, version.Commit, version.Date} { - if !strings.Contains(got, want) { - t.Errorf("versionString() = %q, want it to contain %q", got, want) - } - } -} - func TestParseVersionFlag(t *testing.T) { cases := map[string][]string{ "no flags": {}, diff --git a/environment/ignis-app.dockerfile b/environment/ignis-app.dockerfile index 6eb8c3e..08681c6 100644 --- a/environment/ignis-app.dockerfile +++ b/environment/ignis-app.dockerfile @@ -13,10 +13,21 @@ COPY go.mod go.sum ./ RUN go mod download COPY . . +# Passed by the publish workflow on a tag build; default to the same values +# internal/version hard-codes, so a plain `docker build` is unchanged. +ARG VERSION=dev +ARG COMMIT=none +ARG DATE=unknown # -buildvcs=false: the build context may contain .git, and the toolchain's # VCS stamping shells out to git, which fails on an ownership mismatch in CI. # The image is identified by its release tag, so the stamp buys nothing. -RUN CGO_ENABLED=0 go build -buildvcs=false -o /out/ignis ./cmd/ignis +# -X: same three variables release.yml stamps into the standalone binaries. +RUN CGO_ENABLED=0 go build -buildvcs=false \ + -ldflags="-s -w \ + -X github.com/thd-spatial-ai/ignis/internal/version.Version=${VERSION} \ + -X github.com/thd-spatial-ai/ignis/internal/version.Commit=${COMMIT} \ + -X github.com/thd-spatial-ai/ignis/internal/version.Date=${DATE}" \ + -o /out/ignis ./cmd/ignis # --------------------------------------------------------------------------- # Stage 2: final — only the compiled server binary, no compiler/source/git diff --git a/environment/ignis-db.dockerfile b/environment/ignis-db.dockerfile index 4f38508..3bfbf05 100644 --- a/environment/ignis-db.dockerfile +++ b/environment/ignis-db.dockerfile @@ -17,7 +17,17 @@ COPY go.mod go.sum ./ RUN go mod download COPY . . -RUN CGO_ENABLED=0 go build -buildvcs=false -o /out/build_db ./cmd/build_db +# Passed by the publish workflow on a tag build; default to the same values +# internal/version hard-codes, so a plain `docker build` is unchanged. +ARG VERSION=dev +ARG COMMIT=none +ARG DATE=unknown +RUN CGO_ENABLED=0 go build -buildvcs=false \ + -ldflags="-s -w \ + -X github.com/thd-spatial-ai/ignis/internal/version.Version=${VERSION} \ + -X github.com/thd-spatial-ai/ignis/internal/version.Commit=${COMMIT} \ + -X github.com/thd-spatial-ai/ignis/internal/version.Date=${DATE}" \ + -o /out/build_db ./cmd/build_db # --------------------------------------------------------------------------- # Stage 2: final — compiled binary + the trimmed TABULA workbook baked in. diff --git a/internal/version/version.go b/internal/version/version.go index 155cee9..803b0b0 100644 --- a/internal/version/version.go +++ b/internal/version/version.go @@ -1,7 +1,17 @@ package version +import "fmt" + var ( Version = "dev" Commit = "none" Date = "unknown" ) + +// String renders the build's version, commit and date on one line. +// The three vars are set at link time by -ldflags -X (see release.yml and +// the environment/*.dockerfile builds); an unstamped build reports the +// hard-coded defaults. +func String() string { + return fmt.Sprintf("%s (commit %s, built %s)", Version, Commit, Date) +} diff --git a/internal/version/version_test.go b/internal/version/version_test.go new file mode 100644 index 0000000..eba6902 --- /dev/null +++ b/internal/version/version_test.go @@ -0,0 +1,15 @@ +package version + +import ( + "strings" + "testing" +) + +func TestString(t *testing.T) { + got := String() + for _, want := range []string{Version, Commit, Date} { + if !strings.Contains(got, want) { + t.Errorf("String() = %q, want it to contain %q", got, want) + } + } +}