Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement: atmos list workflows #941

Open
wants to merge 17 commits into
base: main
Choose a base branch
from
Open

Implement: atmos list workflows #941

wants to merge 17 commits into from

Conversation

Cerebrovinny
Copy link
Collaborator

@Cerebrovinny Cerebrovinny commented Jan 15, 2025

what

Atmos list workflow with the standard UI

why

Users should be able to list their workflows using this command

Updated 01/16
Screenshot 2025-01-16 at 06 43 59

references

Summary by CodeRabbit

Release Notes

  • New Features

    • Added a new CLI command to list Atmos workflows.
    • Introduced workflow listing functionality with optional file filtering.
    • Enhanced configuration options for workflow listing, including output format and delimiter.
    • Added a new structure for specifying list configurations in workflow settings.
  • Improvements

    • Enhanced terminal-aware writer for better output formatting.
    • Refined error handling for CLI commands to suppress warnings during help command invocations.
  • Testing

    • Added comprehensive tests for workflow listing functionality, including various scenarios.

The release introduces workflow listing capabilities with enhanced display and configuration options for Atmos users.

@mergify mergify bot added the triage Needs triage label Jan 15, 2025
@osterman
Copy link
Member

  • Can we add some left and right padding to the columns?
  • Demonstrate how it works with no TTY (e.g. in a command pipeline )

@osterman
Copy link
Member

Also add test cases

@osterman osterman added minor New features that do not break anything and removed triage Needs triage labels Jan 16, 2025
@Cerebrovinny
Copy link
Collaborator Author

Also add test cases

Test cases already added here cdd7a1e

coderabbitai[bot]
coderabbitai bot previously approved these changes Jan 16, 2025
Copy link
Contributor

coderabbitai bot commented Jan 16, 2025

📝 Walkthrough

Walkthrough

The pull request introduces a new command atmos list workflows to display workflow information from Atmos configuration files. It includes features for file filtering, terminal-aware output formatting, and enhanced configuration options. The implementation spans multiple files, allowing users to view workflow details in a structured format, with a fallback to plain text when no terminal support is available.

Changes

File Change Summary
cmd/list_workflows.go Added new listWorkflowsCmd with file filtering flag and workflow listing logic.
internal/tui/templates/term/term_writer.go Updated terminal support check using exec.CheckTTYSupport().
pkg/list/list_workflows.go Implemented workflow extraction and listing functions.
pkg/list/list_workflows_test.go Added test cases for workflow listing functionality.
pkg/schema/schema.go Introduced ListConfig and ListColumnConfig types for workflow listing configuration.
cmd/root.go Modified error handling logic in PersistentPreRun function.
tests/test-cases/log-level-validation.yaml Updated test cases for log level validation, focusing on the version command.
tests/snapshots/TestCLICommands_atmos_describe_config.stdout.golden Added new structure for workflow listing configuration in the YAML.

Assessment against linked issues

Objective Addressed Explanation
Implement atmos list workflows
Support file filtering
Fallback to plain text without TTY
Configurable columns via schema Partial implementation, more configuration might be needed.

Possibly related PRs

  • feat: create atmos list command for listing stacks and components #797: The introduction of the listWorkflowsCmd in the main PR is related to the new atmos list command for listing stacks and components, as both involve enhancements to the command-line interface for listing functionalities.
  • Validate Atmos Log Levels #930: The validation of log levels in the main PR aligns with the changes in the logging configuration and validation processes, ensuring that only valid log levels are accepted in the Atmos configuration.
  • Logs validation on root level #946: The changes in the root command to handle logging configurations and validate them at the root level are related to the main PR's focus on improving configuration handling and validation.

Suggested reviewers

  • Gowiem
  • aknysh
  • osterman
✨ Finishing Touches
  • 📝 Generate Docstrings (Beta)

Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR. (Beta)
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary or @auto-summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai or @auto-title anywhere in the PR title to generate the title automatically.

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (5)
pkg/list/list_workflows_test.go (1)

30-47: Reduce code duplication in tests.

The test configuration and assertions are duplicated between the two test functions. Consider:

  1. Moving the common ListConfig to a test helper
  2. Creating a helper function for common assertions
+func createTestConfig() schema.ListConfig {
+    return schema.ListConfig{
+        Columns: []schema.ListColumnConfig{
+            {Name: "File", Value: "{{ .workflow_file }}"},
+            {Name: "Workflow", Value: "{{ .workflow_name }}"},
+            {Name: "Description", Value: "{{ .workflow_description }}"},
+        },
+    }
+}
+
+func assertWorkflowOutput(t *testing.T, output string) {
+    expected := []string{
+        "File", "Workflow", "Description",
+        "example", "test-1", "Test workflow",
+    }
+    for _, row := range expected {
+        assert.Contains(t, output, row)
+    }
+}
cmd/list_workflows.go (1)

20-22: Enhance command documentation with more examples.

Consider adding examples for:

  • Non-TTY usage (e.g., piping to grep)
  • Different output formats
  • File filtering patterns
-    Example: "atmos list workflows\n" +
-        "atmos list workflows -f <file>",
+    Example: "# List all workflows\n" +
+        "atmos list workflows\n\n" +
+        "# Filter workflows by file\n" +
+        "atmos list workflows -f <file>\n\n" +
+        "# Use with pipes\n" +
+        "atmos list workflows | grep 'pattern'",
pkg/list/list_workflows.go (2)

61-67: Optimize string operations in sorting.

The current implementation concatenates strings repeatedly during sorting, which could be inefficient for large datasets.

-sort.Slice(rows, func(i, j int) bool {
-    return strings.Join(rows[i], "\t") < strings.Join(rows[j], "\t")
-})
+sort.Slice(rows, func(i, j int) bool {
+    // Compare elements sequentially to avoid unnecessary string concatenation
+    for col := 0; col < len(rows[i]); col++ {
+        if rows[i][col] != rows[j][col] {
+            return rows[i][col] < rows[j][col]
+        }
+    }
+    return false
+})

17-18: Add comprehensive documentation for exported functions.

The exported functions need better documentation following Go standards.

-// getWorkflowsFromManifest extracts workflows from a workflow manifest
+// getWorkflowsFromManifest extracts workflows from a workflow manifest and returns them as rows
+// where each row contains [fileName, workflowName, description].
 func getWorkflowsFromManifest(manifest schema.WorkflowManifest) ([][]string, error) {

-// FilterAndListWorkflows filters and lists workflows based on the given file
+// FilterAndListWorkflows filters and lists workflows based on the given file flag.
+// It supports both TTY and non-TTY output formats, automatically degrading to a
+// simple tabular format when TTY is not available. The output format can be
+// customized using the listConfig parameter.
 func FilterAndListWorkflows(fileFlag string, listConfig schema.ListConfig) (string, error) {

Also applies to: 30-31

pkg/schema/schema.go (1)

673-681: LGTM! Well-structured types for list configuration.

The new types ListConfig and ListColumnConfig provide a flexible configuration structure for the workflow listing feature. The Format field will help support different output formats (TTY vs non-TTY), and the column configuration allows for customizable output.

Consider adding Go doc comments to describe:

  • Valid values for the Format field
  • Expected format for the Value field (e.g., if it supports templating)
+// ListConfig defines the configuration for listing workflows
+// Format specifies the output format (e.g., "table", "json")
 type ListConfig struct {
   Format  string             `yaml:"format" json:"format" mapstructure:"format"`
   Columns []ListColumnConfig `yaml:"columns" json:"columns" mapstructure:"columns"`
 }

+// ListColumnConfig defines a column in the workflow list output
+// Value can be a static string or a template expression
 type ListColumnConfig struct {
   Name  string `yaml:"name" json:"name" mapstructure:"name"`
   Value string `yaml:"value" json:"value" mapstructure:"value"`
 }
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 20098bf and fdc63cb.

📒 Files selected for processing (5)
  • cmd/list_workflows.go (1 hunks)
  • internal/tui/templates/term/term_writer.go (2 hunks)
  • pkg/list/list_workflows.go (1 hunks)
  • pkg/list/list_workflows_test.go (1 hunks)
  • pkg/schema/schema.go (2 hunks)
⏰ Context from checks skipped due to timeout of 90000ms (2)
  • GitHub Check: Acceptance Tests (windows-latest, windows)
  • GitHub Check: Summary
🔇 Additional comments (3)
internal/tui/templates/term/term_writer.go (1)

34-36: LGTM! Good standardization of TTY support check.

The change to use exec.CheckTTYSupport() aligns with our standardization efforts.

pkg/list/list_workflows.go (1)

38-53: Replace example data with actual workflow manifest loading.

The TODO comment and example data should be replaced with actual implementation.

Let's check if the workflow manifest loading is implemented elsewhere:

Would you like me to help implement the workflow manifest loading functionality or create a GitHub issue to track this?

✅ Verification successful

The workflow manifest loading implementation is indeed missing.

The schema for WorkflowManifest is properly defined in the codebase, but there's no actual implementation for loading workflow manifests from files. The example data should be replaced with proper manifest loading logic.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for workflow manifest loading implementations
rg -l "WorkflowManifest.*Load|LoadWorkflow" --type go

Length of output: 55


Script:

#!/bin/bash
# Search for manifest-related code and configuration loading
echo "=== Searching for manifest-related code ==="
rg -l "manifest" --type go

echo -e "\n=== Searching for YAML/JSON workflow config parsing ==="
rg -l "yaml\.Unmarshal|json\.Unmarshal.*[Ww]orkflow" --type go

echo -e "\n=== Checking schema package for manifest definitions ==="
fd "schema.*\.go$" --exec cat {}

Length of output: 41608

pkg/schema/schema.go (1)

137-138: LGTM! Field addition follows consistent patterns.

The List field is well-structured with appropriate tags, maintaining consistency with other fields in the Workflows struct.

pkg/list/list_workflows_test.go Outdated Show resolved Hide resolved
cmd/list_workflows.go Outdated Show resolved Hide resolved
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

♻️ Duplicate comments (1)
pkg/list/list_workflows_test.go (1)

31-75: 🛠️ Refactor suggestion

Strengthen test coverage with additional test cases.

The test structure is robust, but consider adding these scenarios:

  1. Malformed YAML file to verify error handling
  2. Custom column configuration to verify template rendering
  3. Non-TTY output format (as requested in PR comments)

Here's a suggested addition to the test cases:

 tests := []struct {
     // ... existing fields ...
 }{
     // ... existing test cases ...
+    {
+        name:     "malformed yaml",
+        fileFlag: "testdata/malformed.yaml",
+        config:   schema.ListConfig{},
+        wantErr:  true,
+    },
+    {
+        name:     "custom columns",
+        fileFlag: "",
+        config: schema.ListConfig{
+            Columns: []schema.ListColumnConfig{
+                {Name: "Custom", Value: "{{ .workflow_name | upper }}"},
+            },
+        },
+        contains: []string{"TEST-1"},
+    },
+    {
+        name:     "non-tty output",
+        fileFlag: "",
+        config: schema.ListConfig{
+            Format: "plain",
+        },
+        contains: []string{"test-1\tTest workflow"},
+    },
 }
🧹 Nitpick comments (1)
pkg/list/list_workflows_test.go (1)

11-11: Consider upgrading to yaml.v3 for enhanced security and performance.

The code currently uses gopkg.in/yaml.v2. Version 3 of the yaml package offers better security features and improved performance.

-	"gopkg.in/yaml.v2"
+	"gopkg.in/yaml.v3"
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between fdc63cb and d63081f.

📒 Files selected for processing (2)
  • pkg/list/list_workflows.go (1 hunks)
  • pkg/list/list_workflows_test.go (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • pkg/list/list_workflows.go
⏰ Context from checks skipped due to timeout of 90000ms (2)
  • GitHub Check: Build (windows-latest, windows)
  • GitHub Check: Summary
🔇 Additional comments (1)
pkg/list/list_workflows_test.go (1)

105-144: 🛠️ Refactor suggestion

Refactor test for better structure and stronger assertions.

This test has several opportunities for improvement:

  1. Extract common setup code to avoid duplication
  2. Use structured output verification instead of loose string checks
  3. Verify the exact format and order of the output

Here's a suggested refactor:

+func setupTestWorkflow(t *testing.T) (string, string) {
+    tmpDir, err := os.MkdirTemp("", "workflow_test")
+    require.NoError(t, err)
+    
+    testWorkflowFile := filepath.Join(tmpDir, "test.yaml")
+    // ... existing workflow setup code ...
+    
+    return tmpDir, testWorkflowFile
+}
+
 func TestListWorkflowsWithFile(t *testing.T) {
-    tmpDir, err := os.MkdirTemp("", "workflow_test")
-    require.NoError(t, err)
+    tmpDir, testWorkflowFile := setupTestWorkflow(t)
     defer os.RemoveAll(tmpDir)
-
-    // Create a test workflow file
-    testWorkflowFile := filepath.Join(tmpDir, "test.yaml")
     // ... rest of the setup ...

     output, err := FilterAndListWorkflows(testWorkflowFile, listConfig)
     assert.NoError(t, err)
-    assert.Contains(t, output, "File")
-    assert.Contains(t, output, "Workflow")
-    // ... other Contains checks ...
+    
+    expected := []struct{
+        header string
+        value  string
+    }{
+        {"File", "test.yaml"},
+        {"Workflow", "test-1"},
+        {"Description", "Test workflow"},
+    }
+    
+    for _, e := range expected {
+        headerIdx := strings.Index(output, e.header)
+        valueIdx := strings.Index(output, e.value)
+        assert.Greater(t, valueIdx, headerIdx, 
+            "Value %s should appear after header %s", e.value, e.header)
+    }
 }

Likely invalid or redundant comment.

@osterman
Copy link
Member

  • Please add support for a --format flag. Note, we will be adding this for all list commands.
  • Please add support for --delimiter

Note, if either flag is passed, TTY output is disabled.

See gh CLI for example of format flag.

coderabbitai[bot]
coderabbitai bot previously approved these changes Jan 16, 2025
pkg/list/list_workflows.go Outdated Show resolved Hide resolved
pkg/list/list_workflows.go Outdated Show resolved Hide resolved
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (1)
pkg/schema/schema.go (1)

696-704: Consider adding documentation for the new types.

The ListConfig and ListColumnConfig types are well-structured and follow the codebase patterns. Consider adding documentation comments to describe:

  • The purpose of each type
  • Expected values for the Format field
  • Examples of valid column configurations

Example documentation:

+// ListConfig defines the configuration for list command output formatting
 type ListConfig struct {
     Format  string             `yaml:"format" json:"format" mapstructure:"format"`
     Columns []ListColumnConfig `yaml:"columns" json:"columns" mapstructure:"columns"`
 }

+// ListColumnConfig defines a column in the list output
 type ListColumnConfig struct {
     Name  string `yaml:"name" json:"name" mapstructure:"name"`
     Value string `yaml:"value" json:"value" mapstructure:"value"`
 }
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between d63081f and 7bdbbf6.

📒 Files selected for processing (1)
  • pkg/schema/schema.go (2 hunks)
⏰ Context from checks skipped due to timeout of 90000ms (2)
  • GitHub Check: Build (windows-latest, windows)
  • GitHub Check: Summary
🔇 Additional comments (1)
pkg/schema/schema.go (1)

160-161: LGTM! Well-structured field addition.

The List field is properly integrated into the Workflows struct with consistent tag formatting.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (3)
pkg/list/list_workflows.go (2)

88-93: Consider optimizing the sort key generation.

The current implementation regenerates the sort key for each comparison.

-sort.Slice(rows, func(i, j int) bool {
-    return strings.Join(rows[i], delimiter) < strings.Join(rows[j], delimiter)
-})
+// Pre-compute sort keys
+type rowWithKey struct {
+    row []string
+    key string
+}
+rowsWithKeys := make([]rowWithKey, len(rows))
+for i, row := range rows {
+    rowsWithKeys[i] = rowWithKey{row: row, key: strings.Join(row, delimiter)}
+}
+sort.Slice(rowsWithKeys, func(i, j int) bool {
+    return rowsWithKeys[i].key < rowsWithKeys[j].key
+})
+// Extract sorted rows
+for i, rwk := range rowsWithKeys {
+    rows[i] = rwk.row
+}

133-152: Consider extracting table styling into a separate function.

The table styling logic could be moved to a dedicated function for better maintainability.

+func createStyledTable(header []string, rows [][]string) string {
+    return table.New().
+        Border(lipgloss.ThickBorder()).
+        BorderStyle(lipgloss.NewStyle().Foreground(lipgloss.Color(theme.ColorBorder))).
+        StyleFunc(func(row, col int) lipgloss.Style {
+            style := lipgloss.NewStyle().PaddingLeft(1).PaddingRight(1)
+            if row == 0 {
+                return style.Inherit(theme.Styles.CommandName).Align(lipgloss.Center)
+            }
+            if row%2 == 0 {
+                return style.Inherit(theme.Styles.GrayText)
+            }
+            return style.Inherit(theme.Styles.Description)
+        }).
+        Headers(header...).
+        Rows(rows...).
+        String() + "\n"
+}

Then use it in the main function:

-            t := table.New().
-                Border(lipgloss.ThickBorder())...
-            return t.String() + "\n", nil
+            return createStyledTable(header, rows), nil
cmd/list_workflows.go (1)

64-64: Enhance format flag documentation.

The format flag description should list supported formats.

-    listWorkflowsCmd.PersistentFlags().String("format", "", "Output format (table, json, csv)")
+    listWorkflowsCmd.PersistentFlags().String("format", "", "Output format. Supported values: 'table' (default), 'json', 'csv'")
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 7bdbbf6 and e72cdea.

📒 Files selected for processing (6)
  • cmd/list_workflows.go (1 hunks)
  • cmd/root.go (1 hunks)
  • internal/tui/templates/term/term_writer.go (2 hunks)
  • pkg/list/list_workflows.go (1 hunks)
  • pkg/list/list_workflows_test.go (1 hunks)
  • pkg/schema/schema.go (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • pkg/list/list_workflows_test.go
⏰ Context from checks skipped due to timeout of 90000ms (2)
  • GitHub Check: Build (windows-latest, windows)
  • GitHub Check: Summary
🔇 Additional comments (4)
internal/tui/templates/term/term_writer.go (1)

34-34: LGTM! Standardized TTY support check.

The change to use exec.CheckTTYSupport() aligns with the codebase's standardization efforts.

cmd/root.go (1)

65-70: LGTM! Enhanced error handling for help commands.

The improved error handling logic correctly suppresses config-not-found warnings during help commands while maintaining visibility for other scenarios.

pkg/list/list_workflows.go (1)

21-31: LGTM! Clean implementation of workflow extraction.

The function effectively extracts workflow information into a consistent format.

pkg/schema/schema.go (1)

160-161: LGTM! Clean addition of list configuration to Workflows struct.

The List field addition follows consistent struct tag patterns and integrates well with the existing schema.

cmd/list_workflows.go Show resolved Hide resolved
pkg/schema/schema.go Outdated Show resolved Hide resolved
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (1)
tests/snapshots/TestCLICommands_atmos_describe_config.stdout.golden (1)

37-41: Consider providing default values for better user experience.

The new workflow list configuration aligns well with the PR objectives, particularly supporting the --format flag requirement. However, consider providing sensible defaults:

  1. For format: Consider a default that matches common CLI tools (e.g., "table" or "json")
  2. For columns: Consider defining default columns that would be most useful for typical workflow listing

Example structure:

  "list": {
-    "format": "",
-    "columns": null
+    "format": "table",
+    "columns": ["name", "description", "path"]
  }
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 09f84b8 and 33b3ff2.

📒 Files selected for processing (1)
  • tests/snapshots/TestCLICommands_atmos_describe_config.stdout.golden (1 hunks)
⏰ Context from checks skipped due to timeout of 90000ms (5)
  • GitHub Check: Build (macos-latest, macos)
  • GitHub Check: Build (windows-latest, windows)
  • GitHub Check: Build (ubuntu-latest, linux)
  • GitHub Check: Analyze (go)
  • GitHub Check: Summary
🔇 Additional comments (1)
tests/snapshots/TestCLICommands_atmos_describe_config.stdout.golden (1)

37-41: Verify integration with terminal settings.

The new workflow list configuration should respect the terminal settings defined in the settings.terminal section (e.g., colors, max_width, unicode support).

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (3)
pkg/list/list_workflows.go (3)

30-40: Consider adding input validation

While the implementation is clean, consider adding defensive checks:

  • Validate that manifest.Workflows is not nil
  • Handle potential nil workflow descriptions
 func getWorkflowsFromManifest(manifest schema.WorkflowManifest) ([][]string, error) {
+    if manifest.Workflows == nil {
+        return nil, fmt.Errorf("invalid manifest: workflows map is nil")
+    }
     var rows [][]string
     for workflowName, workflow := range manifest.Workflows {
+        description := workflow.Description
+        if description == "" {
+            description = "No description provided"
+        }
         rows = append(rows, []string{
             manifest.Name,
             workflowName,
-            workflow.Description,
+            description,
         })
     }
     return rows, nil
 }

73-87: Extract example data to a separate function

Consider extracting the example workflow manifest to a dedicated function for better maintainability and testability.

+func getExampleWorkflowManifest() schema.WorkflowManifest {
+    return schema.WorkflowManifest{
+        Name: "example",
+        Workflows: schema.WorkflowConfig{
+            "test-1": schema.WorkflowDefinition{
+                Description: "Test workflow",
+                Steps: []schema.WorkflowStep{
+                    {Command: "echo Command 1", Name: "step1", Type: "shell"},
+                    {Command: "echo Command 2", Name: "step2", Type: "shell"},
+                    {Command: "echo Command 3", Name: "step3", Type: "shell"},
+                    {Command: "echo Command 4", Type: "shell"},
+                },
+            },
+        },
+    }
+}

144-156: Extract style configuration to constants

Consider extracting the style configuration to named constants for better maintainability and reusability across the codebase.

+const (
+    tablePaddingLeft  = 1
+    tablePaddingRight = 1
+)
+
+var tableHeaderStyle = lipgloss.NewStyle().
+    PaddingLeft(tablePaddingLeft).
+    PaddingRight(tablePaddingRight)
+
 t := table.New().
     Border(lipgloss.ThickBorder()).
     BorderStyle(lipgloss.NewStyle().Foreground(lipgloss.Color(theme.ColorBorder))).
     StyleFunc(func(row, col int) lipgloss.Style {
-        style := lipgloss.NewStyle().PaddingLeft(1).PaddingRight(1)
+        style := tableHeaderStyle
         if row == 0 {
             return style.Inherit(theme.Styles.CommandName).Align(lipgloss.Center)
         }
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 33b3ff2 and 2dacafc.

📒 Files selected for processing (1)
  • pkg/list/list_workflows.go (1 hunks)
⏰ Context from checks skipped due to timeout of 90000ms (2)
  • GitHub Check: Build (windows-latest, windows)
  • GitHub Check: Summary
🔇 Additional comments (2)
pkg/list/list_workflows.go (2)

21-27: Well-implemented OS-specific line endings!

The LineEnding function correctly handles platform-specific line endings, which is crucial for cross-platform compatibility.


108-139: Excellent implementation of multiple output formats!

The code effectively handles both JSON and CSV formats with proper delimiter support, making it versatile for different use cases.

pkg/list/list_workflows.go Outdated Show resolved Hide resolved
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (6)
pkg/list/list_workflows.go (3)

27-39: Consider using a constant for valid formats.

The validation logic is solid, but maintaining the valid formats list as a constant would improve maintainability.

+const (
+    validFormats = []string{FormatTable, FormatJSON, FormatCSV}
+)

 func ValidateFormat(format string) error {
     if format == "" {
         return nil
     }
-    validFormats := []string{FormatTable, FormatJSON, FormatCSV}
     for _, f := range validFormats {
         if format == f {
             return nil
         }
     }
     return fmt.Errorf("invalid format '%s'. Supported formats are: %s", format, strings.Join(validFormats, ", "))
 }

104-118: Consider moving example workflow to test helpers.

The example workflow could be moved to a test helper function to improve code organization and reusability.


143-147: Consider using constants for JSON field names.

Using constants for JSON field names would improve maintainability and prevent typos.

+const (
+    JSONFieldFile        = "file"
+    JSONFieldName        = "name"
+    JSONFieldDescription = "description"
+)

 type workflow struct {
-    File        string `json:"file"`
-    Name        string `json:"name"`
-    Description string `json:"description"`
+    File        string `json:"` + JSONFieldFile + `"`
+    Name        string `json:"` + JSONFieldName + `"`
+    Description string `json:"` + JSONFieldDescription + `"`
 }
pkg/list/list_workflows_test.go (2)

63-238: Consider adding more edge cases to the tests.

While the test coverage is good, consider adding these scenarios:

  • Malformed YAML file
  • Very large workflow files
  • Special characters in workflow names

240-332: Enhance test assertions for better validation.

Consider adding more specific assertions:

  • Verify exact content structure
  • Validate field ordering
  • Check for proper escaping in CSV format
pkg/schema/schema.go (1)

696-706: Consider adding more field validations.

The schema could benefit from additional validations:

  • Required fields validation
  • Value template syntax validation
  • Column name uniqueness check
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2dacafc and e125a03.

📒 Files selected for processing (3)
  • pkg/list/list_workflows.go (1 hunks)
  • pkg/list/list_workflows_test.go (1 hunks)
  • pkg/schema/schema.go (2 hunks)
⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: Summary
🔇 Additional comments (6)
pkg/list/list_workflows.go (4)

1-25: Clean package structure and format constants!

The package organization and format constants are well-defined and follow Go conventions.


41-47: Well-implemented OS-specific line ending handling!

The function correctly handles line endings for different operating systems.


171-202: Excellent table formatting with proper TTY handling!

The table formatting implementation is robust with proper styling and graceful fallback for non-TTY environments.


82-86: ⚠️ Potential issue

Add path validation for security.

The file path should be validated to prevent directory traversal attacks.

 if fileFlag != "" {
+    // Validate file path
+    cleanPath := filepath.Clean(fileFlag)
+    if !strings.HasSuffix(cleanPath, ".yaml") && !strings.HasSuffix(cleanPath, ".yml") {
+        return "", fmt.Errorf("invalid workflow file extension: %s", fileFlag)
+    }
+
     if _, err := os.Stat(fileFlag); os.IsNotExist(err) {
         return "", fmt.Errorf("workflow file not found: %s", fileFlag)
     }

Likely invalid or redundant comment.

pkg/list/list_workflows_test.go (1)

18-61: Comprehensive format validation tests!

The test cases cover all scenarios including empty format, valid formats, and invalid format.

pkg/schema/schema.go (1)

160-161: Clean integration of ListConfig field!

The List field is well-placed in the Workflows struct with proper tags.

pkg/list/list_workflows.go Outdated Show resolved Hide resolved
coderabbitai[bot]
coderabbitai bot previously approved these changes Jan 20, 2025
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (4)
pkg/list/list_workflows.go (4)

22-40: Consider using a map for format validation.

While the current implementation is correct, we can optimize the format validation by using a map for O(1) lookup instead of iterating through a slice.

 const (
 	FormatTable = "table"
 	FormatJSON  = "json"
 	FormatCSV   = "csv"
 )
 
+var validFormats = map[string]bool{
+	FormatTable: true,
+	FormatJSON:  true,
+	FormatCSV:   true,
+}
+
 // ValidateFormat checks if the given format is supported
 func ValidateFormat(format string) error {
 	if format == "" {
 		return nil
 	}
-	validFormats := []string{FormatTable, FormatJSON, FormatCSV}
-	for _, f := range validFormats {
-		if format == f {
-			return nil
-		}
+	if validFormats[format] {
+		return nil
 	}
+	formats := []string{FormatTable, FormatJSON, FormatCSV}
-	return fmt.Errorf("invalid format '%s'. Supported formats are: %s", format, strings.Join(validFormats, ", "))
+	return fmt.Errorf("invalid format '%s'. Supported formats are: %s", format, strings.Join(formats, ", "))
 }

42-48: Consider defining line ending constants.

The implementation is solid, but we could make it more maintainable by defining constants for the line endings.

+const (
+	windowsLineEnding = "\r\n"
+	unixLineEnding    = "\n"
+)
+
 // LineEnding returns the appropriate line ending for the current OS
 func LineEnding() string {
 	if runtime.GOOS == "windows" {
-		return "\r\n"
+		return windowsLineEnding
 	}
-	return "\n"
+	return unixLineEnding
 }

184-200: Extract table styling to a separate function.

The table styling logic could be moved to a separate function to improve maintainability.

+func createStyledTable(header []string, rows [][]string) *table.Table {
+	return table.New().
+		Border(lipgloss.ThickBorder()).
+		BorderStyle(lipgloss.NewStyle().Foreground(lipgloss.Color(theme.ColorBorder))).
+		StyleFunc(func(row, col int) lipgloss.Style {
+			style := lipgloss.NewStyle().PaddingLeft(1).PaddingRight(1)
+			if row == 0 {
+				return style.Inherit(theme.Styles.CommandName).Align(lipgloss.Center)
+			}
+			if row%2 == 0 {
+				return style.Inherit(theme.Styles.GrayText)
+			}
+			return style.Inherit(theme.Styles.Description)
+		}).
+		Headers(header...).
+		Rows(rows...)
+}
+
 		if format == "" && exec.CheckTTYSupport() {
-			// Create a styled table for TTY
-			t := table.New().
-				Border(lipgloss.ThickBorder()).
-				BorderStyle(lipgloss.NewStyle().Foreground(lipgloss.Color(theme.ColorBorder))).
-				StyleFunc(func(row, col int) lipgloss.Style {
-					style := lipgloss.NewStyle().PaddingLeft(1).PaddingRight(1)
-					if row == 0 {
-						return style.Inherit(theme.Styles.CommandName).Align(lipgloss.Center)
-					}
-					if row%2 == 0 {
-						return style.Inherit(theme.Styles.GrayText)
-					}
-					return style.Inherit(theme.Styles.Description)
-				}).
-				Headers(header...).
-				Rows(rows...)
+			t := createStyledTable(header, rows)

114-127: Move example workflow to a constant or separate function.

The example workflow could be moved to a constant or separate function to improve maintainability and make it easier to update.

+func getExampleWorkflow() schema.WorkflowManifest {
+	return schema.WorkflowManifest{
+		Name: "example",
+		Workflows: schema.WorkflowConfig{
+			"test-1": schema.WorkflowDefinition{
+				Description: "Test workflow",
+				Steps: []schema.WorkflowStep{
+					{Command: "echo Command 1", Name: "step1", Type: "shell"},
+					{Command: "echo Command 2", Name: "step2", Type: "shell"},
+					{Command: "echo Command 3", Name: "step3", Type: "shell"},
+					{Command: "echo Command 4", Type: "shell"},
+				},
+			},
+		},
+	}
+}
+
-		manifest := schema.WorkflowManifest{
-			Name: "example",
-			Workflows: schema.WorkflowConfig{
-				"test-1": schema.WorkflowDefinition{
-					Description: "Test workflow",
-					Steps: []schema.WorkflowStep{
-						{Command: "echo Command 1", Name: "step1", Type: "shell"},
-						{Command: "echo Command 2", Name: "step2", Type: "shell"},
-						{Command: "echo Command 3", Name: "step3", Type: "shell"},
-						{Command: "echo Command 4", Type: "shell"},
-					},
-				},
-			},
-		}
+		manifest := getExampleWorkflow()
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e125a03 and 25f6079.

📒 Files selected for processing (1)
  • pkg/list/list_workflows.go (1 hunks)
⏰ Context from checks skipped due to timeout of 90000ms (12)
  • GitHub Check: [mock-macos] tests/fixtures/scenarios/complete
  • GitHub Check: [mock-macos] examples/demo-vendoring
  • GitHub Check: [mock-windows] tests/fixtures/scenarios/complete
  • GitHub Check: [mock-windows] examples/demo-vendoring
  • GitHub Check: [mock-windows] examples/demo-context
  • GitHub Check: [mock-windows] examples/demo-component-versions
  • GitHub Check: Acceptance Tests (macos-latest, macos)
  • GitHub Check: Acceptance Tests (windows-latest, windows)
  • GitHub Check: Acceptance Tests (ubuntu-latest, linux)
  • GitHub Check: [k3s] demo-helmfile
  • GitHub Check: [localstack] demo-localstack
  • GitHub Check: Summary
🔇 Additional comments (2)
pkg/list/list_workflows.go (2)

1-20: LGTM! Clean package structure and well-organized imports.

The imports are properly grouped and all are being utilized in the implementation.


50-64: LGTM! Robust workflow extraction with proper nil checks.

The implementation correctly handles nil workflows and follows the suggestions from previous reviews.

pkg/list/list_workflows.go Show resolved Hide resolved
@Cerebrovinny Cerebrovinny requested a review from osterman January 20, 2025 08:14
Copy link
Member

@osterman osterman left a comment

Choose a reason for hiding this comment

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

Enable shapshots in test case yml. See other tests for example.

pkg/list/list_workflows.go Show resolved Hide resolved
Comment on lines +89 to +91
if !strings.HasSuffix(cleanPath, ".yaml") && !strings.HasSuffix(cleanPath, ".yml") {
return "", fmt.Errorf("invalid workflow file extension: %s", fileFlag)
}
Copy link
Member

Choose a reason for hiding this comment

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

We are doing this everywhere, I feel like handling multiple extensions should be generalized.

Copy link
Member

Choose a reason for hiding this comment

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

we also already have the strings .yaml and .yml as global constants, they need to be used in the code

Comment on lines +80 to +84
// Expected line ending based on OS
expectedLineEnding := "\n"
if runtime.GOOS == "windows" {
expectedLineEnding = "\r\n"
}
Copy link
Member

Choose a reason for hiding this comment

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

Should be something in one of our utility packages

Comment on lines +272 to +276
// Expected line ending based on OS
expectedLineEnding := "\n"
if runtime.GOOS == "windows" {
expectedLineEnding = "\r\n"
}
Copy link
Member

Choose a reason for hiding this comment

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

Repeated

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
minor New features that do not break anything
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants