Skip to content

Refactor CompileWorkflowData into smaller, testable functions#14402

Open
Copilot wants to merge 2 commits intomainfrom
copilot/refactor-compile-workflow-data
Open

Refactor CompileWorkflowData into smaller, testable functions#14402
Copilot wants to merge 2 commits intomainfrom
copilot/refactor-compile-workflow-data

Conversation

Copy link
Contributor

Copilot AI commented Feb 7, 2026

The CompileWorkflowData() function was 343 lines, mixing validation, YAML generation, and file I/O. This made individual phases difficult to test and increased cyclomatic complexity.

Changes

Extracted three focused methods:

  • validateWorkflowData() (177 lines) - Expression safety, feature flags, permissions, sandbox config, GitHub MCP toolsets, dispatch-workflow validation
  • generateAndValidateYAML() (81 lines) - YAML generation, expression size validation, template injection checks, schema validation, container/runtime/firewall validation
  • writeWorkflowOutput() (53 lines) - Lock file writing with change detection, file size validation, console output formatting

Refactored main function (53 lines, down from 343) - Now orchestrates initialization and calls the three methods in sequence

Added test coverage - Independent tests for each extracted function covering success and error cases

Before/After

// Before: 343 lines of mixed concerns
func (c *Compiler) CompileWorkflowData(data *WorkflowData, path string) error {
    // Initialize (30 lines)
    // Validate expressions, features, permissions... (170 lines)
    // Generate YAML, validate sizes, schema... (77 lines)
    // Write file, check size, display output... (52 lines)
}

// After: Clear orchestration
func (c *Compiler) CompileWorkflowData(data *WorkflowData, path string) error {
    // Initialize state
    if err := c.validateWorkflowData(data, path); err != nil {
        return err
    }
    yamlContent, err := c.generateAndValidateYAML(data, path, lockFile)
    if err != nil {
        return err
    }
    return c.writeWorkflowOutput(lockFile, yamlContent, path)
}

No functional changes.

Original prompt

This section details on the original issue you should resolve

<issue_title>[Code Quality] Refactor CompileWorkflowData into smaller, testable functions</issue_title>
<issue_description>### Description

The CompileWorkflowData() function in compiler.go is 343 lines long (lines 96-439), making it difficult to test individual validation steps and contributing to high cyclomatic complexity. This violates the maintainability guideline of 50 lines maximum per function.

Current State

  • File: pkg/workflow/compiler.go
  • Function: CompileWorkflowData() (343 lines)
  • Quality Score: 83/100
  • Issue: Function exceeds guideline by ~7x (343 vs 50 line recommendation)
  • Impact: Difficult to test validation phases independently

Why This Matters (Release Mode Priority)

  1. Testing Difficulty: Cannot unit test individual validation steps
  2. Complexity: High cyclomatic complexity increases bug risk
  3. Maintainability: Hard to understand and modify validation logic
  4. Code Smell: Violates Single Responsibility Principle

Suggested Changes

Extract validation phases from CompileWorkflowData() into 3 focused methods:

1. validateWorkflowData() - Lines 131-300

// validateWorkflowData performs comprehensive validation of workflow configuration
// including expressions, features, permissions, and configurations.
func (c *Compiler) validateWorkflowData(data *WorkflowData) error {
    // Expression validation
    // Feature validation  
    // Permission validation
    // Configuration validation
    return nil
}

2. generateAndValidateYAML() - Lines 310-386

// generateAndValidateYAML generates GitHub Actions YAML and validates
// the output size and format.
func (c *Compiler) generateAndValidateYAML(data *WorkflowData) (string, error) {
    // Generate YAML
    // Validate size limits
    // ANSI code sanitization
    return yamlContent, nil
}

3. writeWorkflowOutput() - Lines 388-421

// writeWorkflowOutput writes the compiled workflow to the lock file
// and handles console output formatting.
func (c *Compiler) writeWorkflowOutput(lockFilePath, yamlContent string, data *WorkflowData) error {
    // Write to lock file
    // Generate success message
    // Console output formatting
    return nil
}

Refactored CompileWorkflowData() - ~50 lines

func (c *Compiler) CompileWorkflowData(data *WorkflowData, filePath, outputDir string) error {
    // Validate workflow data
    if err := c.validateWorkflowData(data); err != nil {
        return err
    }
    
    // Generate and validate YAML
    yamlContent, err := c.generateAndValidateYAML(data)
    if err != nil {
        return err
    }
    
    // Write output
    lockFilePath := determineLockFilePath(filePath, outputDir)
    return c.writeWorkflowOutput(lockFilePath, yamlContent, data)
}

Files Affected

  • Modified: pkg/workflow/compiler.go (extract functions, reduce CompileWorkflowData from 343→~50 lines)
  • Modified: pkg/workflow/compiler_test.go (add tests for new functions)

Success Criteria

  • CompileWorkflowData() reduced to ~50 lines (orchestration only)
  • Three new methods created with clear responsibilities
  • Each method independently testable
  • All existing tests pass (make test-unit)
  • New tests added for extracted methods
  • Quality score maintained or improved
  • No functional changes (refactor only)

Estimated Effort

2-3 hours - Function extraction and test updates

Priority

High - Improves testability and reduces complexity, directly supporting release stability.

Source

Extracted from Daily Compiler Code Quality Report - 2026-02-07 github/gh-aw#14370

References:

AI generated by Discussion Task Miner - Code Quality Improvement Agent

  • expires on Feb 8, 2026, 5:06 PM UTC

Comments on the Issue (you are @copilot in this section)


💬 We'd love your input! Share your thoughts on Copilot coding agent in our 2 minute survey.

Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Copilot AI changed the title [WIP] Refactor CompileWorkflowData into smaller, testable functions Refactor CompileWorkflowData into smaller, testable functions Feb 7, 2026
Copilot AI requested a review from pelikhan February 7, 2026 17:56
@pelikhan pelikhan marked this pull request as ready for review February 7, 2026 18:13
Copilot AI review requested due to automatic review settings February 7, 2026 18:13
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Refactors CompileWorkflowData() into smaller methods to improve testability and reduce complexity, with accompanying unit tests for each extracted phase.

Changes:

  • Extracted validateWorkflowData(), generateAndValidateYAML(), and writeWorkflowOutput() from CompileWorkflowData()
  • Reworked CompileWorkflowData() into an orchestration method that delegates to the extracted functions
  • Added unit tests for each extracted function, including an “output unchanged” case

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.

File Description
pkg/workflow/compiler.go Splits CompileWorkflowData() into focused validation/generation/output helpers and updates the main orchestration flow.
pkg/workflow/compiler_test.go Adds new unit tests targeting the extracted helper methods and key success/error paths.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +512 to +522
// Write same content again
compiler := NewCompiler()
err = compiler.writeWorkflowOutput(lockFile, yamlContent, markdownPath)
require.NoError(t, err)

// Check that modification time hasn't changed (file wasn't rewritten)
finalInfo, err := os.Stat(lockFile)
require.NoError(t, err)
finalModTime := finalInfo.ModTime()

assert.Equal(t, initialModTime, finalModTime, "File should not be rewritten if content is unchanged")
Copy link

Copilot AI Feb 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This test can be unreliable because filesystem mtime resolution can be coarse; a rewrite that happens quickly may not change ModTime(), causing the test to pass even if the file was rewritten. To make this robust, introduce a delay sufficient to exceed typical mtime granularity before the second write attempt (then assert modtime is unchanged), or alternatively assert a stronger signal of rewrite avoidance (e.g., compare inode/file ID where available, or instrument the write path via an injectable file-writer in tests).

Copilot uses AI. Check for mistakes.
Comment on lines +426 to +433
tests := []struct {
name string
yamlContent string
noEmit bool
quiet bool
shouldError bool
checkFileSize bool
}{
Copy link

Copilot AI Feb 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The field name checkFileSize is misleading because the test logic checks file existence and content, not size. Consider renaming it to something like expectFileWritten / verifyFileWritten / checkFileWritten to better match its usage.

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Code Quality] Refactor CompileWorkflowData into smaller, testable functions

2 participants