diff --git a/internal/config/attribution_migration_test.go b/internal/config/attribution_migration_test.go new file mode 100644 index 0000000000000000000000000000000000000000..6f54b170ad4e4eb815e7cf22793584cb2ba4c9e4 --- /dev/null +++ b/internal/config/attribution_migration_test.go @@ -0,0 +1,95 @@ +package config + +import ( + "io" + "strings" + "testing" + + "github.com/stretchr/testify/require" +) + +func TestAttributionMigration(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + configJSON string + expectedTrailer TrailerStyle + expectedGenerate bool + }{ + { + name: "old setting co_authored_by=true migrates to co-authored-by", + configJSON: `{ + "options": { + "attribution": { + "co_authored_by": true, + "generated_with": false + } + } + }`, + expectedTrailer: TrailerStyleCoAuthoredBy, + expectedGenerate: false, + }, + { + name: "old setting co_authored_by=false migrates to none", + configJSON: `{ + "options": { + "attribution": { + "co_authored_by": false, + "generated_with": true + } + } + }`, + expectedTrailer: TrailerStyleNone, + expectedGenerate: true, + }, + { + name: "new setting takes precedence over old setting", + configJSON: `{ + "options": { + "attribution": { + "trailer_style": "assisted-by", + "co_authored_by": true, + "generated_with": false + } + } + }`, + expectedTrailer: TrailerStyleAssistedBy, + expectedGenerate: false, + }, + { + name: "default when neither setting present", + configJSON: `{ + "options": { + "attribution": { + "generated_with": true + } + } + }`, + expectedTrailer: TrailerStyleCoAuthoredBy, + expectedGenerate: true, + }, + { + name: "default when attribution is null", + configJSON: `{ + "options": {} + }`, + expectedTrailer: TrailerStyleCoAuthoredBy, + expectedGenerate: true, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + cfg, err := loadFromReaders([]io.Reader{strings.NewReader(tt.configJSON)}) + require.NoError(t, err) + + cfg.setDefaults(t.TempDir(), "") + + require.Equal(t, tt.expectedTrailer, cfg.Options.Attribution.TrailerStyle) + require.Equal(t, tt.expectedGenerate, cfg.Options.Attribution.GeneratedWith) + }) + } +} diff --git a/internal/config/config.go b/internal/config/config.go index b88ff26c9d82c9b00f4cfaa0716ed7b6881233ef..9d49c554034a59a6f549660297d2c59e10536c8b 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -14,6 +14,7 @@ import ( "github.com/charmbracelet/catwalk/pkg/catwalk" "github.com/charmbracelet/crush/internal/csync" "github.com/charmbracelet/crush/internal/env" + "github.com/invopop/jsonschema" "github.com/tidwall/sjson" ) @@ -176,9 +177,19 @@ const ( type Attribution struct { TrailerStyle TrailerStyle `json:"trailer_style,omitempty" jsonschema:"description=Style of attribution trailer to add to commits,enum=none,enum=co-authored-by,enum=assisted-by,default=co-authored-by"` + CoAuthoredBy *bool `json:"co_authored_by,omitempty" jsonschema:"description=Deprecated: use trailer_style instead"` GeneratedWith bool `json:"generated_with,omitempty" jsonschema:"description=Add Generated with Crush line to commit messages and issues and PRs,default=true"` } +// JSONSchemaExtend marks the co_authored_by field as deprecated in the schema. +func (Attribution) JSONSchemaExtend(schema *jsonschema.Schema) { + if schema.Properties != nil { + if prop, ok := schema.Properties.Get("co_authored_by"); ok { + prop.Deprecated = true + } + } +} + type Options struct { ContextPaths []string `json:"context_paths,omitempty" jsonschema:"description=Paths to files containing context information for the AI,example=.cursorrules,example=CRUSH.md"` TUI *TUIOptions `json:"tui,omitempty" jsonschema:"description=Terminal user interface options"` diff --git a/internal/config/load.go b/internal/config/load.go index 80eb031218ceb52a36adaf258c3974f84a0b4db9..77c9377445acadbdeeb49b97996f9a45be0b6dc3 100644 --- a/internal/config/load.go +++ b/internal/config/load.go @@ -356,6 +356,13 @@ func (c *Config) setDefaults(workingDir, dataDir string) { TrailerStyle: TrailerStyleCoAuthoredBy, GeneratedWith: true, } + } else if c.Options.Attribution.TrailerStyle == "" { + // Migrate deprecated co_authored_by or apply default + if c.Options.Attribution.CoAuthoredBy != nil && !*c.Options.Attribution.CoAuthoredBy { + c.Options.Attribution.TrailerStyle = TrailerStyleNone + } else { + c.Options.Attribution.TrailerStyle = TrailerStyleCoAuthoredBy + } } } diff --git a/schema.json b/schema.json index 3a86224fe809816550e61c17b28ded9932656699..61b230aaaea72a4af9c0edab85021760f3d1c199 100644 --- a/schema.json +++ b/schema.json @@ -15,6 +15,11 @@ "description": "Style of attribution trailer to add to commits", "default": "co-authored-by" }, + "co_authored_by": { + "type": "boolean", + "description": "Deprecated: use trailer_style instead", + "deprecated": true + }, "generated_with": { "type": "boolean", "description": "Add Generated with Crush line to commit messages and issues and PRs",