Skip to content
Open
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
15 changes: 15 additions & 0 deletions deployment/docker/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,21 @@ variables to the [Task][gotask] command:
* `DOCKER_RUNNER`: Define a different name for the runner image, defaults to `runner`
* `DOCKER_CMD`: Use another command to build the image, defaults to `docker`

## Customizing Version Information

If you are building downstream Docker images based on Semaphore and want to display your own version string in the Semaphore UI, you can use the `SEMAPHORE_BUILD_INFO` environment variable:

```console
# Set custom version info at runtime
docker run -e SEMAPHORE_BUILD_INFO="v2.14.9-mycompany-1.0.0" semaphoreui/semaphore:v2.14.9

# Or set it when building your own image
FROM semaphoreui/semaphore:v2.14.9
ENV SEMAPHORE_BUILD_INFO="v2.14.9-downstream-custom"
```

When `SEMAPHORE_BUILD_INFO` is set, it will override the default version display format (`{version}-{commit}-{date}`) in both the CLI and web UI. This is useful for downstream distributions that want to show their own version information to users.

## Test

We defined tasks to handle some linting and to verify the images contain the
Expand Down
76 changes: 76 additions & 0 deletions util/api_integration_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
package util

import (
"encoding/json"
"os"
"testing"
)

// TestAPIIntegration simulates how the API uses the Version() function
func TestAPIIntegration_Version(t *testing.T) {
// Test case 1: Default behavior (no environment variable)
os.Unsetenv("SEMAPHORE_BUILD_INFO")

// Set some known values
originalVer := Ver
originalCommit := Commit
originalDate := Date

Ver = "v2.14.9"
Commit = "66611eb"
Date = "1746447063"

defer func() {
Ver = originalVer
Commit = originalCommit
Date = originalDate
}()

// Simulate what the API does
systemInfo := map[string]interface{}{
"version": Version(),
"ansible": "some-ansible-version",
"web_host": "localhost",
}

expected := "v2.14.9-66611eb-1746447063"
if systemInfo["version"] != expected {
t.Errorf("Expected version '%s', but got '%s'", expected, systemInfo["version"])
}

// Test case 2: With environment variable override
customVersion := "v2.14.9-downstream-custom"
err := os.Setenv("SEMAPHORE_BUILD_INFO", customVersion)
if err != nil {
t.Fatalf("Failed to set environment variable: %v", err)
}
defer os.Unsetenv("SEMAPHORE_BUILD_INFO")

// Simulate API call with environment variable set
systemInfo2 := map[string]interface{}{
"version": Version(),
"ansible": "some-ansible-version",
"web_host": "localhost",
}

if systemInfo2["version"] != customVersion {
t.Errorf("Expected version '%s', but got '%s'", customVersion, systemInfo2["version"])
}

// Test that it can be JSON serialized (as the API does)
jsonData, err := json.Marshal(systemInfo2)
if err != nil {
t.Errorf("Failed to marshal system info to JSON: %v", err)
}

// Verify the JSON contains our custom version
var unmarshaled map[string]interface{}
err = json.Unmarshal(jsonData, &unmarshaled)
if err != nil {
t.Errorf("Failed to unmarshal JSON: %v", err)
}

if unmarshaled["version"] != customVersion {
t.Errorf("JSON version mismatch. Expected '%s', got '%s'", customVersion, unmarshaled["version"])
}
}
7 changes: 7 additions & 0 deletions util/version.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package util

import (
"os"
"strings"
)

Expand All @@ -11,6 +12,12 @@ var (
)

func Version() string {
// Check for SEMAPHORE_BUILD_INFO environment variable override
if buildInfo := os.Getenv("SEMAPHORE_BUILD_INFO"); buildInfo != "" {
return buildInfo
}

// Fall back to default version construction
return strings.Join([]string{
Ver,
Commit,
Expand Down
80 changes: 80 additions & 0 deletions util/version_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
package util

import (
"os"
"testing"
)

func TestVersion_Default(t *testing.T) {
// Ensure no environment variable is set
os.Unsetenv("SEMAPHORE_BUILD_INFO")

// Set some test values for the build variables
originalVer := Ver
originalCommit := Commit
originalDate := Date

Ver = "v1.0.0"
Commit = "abc123"
Date = "1234567890"

defer func() {
Ver = originalVer
Commit = originalCommit
Date = originalDate
}()

expected := "v1.0.0-abc123-1234567890"
actual := Version()

if actual != expected {
t.Errorf("Expected version '%s', but got '%s'", expected, actual)
}
}

func TestVersion_EnvironmentOverride(t *testing.T) {
// Set environment variable
customVersion := "MyCustomVersion-2.0.0-beta"
err := os.Setenv("SEMAPHORE_BUILD_INFO", customVersion)
if err != nil {
t.Fatalf("Failed to set environment variable: %v", err)
}
defer os.Unsetenv("SEMAPHORE_BUILD_INFO")

actual := Version()

if actual != customVersion {
t.Errorf("Expected version '%s', but got '%s'", customVersion, actual)
}
}

func TestVersion_EmptyEnvironmentFallsBackToDefault(t *testing.T) {
// Set empty environment variable
err := os.Setenv("SEMAPHORE_BUILD_INFO", "")
if err != nil {
t.Fatalf("Failed to set environment variable: %v", err)
}
defer os.Unsetenv("SEMAPHORE_BUILD_INFO")

// Set some test values for the build variables
originalVer := Ver
originalCommit := Commit
originalDate := Date

Ver = "v1.2.3"
Commit = "def456"
Date = "9876543210"

defer func() {
Ver = originalVer
Commit = originalCommit
Date = originalDate
}()

expected := "v1.2.3-def456-9876543210"
actual := Version()

if actual != expected {
t.Errorf("Expected version '%s', but got '%s'", expected, actual)
}
}
Loading