build: add enhanced information (#2067)

This commit adjusts the build flags to include version information in the LDFLAGS using the -X options. Additionally this makes the information recorded at build time more comprehensive. All build information can now be obtained via the `authelia build` command, and the `authelia version` command is now `authelia --version`. Lastly this adjusts the Dockerfile to utilize docker cache more effectively.
This commit is contained in:
James Elliott 2021-06-18 14:35:43 +10:00 committed by GitHub
parent ef3c2faeb5
commit 0d7b33022c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
20 changed files with 418 additions and 88 deletions

View File

@ -3,22 +3,27 @@
# ======================================= # =======================================
FROM golang:1.16.5-alpine AS builder-backend FROM golang:1.16.5-alpine AS builder-backend
ARG BUILD_TAG
ARG BUILD_COMMIT
WORKDIR /go/src/app WORKDIR /go/src/app
RUN \
echo ">> Downloading required apk's..." && \
apk --no-cache add gcc musl-dev
COPY go.mod go.sum ./
RUN \
echo ">> Downloading go modules..." && \
go mod download
COPY / ./ COPY / ./
ARG LDFLAGS_EXTRA
# CGO_ENABLED=1 is required for building go-sqlite3 # CGO_ENABLED=1 is required for building go-sqlite3
RUN \ RUN \
apk --no-cache add gcc musl-dev && \
go mod download && \
mv public_html internal/server/public_html && \ mv public_html internal/server/public_html && \
echo "Write tag ${BUILD_TAG} and commit ${BUILD_COMMIT} in binary." && \ echo ">> Starting go build..." && \
sed -i "s/__BUILD_TAG__/${BUILD_TAG}/" cmd/authelia/constants.go && \ GOOS=linux GOARCH=amd64 CGO_ENABLED=1 go build -tags netgo \
sed -i "s/__BUILD_COMMIT__/${BUILD_COMMIT}/" cmd/authelia/constants.go && \ -ldflags "-s -w -linkmode external ${LDFLAGS_EXTRA} -extldflags -static" -trimpath -o authelia ./cmd/authelia
GOOS=linux GOARCH=amd64 CGO_ENABLED=1 go build -tags netgo -ldflags '-s -w -linkmode external -extldflags -static' -trimpath -o authelia ./cmd/authelia
# =================================== # ===================================
# ===== Authelia official image ===== # ===== Authelia official image =====

View File

@ -3,25 +3,30 @@
# ======================================= # =======================================
FROM golang:1.16.5-alpine AS builder-backend FROM golang:1.16.5-alpine AS builder-backend
ARG BUILD_TAG
ARG BUILD_COMMIT
ARG CC_VERSION="v15"
WORKDIR /go/src/app WORKDIR /go/src/app
# CGO_ENABLED=1 and gcc cross-compiler is required for building go-sqlite3
ARG CC_VERSION="v15"
RUN \
echo ">> Downloading required apk's..." && \
apk --no-cache add curl && \
echo ">> Downloading cross-compiler..." && \
curl -Lfs "https://github.com/just-containers/musl-cross-make/releases/download/${CC_VERSION}/gcc-9.2.0-arm-linux-musleabihf.tar.xz" | tar -xJ --directory /
COPY go.mod go.sum ./
RUN \
echo ">> Downloading go modules..." && \
go mod download
COPY / ./ COPY / ./
# CGO_ENABLED=1 and gcc cross-compiler is required for building go-sqlite3 ARG LDFLAGS_EXTRA
RUN \ RUN \
apk --no-cache add curl && \
curl -Lfs -o /tmp/gcc-9.2.0-arm-linux-musleabihf.tar.xz "https://github.com/just-containers/musl-cross-make/releases/download/${CC_VERSION}/gcc-9.2.0-arm-linux-musleabihf.tar.xz" && \
tar xf /tmp/gcc-9.2.0-arm-linux-musleabihf.tar.xz -C / && \
go mod download && \
mv public_html internal/server/public_html && \ mv public_html internal/server/public_html && \
echo "Write tag ${BUILD_TAG} and commit ${BUILD_COMMIT} in binary." && \ echo ">> Starting go build..." && \
sed -i "s/__BUILD_TAG__/${BUILD_TAG}/" cmd/authelia/constants.go && \ GOOS=linux GOARCH=arm CGO_ENABLED=1 CC=arm-linux-musleabihf-gcc CGO_LDFLAGS=-fuse-ld=bfd go build -tags netgo \
sed -i "s/__BUILD_COMMIT__/${BUILD_COMMIT}/" cmd/authelia/constants.go && \ -ldflags "-s -w -linkmode external ${LDFLAGS_EXTRA} -extldflags -static" -trimpath -o authelia ./cmd/authelia
GOOS=linux GOARCH=arm CGO_ENABLED=1 CC=arm-linux-musleabihf-gcc CGO_LDFLAGS=-fuse-ld=bfd go build -tags netgo -ldflags '-s -w -linkmode external -extldflags -static' -trimpath -o authelia ./cmd/authelia
# =================================== # ===================================
# ===== Authelia official image ===== # ===== Authelia official image =====
@ -32,8 +37,9 @@ WORKDIR /app
COPY ./qemu-arm-static /usr/bin/qemu-arm-static COPY ./qemu-arm-static /usr/bin/qemu-arm-static
RUN apk --no-cache add ca-certificates su-exec tzdata && \ RUN \
rm /usr/bin/qemu-arm-static apk --no-cache add ca-certificates su-exec tzdata && \
rm /usr/bin/qemu-arm-static
COPY --from=builder-backend /go/src/app/authelia /go/src/app/LICENSE /go/src/app/entrypoint.sh /go/src/app/healthcheck.sh ./ COPY --from=builder-backend /go/src/app/authelia /go/src/app/LICENSE /go/src/app/entrypoint.sh /go/src/app/healthcheck.sh ./

View File

@ -3,25 +3,31 @@
# ======================================= # =======================================
FROM golang:1.16.5-alpine AS builder-backend FROM golang:1.16.5-alpine AS builder-backend
ARG BUILD_TAG
ARG BUILD_COMMIT
ARG CC_VERSION="v15"
WORKDIR /go/src/app WORKDIR /go/src/app
# CGO_ENABLED=1 and gcc cross-compiler is required for building go-sqlite3
ARG CC_VERSION="v15"
RUN \
echo ">> Downloading required apk's..." && \
apk --no-cache add curl && \
echo ">> Downloading cross-compiler..." && \
curl -Lfs "https://github.com/just-containers/musl-cross-make/releases/download/${CC_VERSION}/gcc-9.2.0-aarch64-linux-musl.tar.xz" | tar -xJ --directory /
COPY go.mod go.sum ./
RUN \
echo ">> Downloading go modules..." && \
go mod download
COPY / ./ COPY / ./
# CGO_ENABLED=1 and gcc cross-compiler is required for building go-sqlite3 ARG LDFLAGS_EXTRA
RUN \ RUN \
apk --no-cache add curl && \
curl -Lfs -o /tmp/gcc-9.2.0-aarch64-linux-musl.tar.xz "https://github.com/just-containers/musl-cross-make/releases/download/${CC_VERSION}/gcc-9.2.0-aarch64-linux-musl.tar.xz" && \
tar xf /tmp/gcc-9.2.0-aarch64-linux-musl.tar.xz -C / && \
go mod download && \
mv public_html internal/server/public_html && \ mv public_html internal/server/public_html && \
echo "Write tag ${BUILD_TAG} and commit ${BUILD_COMMIT} in binary." && \ echo ">> Starting go build..." && \
sed -i "s/__BUILD_TAG__/${BUILD_TAG}/" cmd/authelia/constants.go && \ GOOS=linux GOARCH=arm64 CGO_ENABLED=1 CC=aarch64-linux-musl-gcc CGO_LDFLAGS=-fuse-ld=bfd go build -tags netgo -ldflags \
sed -i "s/__BUILD_COMMIT__/${BUILD_COMMIT}/" cmd/authelia/constants.go && \ "-s -w -linkmode external ${LDFLAGS_EXTRA} -extldflags -static" \
GOOS=linux GOARCH=arm64 CGO_ENABLED=1 CC=aarch64-linux-musl-gcc CGO_LDFLAGS=-fuse-ld=bfd go build -tags netgo -ldflags '-s -w -linkmode external -extldflags -static' -trimpath -o authelia ./cmd/authelia -trimpath -o authelia ./cmd/authelia
# =================================== # ===================================
# ===== Authelia official image ===== # ===== Authelia official image =====
@ -32,8 +38,9 @@ WORKDIR /app
COPY ./qemu-aarch64-static /usr/bin/qemu-aarch64-static COPY ./qemu-aarch64-static /usr/bin/qemu-aarch64-static
RUN apk --no-cache add ca-certificates su-exec tzdata && \ RUN \
rm /usr/bin/qemu-aarch64-static apk --no-cache add ca-certificates su-exec tzdata && \
rm /usr/bin/qemu-aarch64-static
COPY --from=builder-backend /go/src/app/authelia /go/src/app/LICENSE /go/src/app/entrypoint.sh /go/src/app/healthcheck.sh ./ COPY --from=builder-backend /go/src/app/authelia /go/src/app/LICENSE /go/src/app/entrypoint.sh /go/src/app/healthcheck.sh ./

View File

@ -4,7 +4,8 @@
FROM node:16-alpine AS builder-frontend FROM node:16-alpine AS builder-frontend
WORKDIR /node/src/app WORKDIR /node/src/app
COPY web .
COPY web ./
# Install the dependencies and build # Install the dependencies and build
RUN yarn install --frozen-lockfile && INLINE_RUNTIME_CHUNK=false yarn coverage RUN yarn install --frozen-lockfile && INLINE_RUNTIME_CHUNK=false yarn coverage
@ -14,26 +15,30 @@ RUN yarn install --frozen-lockfile && INLINE_RUNTIME_CHUNK=false yarn coverage
# ======================================= # =======================================
FROM golang:1.16.5-alpine AS builder-backend FROM golang:1.16.5-alpine AS builder-backend
ARG BUILD_TAG
ARG BUILD_COMMIT
WORKDIR /go/src/app WORKDIR /go/src/app
# gcc and musl-dev are required for building go-sqlite3
RUN \
echo ">> Downloading required apk's..." && \
apk --no-cache add gcc musl-dev
COPY go.mod go.sum ./
RUN \
echo ">> Downloading go modules..." && \
go mod download
COPY / ./ COPY / ./
# Prepare static files to be embedded in Go binary # Prepare static files to be embedded in Go binary
COPY --from=builder-frontend /node/src/app/build internal/server/public_html COPY --from=builder-frontend /node/src/app/build internal/server/public_html
# gcc and musl-dev are required for building go-sqlite3 ARG LDFLAGS_EXTRA
RUN \ RUN \
apk --no-cache add gcc musl-dev && \
go mod download && \
mv api internal/server/public_html/api && \ mv api internal/server/public_html/api && \
echo "Write tag ${BUILD_TAG} and commit ${BUILD_COMMIT} in binary." && \
sed -i "s/__BUILD_TAG__/${BUILD_TAG}/" cmd/authelia/constants.go && \
sed -i "s/__BUILD_COMMIT__/${BUILD_COMMIT}/" cmd/authelia/constants.go && \
cd cmd/authelia && \ cd cmd/authelia && \
go test -c --tags coverage -covermode=atomic -o authelia -coverpkg github.com/authelia/authelia/... echo ">> Starting go build (coverage via go test)..." && \
go test -c --tags coverage -covermode=atomic -ldflags "${LDFLAGS_EXTRA}" -o authelia -coverpkg github.com/authelia/authelia/...
# =================================== # ===================================
# ===== Authelia official image ===== # ===== Authelia official image =====

View File

@ -2,6 +2,7 @@ package main
import ( import (
"os" "os"
"strings"
log "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus"
"github.com/spf13/cobra" "github.com/spf13/cobra"
@ -9,8 +10,8 @@ import (
"github.com/authelia/authelia/internal/utils" "github.com/authelia/authelia/internal/utils"
) )
func buildAutheliaBinary() { func buildAutheliaBinary(xflags []string) {
cmd := utils.CommandWithStdout("go", "build", "-o", "../../"+OutputDir+"/authelia") cmd := utils.CommandWithStdout("go", "build", "-o", "../../"+OutputDir+"/authelia", "-ldflags", strings.Join(xflags, " "))
cmd.Dir = "cmd/authelia" cmd.Dir = "cmd/authelia"
cmd.Env = append(os.Environ(), cmd.Env = append(os.Environ(),
@ -109,8 +110,13 @@ func Build(cobraCmd *cobra.Command, args []string) {
Clean(cobraCmd, args) Clean(cobraCmd, args)
xflags, err := getXFlags("", "0", "")
if err != nil {
log.Fatal(err)
}
log.Debug("Creating `" + OutputDir + "` directory") log.Debug("Creating `" + OutputDir + "` directory")
err := os.MkdirAll(OutputDir, os.ModePerm) err = os.MkdirAll(OutputDir, os.ModePerm)
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
@ -123,6 +129,6 @@ func Build(cobraCmd *cobra.Command, args []string) {
buildSwagger() buildSwagger()
log.Debug("Building Authelia Go binary...") log.Debug("Building Authelia Go binary...")
buildAutheliaBinary() buildAutheliaBinary(xflags)
cleanAssets() cleanAssets()
} }

View File

@ -82,24 +82,13 @@ func dockerBuildOfficialImage(arch string) error {
} }
} }
gitTag := ciTag flags, err := getXFlags(ciBranch, os.Getenv("BUILDKITE_BUILD_NUMBER"), "")
if gitTag == "" {
// If commit is not tagged, mark the build has having master tag.
gitTag = masterTag
}
cmd := utils.Shell("git rev-parse HEAD")
cmd.Stdout = nil
cmd.Stderr = nil
commitBytes, err := cmd.Output()
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
} }
commitHash := strings.Trim(string(commitBytes), "\n") return docker.Build(IntermediateDockerImageName, dockerfile, ".",
strings.Join(flags, " "))
return docker.Build(IntermediateDockerImageName, dockerfile, ".", gitTag, commitHash)
} }
// DockerBuildCmd Command for building docker image of Authelia. // DockerBuildCmd Command for building docker image of Authelia.

View File

@ -0,0 +1,39 @@
package main
import (
"fmt"
"strings"
log "github.com/sirupsen/logrus"
"github.com/spf13/cobra"
)
func init() {
xflagsCmd.Flags().StringP("build", "b", "0", "Sets the BuildNumber flag value")
xflagsCmd.Flags().StringP("extra", "e", "", "Sets the BuildExtra flag value")
}
var xflagsCmd = &cobra.Command{
Use: "xflags",
Run: runXFlags,
Short: "Generate X LDFlags for building Authelia",
}
func runXFlags(cobraCmd *cobra.Command, _ []string) {
build, err := cobraCmd.Flags().GetString("build")
if err != nil {
log.Fatal(err)
}
extra, err := cobraCmd.Flags().GetString("extra")
if err != nil {
log.Fatal(err)
}
flags, err := getXFlags("", build, extra)
if err != nil {
log.Fatal(err)
}
fmt.Println(strings.Join(flags, " "))
}

View File

@ -18,3 +18,5 @@ const masterTag = "master"
const stringFalse = "false" const stringFalse = "false"
const stringTrue = "true" const stringTrue = "true"
const webDirectory = "web" const webDirectory = "web"
const fmtLDFLAGSX = "-X 'github.com/authelia/authelia/internal/utils.%s=%s'"

View File

@ -8,10 +8,11 @@ import (
type Docker struct{} type Docker struct{}
// Build build a docker image. // Build build a docker image.
func (d *Docker) Build(tag, dockerfile, target, gitTag, gitCommit string) error { func (d *Docker) Build(tag, dockerfile, target, ldflags string) error {
return utils.CommandWithStdout( return utils.CommandWithStdout(
"docker", "build", "-t", tag, "-f", dockerfile, "--build-arg", "docker", "build", "-t", tag, "-f", dockerfile,
"BUILD_TAG="+gitTag, "--build-arg", "BUILD_COMMIT="+gitCommit, target).Run() "--build-arg", "LDFLAGS_EXTRA="+ldflags,
target).Run()
} }
// Tag tag a docker image. // Tag tag a docker image.

View File

@ -0,0 +1,67 @@
package main
import (
"fmt"
"strings"
"time"
"github.com/authelia/authelia/internal/utils"
)
func getXFlags(branch, build, extra string) (flags []string, err error) {
if branch == "" {
out, _, err := utils.RunCommandAndReturnOutput("git rev-parse --abbrev-ref HEAD")
if err != nil {
return flags, err
}
if out == "" {
branch = "master"
} else {
branch = out
}
}
gitTagCommit, _, err := utils.RunCommandAndReturnOutput("git rev-list --tags --max-count=1")
if err != nil {
return flags, err
}
tag, _, err := utils.RunCommandAndReturnOutput("git describe --tags --abbrev=0 " + gitTagCommit)
if err != nil {
return flags, err
}
commit, _, err := utils.RunCommandAndReturnOutput("git rev-parse HEAD")
if err != nil {
return flags, err
}
var states []string
if gitTagCommit == commit {
states = append(states, "tagged")
} else {
states = append(states, "untagged")
}
if _, exitCode, _ := utils.RunCommandAndReturnOutput("git diff --quiet"); exitCode != 0 {
states = append(states, "dirty")
} else {
states = append(states, "clean")
}
if build == "" {
build = "manual"
}
return []string{
fmt.Sprintf(fmtLDFLAGSX, "BuildBranch", branch),
fmt.Sprintf(fmtLDFLAGSX, "BuildTag", tag),
fmt.Sprintf(fmtLDFLAGSX, "BuildCommit", commit),
fmt.Sprintf(fmtLDFLAGSX, "BuildDate", time.Now().Format("Mon, 02 Jan 2006 15:04:05 -0700")),
fmt.Sprintf(fmtLDFLAGSX, "BuildState", strings.Join(states, " ")),
fmt.Sprintf(fmtLDFLAGSX, "BuildExtra", extra),
fmt.Sprintf(fmtLDFLAGSX, "BuildNumber", build),
}, nil
}

View File

@ -135,7 +135,7 @@ func main() {
cobraCommands = append(cobraCommands, command) cobraCommands = append(cobraCommands, command)
} }
cobraCommands = append(cobraCommands, commands.HashPasswordCmd, commands.CertificatesCmd, commands.RSACmd) cobraCommands = append(cobraCommands, commands.HashPasswordCmd, commands.CertificatesCmd, commands.RSACmd, xflagsCmd)
rootCmd.PersistentFlags().StringVar(&logLevel, "log-level", "info", "Set the log level for the command") rootCmd.PersistentFlags().StringVar(&logLevel, "log-level", "info", "Set the log level for the command")
rootCmd.AddCommand(cobraCommands...) rootCmd.AddCommand(cobraCommands...)

21
cmd/authelia/const.go Normal file
View File

@ -0,0 +1,21 @@
package main
const fmtAutheliaLong = `authelia %s
An open-source authentication and authorization server providing
two-factor authentication and single sign-on (SSO) for your
applications via a web portal.
Documentation is available at: https://www.authelia.com/docs
`
const fmtAutheliaBuild = `Last Tag: %s
State: %s
Branch: %s
Commit: %s
Build Number: %s
Build OS: %s
Build Arch: %s
Build Date: %s
Extra: %s
`

View File

@ -1,7 +0,0 @@
package main
// BuildTag tag used to bootstrap Authelia binary.
var BuildTag = "__BUILD_TAG__"
// BuildCommit commit used to bootstrap Authelia binary.
var BuildCommit = "__BUILD_COMMIT__"

View File

@ -3,6 +3,7 @@ package main
import ( import (
"fmt" "fmt"
"os" "os"
"runtime"
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
"github.com/spf13/cobra" "github.com/spf13/cobra"
@ -56,6 +57,8 @@ func startServer() {
logger.Fatalf("Cannot initialize logger: %v", err) logger.Fatalf("Cannot initialize logger: %v", err)
} }
logger.Infof("Authelia %s is starting", utils.Version())
switch config.Logging.Level { switch config.Logging.Level {
case "error": case "error":
logger.Info("Logging severity set to error") logger.Info("Logging severity set to error")
@ -145,24 +148,31 @@ func startServer() {
func main() { func main() {
logger := logging.Logger() logger := logging.Logger()
version := utils.Version()
rootCmd := &cobra.Command{ rootCmd := &cobra.Command{
Use: "authelia", Use: "authelia",
Run: func(cmd *cobra.Command, args []string) { Run: func(cmd *cobra.Command, args []string) {
startServer() startServer()
}, },
Version: version,
Short: fmt.Sprintf("authelia %s", version),
Long: fmt.Sprintf(fmtAutheliaLong, version),
} }
rootCmd.Flags().StringVar(&configPathFlag, "config", "", "Configuration file") rootCmd.Flags().StringVar(&configPathFlag, "config", "", "Configuration file")
versionCmd := &cobra.Command{ buildCmd := &cobra.Command{
Use: "version", Use: "build",
Short: "Show the version of Authelia", Short: "Show the build of Authelia",
Run: func(cmd *cobra.Command, args []string) { Run: func(cmd *cobra.Command, args []string) {
fmt.Printf("Authelia version %s, build %s\n", BuildTag, BuildCommit) fmt.Printf(fmtAutheliaBuild, utils.BuildTag, utils.BuildState, utils.BuildBranch, utils.BuildCommit,
utils.BuildNumber, runtime.GOOS, runtime.GOARCH, utils.BuildDate, utils.BuildExtra)
}, },
} }
rootCmd.AddCommand(versionCmd, commands.HashPasswordCmd, rootCmd.AddCommand(buildCmd, commands.HashPasswordCmd,
commands.ValidateConfigCmd, commands.CertificatesCmd, commands.ValidateConfigCmd, commands.CertificatesCmd,
commands.RSACmd) commands.RSACmd)

View File

@ -2,6 +2,7 @@ package suites
import ( import (
"os" "os"
"regexp"
"testing" "testing"
"github.com/stretchr/testify/suite" "github.com/stretchr/testify/suite"
@ -37,10 +38,25 @@ func (s *CLISuite) SetupTest() {
s.coverageArg = coverageArg s.coverageArg = coverageArg
} }
func (s *CLISuite) TestShouldPrintVersion() { func (s *CLISuite) TestShouldPrintBuildInformation() {
output, err := s.Exec("authelia-backend", []string{"authelia", s.testArg, s.coverageArg, "version"}) output, err := s.Exec("authelia-backend", []string{"authelia", s.testArg, s.coverageArg, "build"})
s.Assert().Nil(err) s.Assert().Nil(err)
s.Assert().Contains(output, "Authelia version") s.Assert().Contains(output, "Last Tag: ")
s.Assert().Contains(output, "State: ")
s.Assert().Contains(output, "Branch: ")
s.Assert().Contains(output, "Build Number: ")
s.Assert().Contains(output, "Build OS: ")
s.Assert().Contains(output, "Build Arch: ")
s.Assert().Contains(output, "Build Date: ")
r := regexp.MustCompile(`^Last Tag: v\d+\.\d+\.\d+\nState: (tagged|untagged) (clean|dirty)\nBranch: [^\s\n]+\nCommit: [0-9a-f]{40}\nBuild Number: \d+\nBuild OS: (linux|darwin|windows|freebsd)\nBuild Arch: (amd64|arm|arm64)\nBuild Date: (Sun|Mon|Tue|Wed|Thu|Fri|Sat), \d{2} (Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec) \d{4} \d{2}:\d{2}:\d{2} [+-]\d{4}\nExtra: \n`)
s.Assert().Regexp(r, output)
}
func (s *CLISuite) TestShouldPrintVersion() {
output, err := s.Exec("authelia-backend", []string{"authelia", s.testArg, s.coverageArg, "--version"})
s.Assert().Nil(err)
s.Assert().Contains(output, "authelia version")
} }
func (s *CLISuite) TestShouldValidateConfig() { func (s *CLISuite) TestShouldValidateConfig() {

View File

@ -39,6 +39,10 @@ const (
// Month is an int based representation of the time unit. // Month is an int based representation of the time unit.
Month = Year / 12 Month = Year / 12
clean = "clean"
tagged = "tagged"
unknown = "unknown"
) )
// ErrTimeoutReached error thrown when a timeout is reached. // ErrTimeoutReached error thrown when a timeout is reached.

View File

@ -44,6 +44,20 @@ func Shell(command string) *exec.Cmd {
return CommandWithStdout("bash", "-c", command) return CommandWithStdout("bash", "-c", command)
} }
// RunCommandAndReturnOutput runs a shell command then returns the stdout and the exit code.
func RunCommandAndReturnOutput(command string) (output string, exitCode int, err error) {
cmd := Shell(command)
cmd.Stdout = nil
cmd.Stderr = nil
outputBytes, err := cmd.Output()
if err != nil {
return "", cmd.ProcessState.ExitCode(), err
}
return strings.Trim(string(outputBytes), "\n"), cmd.ProcessState.ExitCode(), nil
}
// RunCommandUntilCtrlC run a command until ctrl-c is hit. // RunCommandUntilCtrlC run a command until ctrl-c is hit.
func RunCommandUntilCtrlC(cmd *exec.Cmd) { func RunCommandUntilCtrlC(cmd *exec.Cmd) {
mutex := sync.Mutex{} mutex := sync.Mutex{}

104
internal/utils/version.go Normal file
View File

@ -0,0 +1,104 @@
package utils
import (
"fmt"
"strings"
)
// BuildTag is replaced by LDFLAGS at build time with the latest tag at or before the current commit.
var BuildTag = "unknown"
// BuildState is replaced by LDFLAGS at build time with `tagged` or `untagged` depending on if the commit is tagged, and
// `clean` or `dirty` depending on the working tree state. For example if the commit was tagged and the working tree
// was dirty it would be "tagged dirty". This is used to determine the version string output mode.
var BuildState = "untagged dirty"
// BuildExtra is replaced by LDFLAGS at build time with a blank string by default. People porting Authelia can use this
// to add a suffix to their versions.
var BuildExtra = ""
// BuildDate is replaced by LDFLAGS at build time with the date the build started.
var BuildDate = ""
// BuildCommit is replaced by LDFLAGS at build time with the current commit.
var BuildCommit = "unknown"
// BuildBranch is replaced by LDFLAGS at build time with the current branch.
var BuildBranch = "master"
// BuildNumber is replaced by LDFLAGS at build time with the CI build number.
var BuildNumber = "0"
// Version returns the Authelia version.
//
// The format of the string is dependent on the values in BuildState. If tagged and clean are present it returns the
// BuildTag i.e. v1.0.0. If dirty and tagged are present it returns <BuildTag>-dirty. Otherwise the following is the
// format: untagged-<BuildTag>-dirty-<BuildExtra> (<BuildBranch>, <BuildCommit>).
//
func Version() (versionString string) {
return version(BuildTag, BuildState, BuildCommit, BuildBranch, BuildExtra)
}
func version(tag, state, commit, branch, extra string) (version string) {
b := strings.Builder{}
states := strings.Split(state, " ")
isClean := IsStringInSlice(clean, states)
isTagged := IsStringInSlice(tagged, states)
if isClean && isTagged {
b.WriteString(tag)
if extra != "" {
b.WriteRune('-')
b.WriteString(extra)
}
return b.String()
}
if isTagged && !isClean {
b.WriteString(tag)
b.WriteString("-dirty")
return b.String()
}
if !isTagged {
b.WriteString("untagged-")
}
b.WriteString(tag)
if !isClean {
b.WriteString("-dirty")
}
if extra != "" {
b.WriteRune('-')
b.WriteString(extra)
}
b.WriteString(fmt.Sprintf(" (%s, %s)", branch, commitShort(commit)))
return b.String()
}
func commitShort(commitLong string) (commit string) {
if commitLong == "" {
return unknown
}
b := strings.Builder{}
for i, r := range commitLong {
b.WriteRune(r)
if i >= 6 {
break
}
}
return b.String()
}

View File

@ -0,0 +1,41 @@
package utils
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestVersionDefault(t *testing.T) {
v := Version()
assert.Equal(t, "untagged-unknown-dirty (master, unknown)", v)
}
func TestVersion(t *testing.T) {
var v string
v = version("v4.90.0", "tagged clean", "50d8b4a941c26b89482c94ab324b5a274f9ced66", "master", "")
assert.Equal(t, "v4.90.0", v)
v = version("v4.90.0", "tagged clean", "50d8b4a941c26b89482c94ab324b5a274f9ced66", "master", "freshports")
assert.Equal(t, "v4.90.0-freshports", v)
v = version("v4.90.0", "tagged dirty", "50d8b4a941c26b89482c94ab324b5a274f9ced66", "master", "")
assert.Equal(t, "v4.90.0-dirty", v)
v = version("v4.90.0", "untagged dirty", "50d8b4a941c26b89482c94ab324b5a274f9ced66", "master", "")
assert.Equal(t, "untagged-v4.90.0-dirty (master, 50d8b4a)", v)
v = version("v4.90.0", "untagged clean", "50d8b4a941c26b89482c94ab324b5a274f9ced66", "master", "")
assert.Equal(t, "untagged-v4.90.0 (master, 50d8b4a)", v)
v = version("v4.90.0", "untagged clean", "50d8b4a941c26b89482c94ab324b5a274f9ced66", "master", "freshports")
assert.Equal(t, "untagged-v4.90.0-freshports (master, 50d8b4a)", v)
v = version("v4.90.0", "untagged clean", "", "master", "")
assert.Equal(t, "untagged-v4.90.0 (master, unknown)", v)
v = version("v4.90.0", "", "50d8b4a941c26b89482c94ab324b5a274f9ced66", "master", "")
assert.Equal(t, "untagged-v4.90.0-dirty (master, 50d8b4a)", v)
}