diff --git a/application/source/config.go b/application/source/config.go index b6cc83a1e92d571dc0ef58a25d0d2d4993cf3bf0..84ef8bc49710418fff8cd1ed9e7b2b4e31549dd5 100644 --- a/application/source/config.go +++ b/application/source/config.go @@ -31,7 +31,7 @@ type Configuration struct { Gitlab struct { Token string `yaml:"Token"` - } `yaml:"GitLab"` + } `yaml:"Gitlab"` Overview struct { Template struct { diff --git a/application/source/gitlab.go b/application/source/gitlab.go index 242f9167b310d5d18ce1dffd532125bcde3864a2..3518acc6e6725ac416bd6ddba8dd8449b9caaaa9 100644 --- a/application/source/gitlab.go +++ b/application/source/gitlab.go @@ -1,9 +1,13 @@ package main import ( + "errors" + "fmt" "net/url" "path" + "gopkg.in/yaml.v3" + "github.com/go-git/go-git/v5" "github.com/xanzy/go-gitlab" ) @@ -168,6 +172,83 @@ func syncFilesWithGitlab() error { } +func nodesEqual(l, r *yaml.Node) bool { + if l.Kind == yaml.ScalarNode && r.Kind == yaml.ScalarNode { + return l.Value == r.Value + } + panic("equals on non-scalars not implemented!") +} + +func recursiveRemove(nodes *yaml.Node) error { + + if nodes.Kind == yaml.DocumentNode { + recursiveRemove(nodes.Content[0]) + } + + if nodes.Kind != yaml.MappingNode { + return nil + } + + var found int + + for i := 0; i < len(nodes.Content); i += 2 { + + fmt.Println(nodes.Content[i].Value) + + if nodes.Content[i].Value == "Issues" { + found = i + break + } + + if err := recursiveRemove(nodes.Content[i+1]); err != nil { + return errors.New("at key " + nodes.Content[i].Value + ": " + err.Error()) + } + + } + + if found > 0 { + + copy(nodes.Content[found:], nodes.Content[found+2:]) // Shift a[i+1:] left one index. + nodes.Content[len(nodes.Content)-1] = nil // Erase last element (write zero value). + nodes.Content[len(nodes.Content)-2] = nil // Erase last element (write zero value). + nodes.Content = nodes.Content[:len(nodes.Content)-2] + } + + return nil +} + +func recursiveMerge(from, into *yaml.Node) error { + if from.Kind != into.Kind { + return errors.New("cannot merge nodes of different kinds") + } + switch from.Kind { + case yaml.MappingNode: + for i := 0; i < len(from.Content); i += 2 { + found := false + for j := 0; j < len(into.Content); j += 2 { + if nodesEqual(from.Content[i], into.Content[j]) { + found = true + + if err := recursiveMerge(from.Content[i+1], into.Content[j+1]); err != nil { + return errors.New("at key " + from.Content[i].Value + ": " + err.Error()) + } + break + } + } + if !found { + into.Content = append(into.Content, from.Content[i:i+2]...) + } + } + case yaml.SequenceNode: + into.Content = append(into.Content, from.Content...) + case yaml.DocumentNode: + recursiveMerge(from.Content[0], into.Content[0]) + default: + return errors.New("can only merge mapping and sequence nodes") + } + return nil +} + func syncIssuesWithGitlab(pageData map[string]*requirement) { for _, pageData := range pageData { @@ -185,6 +266,15 @@ func syncIssuesWithGitlab(pageData map[string]*requirement) { } pageData.Issues[k].GitlabRemote = issue pageData.Issues[k].GitlabIntern.ID = issue.IID + + var change yaml.Node + bytes, err := yaml.Marshal(&pageData) + if err != nil { + fmt.Println(err) + } + yaml.Unmarshal(bytes, &change) + recursiveRemove(pageData.OriginNode) + recursiveMerge(&change, pageData.OriginNode) } } diff --git a/application/source/issues.go b/application/source/issues.go index 355fa63aed6ac5c0749bba2df5c82d320ff43e48..221b3243614181d9b4d866157adac5081dc75fdf 100644 --- a/application/source/issues.go +++ b/application/source/issues.go @@ -23,7 +23,7 @@ type GitlabInternalIssueStruct struct { type Issue struct { GitlabIntern *GitlabInternalIssueStruct `yaml:"Gitlab"` - GitlabRemote *gitlab.Issue + GitlabRemote *gitlab.Issue `yaml:"-"` } func loadIssuesFromGitlab(context *gitlabContext, issueID int) (*gitlab.Issue, error) { diff --git a/application/source/requirements.go b/application/source/requirements.go index d4a323f70469383e8e421c8c193d875ed42b33bd..02a3b4020b00e235afbafc7500a55947e6800bf0 100644 --- a/application/source/requirements.go +++ b/application/source/requirements.go @@ -17,16 +17,16 @@ import ( ) type requirement struct { - ToDos []task - Absolute string - File string + ToDos []task `yaml:"-"` + Absolute string `yaml:"-"` + File string `yaml:"-"` Items []Item `yaml:"Items"` Privacy []Privacy `yaml:"Privacy"` Issues []Issue `yaml:"Issues"` // remember the node structure of yaml - OriginNode *yaml.Node - OriginText string + OriginNode *yaml.Node `yaml:"-"` + OriginText string `yaml:"-"` ID string `yaml:"ID"` References []string `yaml:"References"`