From 694734a66bf63c9c411cad53655697e6f7d55535 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 18 Feb 2026 13:36:18 +0000 Subject: [PATCH 1/4] Initial plan From 19637c4112ec9df40e5379a9a0ad5bcfd9806299 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 18 Feb 2026 13:45:02 +0000 Subject: [PATCH 2/4] Add compiler_version field to LockMetadata for release builds Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com> --- pkg/workflow/lock_schema.go | 17 ++++++--- pkg/workflow/lock_schema_test.go | 62 ++++++++++++++++++++++++++++++++ 2 files changed, 75 insertions(+), 4 deletions(-) diff --git a/pkg/workflow/lock_schema.go b/pkg/workflow/lock_schema.go index 339108dda2f..fa4989f23b6 100644 --- a/pkg/workflow/lock_schema.go +++ b/pkg/workflow/lock_schema.go @@ -21,9 +21,10 @@ const ( // LockMetadata represents the structured metadata embedded in lock files type LockMetadata struct { - SchemaVersion LockSchemaVersion `json:"schema_version"` - FrontmatterHash string `json:"frontmatter_hash,omitempty"` - StopTime string `json:"stop_time,omitempty"` + 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 @@ -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 diff --git a/pkg/workflow/lock_schema_test.go b/pkg/workflow/lock_schema_test.go index c1c790435af..0f3d926c2e0 100644 --- a/pkg/workflow/lock_schema_test.go +++ b/pkg/workflow/lock_schema_test.go @@ -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 { @@ -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") } @@ -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) @@ -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) { @@ -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 { From 6617fb6628fa58896e7a6640ee7ecc28d1017cf1 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 18 Feb 2026 13:47:43 +0000 Subject: [PATCH 3/4] Add integration test for compiler version in lock metadata Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com> --- pkg/workflow/compiler_yaml_test.go | 104 +++++++++++++++++++++++++++++ pkg/workflow/lock_schema.go | 12 ++-- 2 files changed, 110 insertions(+), 6 deletions(-) diff --git a/pkg/workflow/compiler_yaml_test.go b/pkg/workflow/compiler_yaml_test.go index 7944031bb86..a919fee2031 100644 --- a/pkg/workflow/compiler_yaml_test.go +++ b/pkg/workflow/compiler_yaml_test.go @@ -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) +} +} +}) +} +} diff --git a/pkg/workflow/lock_schema.go b/pkg/workflow/lock_schema.go index fa4989f23b6..d21a03aeb2e 100644 --- a/pkg/workflow/lock_schema.go +++ b/pkg/workflow/lock_schema.go @@ -21,10 +21,10 @@ const ( // LockMetadata represents the structured metadata embedded in lock files 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"` + 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 @@ -123,12 +123,12 @@ func GenerateLockMetadata(frontmatterHash string, stopTime string) *LockMetadata FrontmatterHash: frontmatterHash, StopTime: stopTime, } - + // Include compiler version only for release builds if IsRelease() { metadata.CompilerVersion = GetVersion() } - + return metadata } From e5d42d12d77212ea5a8575e6ac50290ed4131b62 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 18 Feb 2026 14:09:51 +0000 Subject: [PATCH 4/4] Format code and finalize version metadata implementation Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com> --- pkg/workflow/compiler_yaml_test.go | 166 ++++++++++++++--------------- 1 file changed, 83 insertions(+), 83 deletions(-) diff --git a/pkg/workflow/compiler_yaml_test.go b/pkg/workflow/compiler_yaml_test.go index a919fee2031..2b2e1af3da8 100644 --- a/pkg/workflow/compiler_yaml_test.go +++ b/pkg/workflow/compiler_yaml_test.go @@ -1239,45 +1239,45 @@ 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, -}, -} + // 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) + 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 := `--- + // Create a simple workflow + workflowContent := `--- engine: copilot on: issues --- @@ -1285,59 +1285,59 @@ on: issues 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) -} + 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) -} + // 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) -} + // 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) + 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 -} -} + // 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") -} + if metadataLine == "" { + t.Fatal("Could not find gh-aw-metadata in lock file") + } -// Check if version is present -hasVersion := strings.Contains(metadataLine, `"compiler_version"`) + // 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 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 !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) -} -} -}) -} + // 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) + } + } + }) + } }