-
Notifications
You must be signed in to change notification settings - Fork 37
/
change.go
161 lines (132 loc) · 4.01 KB
/
change.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
package core
import (
"fmt"
"io"
"sort"
"strings"
"time"
"gopkg.in/yaml.v2"
"github.com/miniscruff/changie/shared"
)
type ChangesConfigSorter struct {
changes []Change
config Config
}
func SortByConfig(config *Config) *ChangesConfigSorter {
return &ChangesConfigSorter{
config: *config,
}
}
// Sort sorts the argument slice according to the less functions passed to OrderedBy.
func (s *ChangesConfigSorter) Sort(changes []Change) {
s.changes = changes
sort.Sort(s)
}
// Len is part of sort.Interface.
func (s *ChangesConfigSorter) Len() int {
return len(s.changes)
}
// Swap is part of sort.Interface.
func (s *ChangesConfigSorter) Swap(i, j int) {
s.changes[i], s.changes[j] = s.changes[j], s.changes[i]
}
// Less will compare two Change values with the config settings.
// * Components, if enabled, are sorted by index in config
// * Kind, if enabled, are sorted by index in config
// * Time sorted newest first
func (s *ChangesConfigSorter) Less(i, j int) bool {
a, b := &s.changes[i], &s.changes[j]
// Start by sorting by component index
if len(s.config.Components) > 0 && a.Component != b.Component {
for _, c := range s.config.Components {
if a.Component == c {
return true
} else if b.Component == c {
return false
}
}
}
// Then sort by kind index
if len(s.config.Kinds) > 0 && a.Kind != b.Kind {
for _, k := range s.config.Kinds {
if a.Kind == k.Label {
return true
} else if b.Kind == k.Label {
return false
}
}
}
// Finish sort by oldest first
return b.Time.After(a.Time)
}
// Change represents an atomic change to a project.
type Change struct {
// Project of our change, if one was provided.
Project string `yaml:",omitempty" default:""`
// Component of our change, if one was provided.
Component string `yaml:",omitempty" default:""`
// Kind of our change, if one was provided.
Kind string `yaml:",omitempty" default:""`
// Body message of our change, if one was provided.
Body string `yaml:",omitempty" default:""`
// When our change was made.
Time time.Time `yaml:"" required:"true"`
// Custom values corresponding to our options where each key-value pair is the key of the custom option
// and value the one provided in the change.
// example: yaml
// custom:
// - key: Issue
// type: int
// changeFormat: "{{.Body}} from #{{.Custom.Issue}}"
Custom map[string]string `yaml:",omitempty" default:"nil"`
// Env vars configured by the system.
// This is not written in change fragments but instead loaded by the system and accessible for templates.
// For example if you want to use an env var in [change format](#config-changeformat) you can,
// but env vars configured when executing `changie new` will not be saved.
// See [envPrefix](#config-envprefix) for configuration.
Env map[string]string `yaml:"-" default:"nil"`
// Filename the change was saved to.
Filename string `yaml:"-"`
}
// WriteTo will write a change to the writer as YAML
func (change Change) WriteTo(writer io.Writer) (int64, error) {
bs, _ := yaml.Marshal(&change)
n, err := writer.Write(bs)
return int64(n), err
}
func (change *Change) PostProcess(cfg *Config, kind *KindConfig) error {
postConfigs := make([]PostProcessConfig, 0)
if kind == nil || !kind.SkipGlobalPost {
postConfigs = append(postConfigs, cfg.Post...)
}
if kind != nil {
postConfigs = append(postConfigs, kind.Post...)
}
if len(postConfigs) == 0 {
return nil
}
templateCache := NewTemplateCache()
for _, post := range postConfigs {
writer := strings.Builder{}
err := templateCache.Execute(post.Value, &writer, change)
if err != nil {
return err
}
change.Custom[post.Key] = writer.String()
}
return nil
}
// LoadChange will load a change from file path
func LoadChange(path string, rf shared.ReadFiler) (Change, error) {
var c Change
bs, err := rf(path)
if err != nil {
return c, fmt.Errorf("reading change file '%s': %w", path, err)
}
err = yaml.Unmarshal(bs, &c)
if err != nil {
return c, fmt.Errorf("unmarshaling change file '%s': %w", path, err)
}
c.Filename = path
return c, nil
}