diff --git a/pkg/config/app_config.go b/pkg/config/app_config.go index 27ee38c0bfb..3a7186dea5c 100644 --- a/pkg/config/app_config.go +++ b/pkg/config/app_config.go @@ -722,6 +722,14 @@ type CachedPullRequest struct { HeadRepositoryOwner string `yaml:"headRepositoryOwner"` } +// MarshalYAML trims fields that break YAML round-trips when cached to state.yml. +func (pr CachedPullRequest) MarshalYAML() (interface{}, error) { + type cachedPullRequest CachedPullRequest + sanitized := cachedPullRequest(pr) + sanitized.Title = strings.TrimSpace(pr.Title) + return sanitized, nil +} + func getDefaultAppState() *AppState { return &AppState{ GithubPullRequests: make(map[string][]CachedPullRequest), diff --git a/pkg/config/cached_pull_request_test.go b/pkg/config/cached_pull_request_test.go new file mode 100644 index 00000000000..6038b6d6338 --- /dev/null +++ b/pkg/config/cached_pull_request_test.go @@ -0,0 +1,32 @@ +package config + +import ( + "testing" + + "gopkg.in/yaml.v3" +) + +func TestCachedPullRequestTitleYAMLRoundTrip(t *testing.T) { + t.Parallel() + + state := AppState{ + GithubPullRequests: map[string][]CachedPullRequest{ + "/tmp/repo": {{ + HeadRefName: "example-branch", + Number: 9, + Title: "\nExample pull request title", + State: "MERGED", + }}, + }, + } + + data, err := yaml.Marshal(&state) + if err != nil { + t.Fatal(err) + } + + var decoded AppState + if err := yaml.Unmarshal(data, &decoded); err != nil { + t.Fatalf("yaml unmarshal failed: %v\n%s", err, data) + } +} diff --git a/pkg/gui/controllers/helpers/refresh_helper.go b/pkg/gui/controllers/helpers/refresh_helper.go index 2922b44037d..bca42db0c98 100644 --- a/pkg/gui/controllers/helpers/refresh_helper.go +++ b/pkg/gui/controllers/helpers/refresh_helper.go @@ -973,7 +973,7 @@ func (self *RefreshHelper) savePullRequestsToCache(prs []*models.GithubPullReque return config.CachedPullRequest{ HeadRefName: pr.HeadRefName, Number: pr.Number, - Title: pr.Title, + Title: strings.TrimSpace(pr.Title), State: pr.State, Url: pr.Url, HeadRepositoryOwner: pr.HeadRepositoryOwner.Login,