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
11 changes: 9 additions & 2 deletions pkg/appstream/resolver.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,29 +40,36 @@ func ResolveRelease(executor executil.Executor, explicitVersion, explicitDate, e
res.Source = "explicit"
}

var rawGitTag string

// 2. CI Environment Variables
if res.Version == "" {
if os.Getenv("GITHUB_REF_TYPE") == "tag" && os.Getenv("GITHUB_REF_NAME") != "" {
res.Version = SanitizeVersion(os.Getenv("GITHUB_REF_NAME"))
tag := os.Getenv("GITHUB_REF_NAME")
res.Version = SanitizeVersion(tag)
rawGitTag = tag
res.Source = "env:GITHUB_REF_NAME"
} else if ref := os.Getenv("GITHUB_REF"); strings.HasPrefix(ref, "refs/tags/") {
tag := strings.TrimPrefix(ref, "refs/tags/")
res.Version = SanitizeVersion(tag)
rawGitTag = tag
res.Source = "env:GITHUB_REF"
} else if tag := os.Getenv("CI_COMMIT_TAG"); tag != "" {
res.Version = SanitizeVersion(tag)
rawGitTag = tag
res.Source = "env:CI_COMMIT_TAG"
} else if tag := os.Getenv("CIRCLE_TAG"); tag != "" {
res.Version = SanitizeVersion(tag)
rawGitTag = tag
res.Source = "env:CIRCLE_TAG"
} else if tag := os.Getenv("TRAVIS_TAG"); tag != "" {
res.Version = SanitizeVersion(tag)
rawGitTag = tag
res.Source = "env:TRAVIS_TAG"
}
}

// 3. Local Git repository tags
var rawGitTag string
if res.Version == "" {
// Attempt exact tag match on HEAD
cmdExact := executor.Command("git", "describe", "--tags", "--exact-match")
Expand Down
212 changes: 173 additions & 39 deletions pkg/appstream/resolver_test.go
Original file line number Diff line number Diff line change
@@ -1,13 +1,31 @@
package appstream

import (
"os"
"errors"
"testing"

"github.com/aetherpak/aetherpak/pkg/executil"
)

var ciTagEnvVars = []string{
"GITHUB_REF_TYPE",
"GITHUB_REF_NAME",
"GITHUB_REF",
"CI_COMMIT_TAG",
"CIRCLE_TAG",
"TRAVIS_TAG",
}

func clearCIEnv(t *testing.T) {
t.Helper()
for _, k := range ciTagEnvVars {
t.Setenv(k, "")
}
}

func TestResolveRelease_Explicit(t *testing.T) {
clearCIEnv(t)

res, ok := ResolveRelease(nil, "v1.5.0", "2026-08-22", "Awesome release", "https://example.com")
if !ok {
t.Fatalf("expected ok=true for explicit version")
Expand All @@ -30,50 +48,166 @@ func TestResolveRelease_Explicit(t *testing.T) {
}

func TestResolveRelease_CIEnv(t *testing.T) {
os.Setenv("GITHUB_REF_TYPE", "tag")
os.Setenv("GITHUB_REF_NAME", "v2.0.0-beta.1")
defer func() {
os.Unsetenv("GITHUB_REF_TYPE")
os.Unsetenv("GITHUB_REF_NAME")
}()

res, ok := ResolveRelease(nil, "", "", "", "")
if !ok {
t.Fatalf("expected ok=true for GITHUB_REF_NAME")
}
if res.Version != "2.0.0-beta.1" {
t.Errorf("expected version 2.0.0-beta.1, got %s", res.Version)
}
if res.Source != "env:GITHUB_REF_NAME" {
t.Errorf("expected source env:GITHUB_REF_NAME, got %s", res.Source)
tests := []struct {
name string
setup func(t *testing.T)
expectedVer string
expectedSrc string
}{
{
name: "GITHUB_REF_NAME",
setup: func(t *testing.T) {
t.Setenv("GITHUB_REF_TYPE", "tag")
t.Setenv("GITHUB_REF_NAME", "v2.0.0-beta.1")
},
expectedVer: "2.0.0-beta.1",
expectedSrc: "env:GITHUB_REF_NAME",
},
{
name: "GITHUB_REF",
setup: func(t *testing.T) {
t.Setenv("GITHUB_REF", "refs/tags/v2.1.0")
},
expectedVer: "2.1.0",
expectedSrc: "env:GITHUB_REF",
},
{
name: "CI_COMMIT_TAG",
setup: func(t *testing.T) {
t.Setenv("CI_COMMIT_TAG", "v2.2.0")
},
expectedVer: "2.2.0",
expectedSrc: "env:CI_COMMIT_TAG",
},
{
name: "CIRCLE_TAG",
setup: func(t *testing.T) {
t.Setenv("CIRCLE_TAG", "v2.3.0")
},
expectedVer: "2.3.0",
expectedSrc: "env:CIRCLE_TAG",
},
{
name: "TRAVIS_TAG",
setup: func(t *testing.T) {
t.Setenv("TRAVIS_TAG", "v2.4.0")
},
expectedVer: "2.4.0",
expectedSrc: "env:TRAVIS_TAG",
},
}
if res.Date == "" {
t.Errorf("expected non-empty date")

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
clearCIEnv(t)
tt.setup(t)

res, ok := ResolveRelease(nil, "", "", "", "")
if !ok {
t.Fatalf("expected ok=true")
}
if res.Version != tt.expectedVer {
t.Errorf("expected version %s, got %s", tt.expectedVer, res.Version)
}
if res.Source != tt.expectedSrc {
t.Errorf("expected source %s, got %s", tt.expectedSrc, res.Source)
}
if res.Date == "" {
t.Errorf("expected non-empty date")
}
})
}
}

func TestResolveRelease_GitMock(t *testing.T) {
mockExec := executil.NewMockExecutor()
mockExec.OnCommand = func(cmd *executil.MockCommand) {
if cmd.Name == "git" && len(cmd.Args) >= 3 && cmd.Args[0] == "describe" && cmd.Args[1] == "--tags" && cmd.Args[2] == "--exact-match" {
cmd.OutData = []byte("v3.2.1\n")
t.Run("ExactTag", func(t *testing.T) {
clearCIEnv(t)
mockExec := executil.NewMockExecutor()
mockExec.OnCommand = func(cmd *executil.MockCommand) {
if cmd.Name == "git" && len(cmd.Args) >= 3 && cmd.Args[0] == "describe" && cmd.Args[1] == "--tags" && cmd.Args[2] == "--exact-match" {
cmd.OutData = []byte("v3.2.1\n")
}
if cmd.Name == "git" && len(cmd.Args) >= 4 && cmd.Args[0] == "log" && cmd.Args[2] == "--format=%cs" {
cmd.OutData = []byte("2026-05-10\n")
}
}
if cmd.Name == "git" && len(cmd.Args) >= 4 && cmd.Args[0] == "log" && cmd.Args[2] == "--format=%cs" {
cmd.OutData = []byte("2026-05-10\n")

res, ok := ResolveRelease(mockExec, "", "", "", "")
if !ok {
t.Fatalf("expected ok=true for git mock tag")
}
}
if res.Version != "3.2.1" {
t.Errorf("expected version 3.2.1, got %s", res.Version)
}
if res.Date != "2026-05-10" {
t.Errorf("expected date 2026-05-10 from git log, got %s", res.Date)
}
if res.Source != "git:exact-tag" {
t.Errorf("expected source git:exact-tag, got %s", res.Source)
}
})

res, ok := ResolveRelease(mockExec, "", "", "", "")
if !ok {
t.Fatalf("expected ok=true for git mock tag")
}
if res.Version != "3.2.1" {
t.Errorf("expected version 3.2.1, got %s", res.Version)
}
if res.Date != "2026-05-10" {
t.Errorf("expected date 2026-05-10 from git log, got %s", res.Date)
}
if res.Source != "git:exact-tag" {
t.Errorf("expected source git:exact-tag, got %s", res.Source)
}
t.Run("DescribeTagFallback", func(t *testing.T) {
clearCIEnv(t)
mockExec := executil.NewMockExecutor()
mockExec.OnCommand = func(cmd *executil.MockCommand) {
if cmd.Name == "git" && len(cmd.Args) >= 3 && cmd.Args[0] == "describe" && cmd.Args[1] == "--tags" && cmd.Args[2] == "--exact-match" {
cmd.RunErr = errors.New("tag not found")
}
if cmd.Name == "git" && len(cmd.Args) >= 3 && cmd.Args[0] == "describe" && cmd.Args[1] == "--tags" && cmd.Args[2] == "--abbrev=0" {
cmd.OutData = []byte("v3.2.0\n")
}
if cmd.Name == "git" && len(cmd.Args) >= 4 && cmd.Args[0] == "log" && cmd.Args[2] == "--format=%cs" {
cmd.OutData = []byte("2026-05-01\n")
}
}

res, ok := ResolveRelease(mockExec, "", "", "", "")
if !ok {
t.Fatalf("expected ok=true for git describe tag fallback")
}
if res.Version != "3.2.0" {
t.Errorf("expected version 3.2.0, got %s", res.Version)
}
if res.Date != "2026-05-01" {
t.Errorf("expected date 2026-05-01 from git log, got %s", res.Date)
}
if res.Source != "git:describe-tag" {
t.Errorf("expected source git:describe-tag, got %s", res.Source)
}
})

t.Run("NoTagFound", func(t *testing.T) {
clearCIEnv(t)
mockExec := executil.NewMockExecutor()
mockExec.OnCommand = func(cmd *executil.MockCommand) {
cmd.RunErr = errors.New("no tag")
}

_, ok := ResolveRelease(mockExec, "", "", "", "")
if ok {
t.Fatalf("expected ok=false when no tags found")
}
})

t.Run("ExplicitDateOverridesGitDate", func(t *testing.T) {
clearCIEnv(t)
mockExec := executil.NewMockExecutor()
mockExec.OnCommand = func(cmd *executil.MockCommand) {
if cmd.Name == "git" && len(cmd.Args) >= 3 && cmd.Args[0] == "describe" && cmd.Args[1] == "--tags" && cmd.Args[2] == "--exact-match" {
cmd.OutData = []byte("v3.2.1\n")
}
if cmd.Name == "git" && len(cmd.Args) >= 4 && cmd.Args[0] == "log" && cmd.Args[2] == "--format=%cs" {
cmd.OutData = []byte("2026-05-10\n")
}
}

res, ok := ResolveRelease(mockExec, "", "2026-12-31", "", "")
if !ok {
t.Fatalf("expected ok=true")
}
if res.Date != "2026-12-31" {
t.Errorf("expected explicit date 2026-12-31, got %s", res.Date)
}
})
}
Loading