Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 12 additions & 32 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
# Use a golang alpine as the base image
FROM public.ecr.aws/docker/library/golang:1.23.3-alpine3.20 as go_builder
FROM public.ecr.aws/docker/library/golang:1.25.1-alpine3.22 AS go_builder
RUN apk update
RUN apk add make cmake git alpine-sdk

ENV CGO_ENABLED=1 GOOS=linux
# Setup

# Read arguments
Expand All @@ -11,59 +11,39 @@ ARG VERSION_TAG
ARG GIT_COMMIT
ARG COMMIT_DATE
ARG BUILD_DATE

ARG DIRTY
# Set env variables
ENV COMMIT_DATE=$COMMIT_DATE
ENV SERVICE=$SERVICE
ENV GIT_COMMIT=$GIT_COMMIT
ENV VERSION_TAG=$VERSION_TAG
ENV BUILD_DATE=$BUILD_DATE
ENV DIRTY=$DIRTY
RUN echo "building service: ${SERVICE}"
RUN echo "version: ${VERSION_TAG}"
RUN echo "git commit: ${GIT_COMMIT}"
RUN echo "commit date: ${COMMIT_DATE}"
RUN echo "compilation date: ${BUILD_DATE}"
RUN echo "dirty build: ${DIRTY}"

# Set the working directory
WORKDIR /
COPY . .

# Build
RUN make gobuild

# Create linux svcuser
RUN mkdir /build/etc && \
echo "svcuser:x:1010:1010::/sbin/nologin:/bin/false" > /build/etc/passwd && \
echo "macuser:x:501:20::/sbin/nologin:/bin/false" >> /build/etc/passwd && \
echo "linuxuser:x:1000:1000::/sbin/nologin:/bin/false" >> /build/etc/passwd && \
echo "root:x:0:0:root:/sbin/nologin:/bin/false" >> /build/etc/passwd && \
echo "svcgroup:x:1010:svcuser" > /build/etc/group && \
echo "macgroup:x:20:macuser" >> /build/etc/group && \
echo "linuxgroup:x:1000:linuxuser" >> /build/etc/group && \
echo "root:x:0:root" >> /build/etc/group && \
mkdir /build/config && \
chown -R 1010:1010 /build/config

RUN make build

############################################################################################################

#SSL certs
FROM alpine as certs
RUN apk add --no-cache ca-certificates

############################################################################################################


# Copy binary to a scratch container. Let's keep our images nice and small!
FROM scratch
COPY --from=go_builder /build .
COPY --from=certs /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/
# Copy binary to a fresh alpine container. Let's keep our images nice and small!
FROM alpine:3.22
RUN adduser -D -H -u 1010 svcuser && apk add --no-cache ca-certificates
COPY --from=go_builder /build/checkout /checkout
COPY LICENSE ./
# Set User
USER svcuser
# Expose the port your application will run on
EXPOSE 8000

# Expose the default application port
EXPOSE 8080
# Run the binary
ENTRYPOINT ["/checkout"]

33 changes: 23 additions & 10 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,34 @@

# Build folder
BUILD_FOLDER = build
COVERAGE_BUILD_FOLDER ?= $(BUILD_FOLDER)/coverage
UNIT_COVERAGE_OUT ?= $(COVERAGE_BUILD_FOLDER)/ut_cov.out
BIN ?= $(BUILD_FOLDER)/checkout

# Packages
PKG ?= github.com/ATMackay/checkout
CONSTANTS_PKG ?= $(PKG)/constants

# Test coverage variables
COVERAGE_BUILD_FOLDER = $(BUILD_FOLDER)/coverage
UNIT_COVERAGE_OUT = $(COVERAGE_BUILD_FOLDER)/ut_cov.out

# Git based version
VERSION_TAG ?= $(shell git describe --tags)
GIT_COMMIT ?= $(shell git rev-parse HEAD)
BUILD_DATE ?= $(shell date -u +'%Y-%m-%d %H:%M:%S')
COMMIT_DATE ?= $(shell git show -s --format="%ci" $(shell git rev-parse HEAD))
VERSION_TAG ?= $(shell git describe --tags)
GIT_COMMIT ?= $(shell git rev-parse HEAD)
BUILD_DATE ?= $(shell date -u +'%Y-%m-%d %H:%M:%S')
COMMIT_DATE ?= $(shell git show -s --format="%ci" $(shell git rev-parse HEAD))
DIRTY ?= false

LDFLAGS := -s -w \
-X '$(CONSTANTS_PKG).Version=$(VERSION_TAG)' \
-X '$(CONSTANTS_PKG).CommitDate=$(COMMIT_DATE)' \
-X '$(CONSTANTS_PKG).GitCommit=$(GIT_COMMIT)' \
-X '$(CONSTANTS_PKG).BuildDate=$(BUILD_DATE)' \
-X '$(CONSTANTS_PKG).Dirty=$(DIRTY)'

build:
@GO111MODULE=on go build -o $(BUILD_FOLDER)/checkout \
-ldflags=" -X 'github.com/ATMackay/checkout/constants.Version=$(VERSION_TAG)' -X 'github.com/ATMackay/checkout/constants.CommitDate=$(COMMIT_DATE)' -X 'github.com/ATMackay/checkout/constants.BuildDate=$(BUILD_DATE)' -X 'github.com/ATMackay/checkout/constants.GitCommit=$(GIT_COMMIT)'"
@echo "Checkout server successfully built. To run the application execute './$(BUILD_FOLDER)/checkout run'"
@mkdir -p build
@echo ">> building $(BIN) (version=$(VERSION_TAG) commit=$(GIT_COMMIT) dirty=$(DIRTY))"
GO111MODULE=on go build -ldflags "$(LDFLAGS)" -o $(BIN)
@echo "Checkout server successfully built. To run the application execute './$(BIN) run'"

run: build
@./$(BUILD_FOLDER)/checkout run --memory-db
Expand Down
76 changes: 59 additions & 17 deletions build-docker.sh
Original file line number Diff line number Diff line change
@@ -1,22 +1,64 @@
#!/usr/bin/env bash

set -e

commit_hash=$(git rev-parse HEAD)
commit_hash_short=$(git rev-parse --short HEAD)
commit_timestamp=$(git show -s --format="%ci" ${commit_hash})
version_tag=$(git describe --tags)
build_date=$(date -u +'%Y-%m-%d %H:%M:%S')

docker build \
--build-arg SERVICE=checkout \
--build-arg GIT_COMMIT="$commit_hash" \
--build-arg COMMIT_DATE="$commit_timestamp" \
--build-arg VERSION_TAG="$version_tag" \
--build-arg BUILD_DATE="$build_date" \
-t checkout:latest \
-t checkout:"$commit_hash_short" \
-f Dockerfile .
#!/usr/bin/env bash
set -Eeuo pipefail

IMAGE_NAME=${IMAGE_NAME:-checkout}
SERVICE=${SERVICE:-checkout}

# Git info
commit_hash="$(git rev-parse HEAD)"
commit_hash_short="$(git rev-parse --short=12 HEAD)"
commit_timestamp="$(git show -s --format=%cI "${commit_hash}")"
build_date="$(date -u +%Y-%m-%dT%H:%M:%SZ)"

# Base tag from Git
base_tag="$(git describe --tags --abbrev=0 --match 'v*' 2>/dev/null)"

# Dirty detection: non-empty output -> dirty
if [[ -n "$(git status --porcelain)" ]]; then
dirty="true"
version_tag="${base_tag}-dirty-${commit_hash_short}-$(date -u +%Y%m%d%H%M)"
tags=( "${IMAGE_NAME}:${version_tag}" ) # no :latest for dirty images
else
dirty="false"
version_tag="${base_tag}"
tags=( "${IMAGE_NAME}:${version_tag}" "${IMAGE_NAME}:${commit_hash_short}" "${IMAGE_NAME}:latest" )
fi

echo ">> version_tag=${version_tag}"
echo ">> commit=${commit_hash}"
echo ">> dirty=${dirty}"
echo ">> build_date=${build_date}"

# Build args (propagated into your Makefile's -ldflags via Dockerfile)
build_args="\
--build-arg SERVICE=${SERVICE} \
--build-arg GIT_COMMIT=${commit_hash} \
--build-arg COMMIT_DATE=${commit_timestamp} \
--build-arg VERSION_TAG=${version_tag} \
--build-arg BUILD_DATE=${build_date} \
--build-arg DIRTY=${dirty} \
"

# Primary tag = first in the list
set -- $tags
primary_tag="$1"

# Build image
echo ">> docker build -t $primary_tag $build_args -f Dockerfile ."
docker build -t "$primary_tag" $build_args -f Dockerfile .

# Apply the remaining tags
shift
for t in "$@"; do
docker tag "$primary_tag" "$t"
done

echo ">> Built tags:"
for t in $tags; do
echo " $t"
done

# Remove intermediate Docker layers
docker image prune -f
4 changes: 4 additions & 0 deletions cmd/cmd_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,7 @@ func Test_CheckoutCMD(t *testing.T) {
c := NewCheckoutCmd()
require.Len(t, c.Commands(), 2)
}

func Test_BuildDirty(t *testing.T) {
require.False(t, buildDirty())
}
3 changes: 1 addition & 2 deletions cmd/logging_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,7 @@ func Test_Logger(t *testing.T) {
for _, format := range format {
for _, tc := range tests {
t.Run(tc.name+format, func(t *testing.T) {
err := initLogging(tc.levelStr, format)
if (err != nil) != tc.expectErr {
if err := initLogging(tc.levelStr, format); (err != nil) != tc.expectErr {
t.Errorf("unexpected error %v", err)
}
})
Expand Down
7 changes: 7 additions & 0 deletions cmd/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"os"
"os/signal"
"path/filepath"
"strings"

"github.com/ATMackay/checkout/constants"
"github.com/ATMackay/checkout/database"
Expand Down Expand Up @@ -67,6 +68,10 @@ func NewRunCmd() *cobra.Command {
"commit", constants.GitCommit,
"version", constants.Version,
)
if buildDirty() {
// Warn if the build contains uncommitted changes
slog.Warn("running a DIRTY build (uncommitted changes present) — do not run in production")
}
svc.Start()

sigChan := make(chan os.Signal, 1)
Expand Down Expand Up @@ -127,3 +132,5 @@ func NewRunCmd() *cobra.Command {
viper.AutomaticEnv() // Automatically read environment variables
return cmd
}

func buildDirty() bool { return strings.EqualFold(constants.Dirty, "true") }
3 changes: 3 additions & 0 deletions cmd/version.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ func VersionCmd() *cobra.Command {
fmt.Println("git commit sha:", constants.GitCommit)
fmt.Println("commit timestamp:", constants.CommitDate)
fmt.Println("compilation date:", constants.BuildDate)
if buildDirty() {
fmt.Println("git tree DIRTY (uncommitted changes in build).")
}
return nil
},
}
Expand Down
1 change: 1 addition & 0 deletions constants/version.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,5 @@ var (
CommitDate = "" // overwritten by -ldflag "-X 'github.com/ATMackay/checkout/constants.CommitDate=$commit_date'"
GitCommit = "" // overwritten by -ldflag "-X 'github.com/ATMackay/checkout/constants.GitCommit=$commit_hash'"
BuildDate = "" // overwritten by -ldflag "-X 'github.com/ATMackay/checkout/constants.BuildDate=$build_date'"
Dirty = "false" // overwritten by -ldflag "-X 'github.com/ATMackay/checkout/constants.Dirty=$dirty'"
)