Skip to content

refactor: extract shared project config parsing helpers to eliminate duplication - #20939

Merged
pelikhan merged 5 commits into
mainfrom
copilot/refactor-duplicate-project-config-parsing
Mar 14, 2026
Merged

refactor: extract shared project config parsing helpers to eliminate duplication#20939
pelikhan merged 5 commits into
mainfrom
copilot/refactor-duplicate-project-config-parsing

Conversation

CopilotAI commented Mar 14, 2026

Copy link
Copy Markdown
Contributor

parseCreateProjectsConfig and parseUpdateProjectConfig contained ~100 lines of identical views and field-definitions parsing logic, creating a divergence risk where fixes or schema changes had to be applied twice.

Changes

  • pkg/workflow/project_config_parsing.go (new): two standalone helpers:

    • parseProjectViews(configMap map[string]any, log *logger.Logger) []ProjectView
    • parseProjectFieldDefinitions(configMap map[string]any, log *logger.Logger) []ProjectFieldDefinition
  • create_project.go / update_project.go: inline parsing blocks replaced with calls to the shared helpers; per-file loggers are passed through so debug output remains contextual.

  • pkg/workflow/project_config_parsing_test.go (new): table-driven tests for each helper (missing keys, invalid items, all optional fields) plus a parity test asserting both command paths produce identical results for the same input.

// Before: ~50 lines of inline loops in each of create_project.go and update_project.go// After:createProjectsConfig.Views=parseProjectViews(configMap, createProjectLog)
createProjectsConfig.FieldDefinitions=parseProjectFieldDefinitions(configMap, createProjectLog)

CopilotAIand others added 2 commits March 14, 2026 04:01
…duplication
Extract parseProjectViews and parseProjectFieldDefinitions from the duplicated
blocks in parseCreateProjectsConfig and parseUpdateProjectConfig into a shared
pkg/workflow/project_config_parsing.go file.
Both methods now delegate to the helpers, eliminating ~100 lines of duplicated
code and ensuring a single source of truth for views/field-definitions parsing.
Also adds parity tests in project_config_parsing_test.go covering the helpers
directly and verifying identical behavior from both the create and update paths.
Fixes #<issue>"
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
CopilotAI review requested due to automatic review settings March 14, 2026 14:21

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Refactors duplicated views and field-definitions parsing logic out of the create/update project config paths into shared helpers to reduce drift and centralize behavior.

Changes:

  • Added shared parsing helpers for project views and field-definitions.
  • Updated create-project and update-project config parsing to call the shared helpers.
  • Added new unit tests covering the helpers plus a parity check across both command paths.

Reviewed changes

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

FileDescription
pkg/workflow/project_config_parsing.goNew shared parsing helpers for views and field-definitions.
pkg/workflow/create_project.goReplaces inline parsing with calls to shared helpers.
pkg/workflow/update_project.goReplaces inline parsing with calls to shared helpers.
pkg/workflow/project_config_parsing_test.goNew table-driven tests for helper behavior and create/update parity.

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

You can also share your feedback on Copilot code review. Take the survey.

Comment on lines +18 to +136
func TestParseProjectViews(t *testing.T) {
tests := []struct {
name string
input map[string]any
expected []ProjectView
}{
{
name: "no views key",
input: map[string]any{},
expected: nil,
},
{
name: "empty views list",
input: map[string]any{
"views": []any{},
},
expected: nil,
},
{
name: "single valid view with required fields only",
input: map[string]any{
"views": []any{
map[string]any{
"name": "Board",
"layout": "board",
},
},
},
expected: []ProjectView{
{Name: "Board", Layout: "board"},
},
},
{
name: "view with all optional fields",
input: map[string]any{
"views": []any{
map[string]any{
"name": "Task Board",
"layout": "board",
"filter": "is:issue",
"visible-fields": []any{1, 2, 3},
"description": "Main board",
},
},
},
expected: []ProjectView{
{
Name: "Task Board",
Layout: "board",
Filter: "is:issue",
VisibleFields: []int{1, 2, 3},
Description: "Main board",
},
},
},
{
name: "view missing name is skipped",
input: map[string]any{
"views": []any{
map[string]any{"layout": "board"},
},
},
expected: nil,
},
{
name: "view missing layout is skipped",
input: map[string]any{
"views": []any{
map[string]any{"name": "Board"},
},
},
expected: nil,
},
{
name: "mix of valid and invalid views",
input: map[string]any{
"views": []any{
map[string]any{
"name": "Valid",
"layout": "table",
},
map[string]any{
// Missing layout
"name": "Invalid",
},
map[string]any{
"name": "Also Valid",
"layout": "roadmap",
},
},
},
expected: []ProjectView{
{Name: "Valid", Layout: "table"},
{Name: "Also Valid", Layout: "roadmap"},
},
},
{
name: "non-map view item is skipped",
input: map[string]any{
"views": []any{
"not-a-map",
map[string]any{
"name": "Good",
"layout": "board",
},
},
},
expected: []ProjectView{
{Name: "Good", Layout: "board"},
},
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
result := parseProjectViews(tt.input, testLog)
assert.Equal(t, tt.expected, result, "parseProjectViews result should match expected")
})
}
Comment on lines +24 to +35
{
name: "no views key",
input: map[string]any{},
expected: nil,
},
{
name: "empty views list",
input: map[string]any{
"views": []any{},
},
expected: nil,
},
@pelikhan

Copy link
Copy Markdown
Collaborator

@copilot review comments

- Add wrong container type cases for views and field-definitions
(string/map instead of []any) to lock in nil-early-return behavior
- Add mixed-type visible-fields and options cases to document that
non-int/non-string elements are silently skipped
- Use assert.Empty for nil-expected cases to avoid brittle
nil-vs-empty-slice comparisons
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>

CopilotAI commented Mar 14, 2026

Copy link
Copy Markdown
ContributorAuthor

@copilot review comments

Addressed both review comments in c398e7c:

  1. Added wrong-container-type test cases ("views": "not-a-list", "views": map[string]any{...}, and equivalent for field-definitions) to lock in the early-return behavior.
  2. Added mixed-type element cases: visible-fields with non-int values and options with non-string values — both document that invalid elements are silently skipped.
  3. Replaced assert.Equal(t, nil, result, ...) with assert.Empty(t, result, ...) for all nil-result cases to avoid brittle nil-vs-empty-slice comparisons.

@pelikhan
pelikhan merged commit 052be9d into mainMar 14, 2026
52 checks passed
@pelikhan
pelikhan deleted the copilot/refactor-duplicate-project-config-parsing branch March 14, 2026 14:38
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Duplicate Code: project config parsing duplicated in create/update project handlers

3 participants

@pelikhan