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
104 changes: 104 additions & 0 deletions pkg/workflow/compiler_yaml_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1237,3 +1237,107 @@ This is a test workflow.`
})
}
}

func TestLockMetadataVersionInReleaseBuilds(t *testing.T) {
// Save and restore original values
originalIsRelease := isReleaseBuild
originalVersion := compilerVersion
defer func() {
isReleaseBuild = originalIsRelease
compilerVersion = originalVersion
}()

tmpDir := testutil.TempDir(t, "lock-metadata-version")

// Test both dev and release modes
tests := []struct {
name string
isRelease bool
version string
expectVersion bool
}{
{
name: "dev build should not include version",
isRelease: false,
version: "dev",
expectVersion: false,
},
{
name: "release build should include version",
isRelease: true,
version: "v0.1.2",
expectVersion: true,
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
// Set version and release flag
SetIsRelease(tt.isRelease)
SetVersion(tt.version)

// Create a simple workflow
workflowContent := `---
engine: copilot
on: issues
---
# Test Workflow

Test prompt.
`
workflowPath := filepath.Join(tmpDir, tt.name+".md")
if err := os.WriteFile(workflowPath, []byte(workflowContent), 0o644); err != nil {
t.Fatalf("Failed to write workflow file: %v", err)
}

// Compile the workflow
compiler := NewCompiler()
err := compiler.CompileWorkflow(workflowPath)
if err != nil {
t.Fatalf("Failed to compile workflow: %v", err)
}

// Read the lock file
lockFile := strings.TrimSuffix(workflowPath, ".md") + ".lock.yml"
lockContent, err := os.ReadFile(lockFile)
if err != nil {
t.Fatalf("Failed to read lock file: %v", err)
}

lockContentStr := string(lockContent)

// Extract metadata line
metadataLine := ""
lines := strings.Split(lockContentStr, "\n")
for _, line := range lines {
if strings.Contains(line, "gh-aw-metadata:") {
metadataLine = line
break
}
}

if metadataLine == "" {
t.Fatal("Could not find gh-aw-metadata in lock file")
}

// Check if version is present
hasVersion := strings.Contains(metadataLine, `"compiler_version"`)

if tt.expectVersion && !hasVersion {
t.Errorf("Expected version to be included in metadata for release build, but it was not found.\nMetadata: %s", metadataLine)
}

if !tt.expectVersion && hasVersion {
t.Errorf("Expected version to NOT be included in metadata for dev build, but it was found.\nMetadata: %s", metadataLine)
}

// If version is expected, verify it matches
if tt.expectVersion && hasVersion {
expectedVersionStr := fmt.Sprintf(`"compiler_version":"%s"`, tt.version)
if !strings.Contains(metadataLine, expectedVersionStr) {
t.Errorf("Expected version '%s' to be in metadata, but got:\n%s", tt.version, metadataLine)
}
}
})
}
}
11 changes: 10 additions & 1 deletion pkg/workflow/lock_schema.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ type LockMetadata struct {
SchemaVersion LockSchemaVersion `json:"schema_version"`
FrontmatterHash string `json:"frontmatter_hash,omitempty"`
StopTime string `json:"stop_time,omitempty"`
CompilerVersion string `json:"compiler_version,omitempty"`
}

// SupportedSchemaVersions lists all schema versions this build can consume
Expand Down Expand Up @@ -115,12 +116,20 @@ func formatSupportedVersions() string {
}

// GenerateLockMetadata creates a LockMetadata struct for embedding in lock files
// For release builds, the compiler version is included in the metadata
func GenerateLockMetadata(frontmatterHash string, stopTime string) *LockMetadata {
return &LockMetadata{
metadata := &LockMetadata{
SchemaVersion: LockSchemaV1,
FrontmatterHash: frontmatterHash,
StopTime: stopTime,
}

// Include compiler version only for release builds
if IsRelease() {
metadata.CompilerVersion = GetVersion()
}

return metadata
}

// ToJSON converts LockMetadata to a compact JSON string for embedding in comments
Expand Down
62 changes: 62 additions & 0 deletions pkg/workflow/lock_schema_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,19 @@ name: test
expectLegacy: false,
expectError: false,
},
{
name: "metadata with compiler version",
content: `# gh-aw-metadata: {"schema_version":"v1","frontmatter_hash":"abc123","compiler_version":"v0.1.2"}
name: test
`,
expectMetadata: &LockMetadata{
SchemaVersion: LockSchemaV1,
FrontmatterHash: "abc123",
CompilerVersion: "v0.1.2",
},
expectLegacy: false,
expectError: false,
},
}

for _, tt := range tests {
Expand All @@ -98,6 +111,7 @@ name: test
require.NotNil(t, metadata, "Expected metadata to be parsed")
assert.Equal(t, tt.expectMetadata.SchemaVersion, metadata.SchemaVersion, "Schema version mismatch")
assert.Equal(t, tt.expectMetadata.FrontmatterHash, metadata.FrontmatterHash, "Frontmatter hash mismatch")
assert.Equal(t, tt.expectMetadata.CompilerVersion, metadata.CompilerVersion, "Compiler version mismatch")
} else if !tt.expectError {
assert.Nil(t, metadata, "Expected nil metadata")
}
Expand Down Expand Up @@ -211,6 +225,40 @@ func TestIsSchemaVersionSupported(t *testing.T) {
}

func TestGenerateLockMetadata(t *testing.T) {
// Save and restore original values
originalIsRelease := isReleaseBuild
originalVersion := compilerVersion
defer func() {
isReleaseBuild = originalIsRelease
compilerVersion = originalVersion
}()

// Test dev build (default)
SetIsRelease(false)
SetVersion("dev")
hash := "abcd1234"
stopTime := "2026-02-17 20:00:00"
metadata := GenerateLockMetadata(hash, stopTime)

assert.NotNil(t, metadata, "Metadata should be created")
assert.Equal(t, LockSchemaV1, metadata.SchemaVersion, "Should use current schema version")
assert.Equal(t, hash, metadata.FrontmatterHash, "Should preserve frontmatter hash")
assert.Equal(t, stopTime, metadata.StopTime, "Should preserve stop time")
assert.Empty(t, metadata.CompilerVersion, "Dev builds should not include version")
}

func TestGenerateLockMetadataReleaseBuild(t *testing.T) {
// Save and restore original values
originalIsRelease := isReleaseBuild
originalVersion := compilerVersion
defer func() {
isReleaseBuild = originalIsRelease
compilerVersion = originalVersion
}()

// Test release build
SetIsRelease(true)
SetVersion("v0.1.2")
hash := "abcd1234"
stopTime := "2026-02-17 20:00:00"
metadata := GenerateLockMetadata(hash, stopTime)
Expand All @@ -219,6 +267,7 @@ func TestGenerateLockMetadata(t *testing.T) {
assert.Equal(t, LockSchemaV1, metadata.SchemaVersion, "Should use current schema version")
assert.Equal(t, hash, metadata.FrontmatterHash, "Should preserve frontmatter hash")
assert.Equal(t, stopTime, metadata.StopTime, "Should preserve stop time")
assert.Equal(t, "v0.1.2", metadata.CompilerVersion, "Release builds should include version")
}

func TestGenerateLockMetadataWithoutStopTime(t *testing.T) {
Expand Down Expand Up @@ -258,6 +307,19 @@ func TestLockMetadataToJSON(t *testing.T) {
`"schema_version":"v1"`,
},
},
{
name: "metadata with compiler version",
metadata: &LockMetadata{
SchemaVersion: LockSchemaV1,
FrontmatterHash: "test123",
CompilerVersion: "v0.1.2",
},
contains: []string{
`"schema_version":"v1"`,
`"frontmatter_hash":"test123"`,
`"compiler_version":"v0.1.2"`,
},
},
}

for _, tt := range tests {
Expand Down
Loading