• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

kubernetes-sigs / kubebuilder / 14165978911

31 Mar 2025 07:06AM UTC coverage: 72.693% (-0.3%) from 72.977%
14165978911

Pull #4675

github

kersten
refactor: convert CLI methods to use pointer receivers

Updated all CLI method receivers to use pointer semantics (*CLI)
instead of value (CLI), ensuring consistent behavior across command
setup functions and reducing potential for unintentional value copying.
Pull Request #4675: ⚠️ 🐛 (API) convert CLI methods to use pointer receivers

22 of 22 new or added lines in 9 files covered. (100.0%)

34 existing lines in 4 files now uncovered.

2300 of 3164 relevant lines covered (72.69%)

16.74 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

15.73
/pkg/plugin/util/util.go
1
/*
2
Copyright 2019 The Kubernetes Authors.
3

4
Licensed under the Apache License, Version 2.0 (the "License");
5
you may not use this file except in compliance with the License.
6
You may obtain a copy of the License at
7

8
    http://www.apache.org/licenses/LICENSE-2.0
9

10
Unless required by applicable law or agreed to in writing, software
11
distributed under the License is distributed on an "AS IS" BASIS,
12
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
See the License for the specific language governing permissions and
14
limitations under the License.
15
*/
16

17
package util
18

19
import (
20
        "bufio"
21
        "bytes"
22
        "crypto/rand"
23
        "errors"
24
        "fmt"
25
        "math/big"
26
        "os"
27
        "regexp"
28
        "strings"
29
)
30

31
const (
32
        // KubebuilderBinName define the name of the kubebuilder binary to be used in the tests
33
        KubebuilderBinName = "kubebuilder"
34
)
35

36
// RandomSuffix returns a 4-letter string.
37
func RandomSuffix() (string, error) {
3✔
38
        source := []rune("abcdefghijklmnopqrstuvwxyz")
3✔
39
        res := make([]rune, 4)
3✔
40
        for i := range res {
15✔
41
                bi := new(big.Int)
12✔
42
                r, err := rand.Int(rand.Reader, bi.SetInt64(int64(len(source))))
12✔
43
                if err != nil {
12✔
44
                        return "", err
×
45
                }
×
46
                res[i] = source[r.Int64()]
12✔
47
        }
48
        return string(res), nil
3✔
49
}
50

51
// GetNonEmptyLines converts given command output string into individual objects
52
// according to line breakers, and ignores the empty elements in it.
53
func GetNonEmptyLines(output string) []string {
3✔
54
        var res []string
3✔
55
        elements := strings.Split(output, "\n")
3✔
56
        for _, element := range elements {
11✔
57
                if element != "" {
12✔
58
                        res = append(res, element)
4✔
59
                }
4✔
60
        }
61

62
        return res
3✔
63
}
64

65
// InsertCode searches target content in the file and insert `toInsert` after the target.
66
func InsertCode(filename, target, code string) error {
2✔
67
        //nolint:gosec // false positive
2✔
68
        contents, err := os.ReadFile(filename)
2✔
69
        if err != nil {
2✔
70
                return err
×
71
        }
×
72
        idx := strings.Index(string(contents), target)
2✔
73
        if idx == -1 {
3✔
74
                return fmt.Errorf("string %s not found in %s", target, string(contents))
1✔
75
        }
1✔
76
        out := string(contents[:idx+len(target)]) + code + string(contents[idx+len(target):])
1✔
77
        //nolint:gosec // false positive
1✔
78
        return os.WriteFile(filename, []byte(out), 0o644)
1✔
79
}
80

81
// InsertCodeIfNotExist insert code if it does not already exists
82
func InsertCodeIfNotExist(filename, target, code string) error {
×
83
        //nolint:gosec // false positive
×
84
        contents, err := os.ReadFile(filename)
×
85
        if err != nil {
×
86
                return err
×
87
        }
×
88

89
        idx := strings.Index(string(contents), code)
×
90
        if idx != -1 {
×
91
                return nil
×
92
        }
×
93

94
        return InsertCode(filename, target, code)
×
95
}
96

97
// AppendCodeIfNotExist checks if the code does not already exist in the file, and if not, appends it to the end.
98
func AppendCodeIfNotExist(filename, code string) error {
×
99
        contents, err := os.ReadFile(filename)
×
100
        if err != nil {
×
101
                return err
×
102
        }
×
103

104
        if strings.Contains(string(contents), code) {
×
105
                return nil // Code already exists, no need to append.
×
106
        }
×
107

108
        return AppendCodeAtTheEnd(filename, code)
×
109
}
110

111
// AppendCodeAtTheEnd appends the given code at the end of the file.
112
func AppendCodeAtTheEnd(filename, code string) error {
×
113
        f, err := os.OpenFile(filename, os.O_APPEND|os.O_WRONLY, 0o644)
×
114
        if err != nil {
×
115
                return err
×
116
        }
×
117
        defer func() {
×
118
                if err := f.Close(); err != nil {
×
119
                        return
×
120
                }
×
121
        }()
122

123
        _, err = f.WriteString(code)
×
124
        return err
×
125
}
126

127
// UncommentCode searches for target in the file and remove the comment prefix
128
// of the target content. The target content may span multiple lines.
129
func UncommentCode(filename, target, prefix string) error {
×
130
        //nolint:gosec // false positive
×
131
        content, err := os.ReadFile(filename)
×
132
        if err != nil {
×
133
                return err
×
134
        }
×
135
        strContent := string(content)
×
136

×
137
        idx := strings.Index(strContent, target)
×
138
        if idx < 0 {
×
139
                return fmt.Errorf("unable to find the code %s to be uncomment", target)
×
140
        }
×
141

142
        out := new(bytes.Buffer)
×
143
        _, err = out.Write(content[:idx])
×
144
        if err != nil {
×
145
                return err
×
146
        }
×
147

148
        scanner := bufio.NewScanner(bytes.NewBufferString(target))
×
149
        if !scanner.Scan() {
×
150
                return nil
×
151
        }
×
152
        for {
×
153
                _, err := out.WriteString(strings.TrimPrefix(scanner.Text(), prefix))
×
154
                if err != nil {
×
155
                        return err
×
156
                }
UNCOV
157
                // Avoid writing a newline in case the previous line was the last in target.
×
158
                if !scanner.Scan() {
×
159
                        break
UNCOV
160
                }
×
161
                if _, err := out.WriteString("\n"); err != nil {
×
162
                        return err
×
163
                }
164
        }
UNCOV
165

×
166
        _, err = out.Write(content[idx+len(target):])
×
167
        if err != nil {
×
168
                return err
×
169
        }
UNCOV
170
        //nolint:gosec // false positive
×
171
        return os.WriteFile(filename, out.Bytes(), 0o644)
172
}
173

174
// CommentCode searches for target in the file and adds the comment prefix
UNCOV
175
// to the target content. The target content may span multiple lines.
×
176
func CommentCode(filename, target, prefix string) error {
×
177
        // Read the file content
×
178
        content, err := os.ReadFile(filename)
×
179
        if err != nil {
×
180
                return err
×
181
        }
×
182
        strContent := string(content)
×
183

×
184
        // Find the target code to be commented
×
185
        idx := strings.Index(strContent, target)
×
186
        if idx < 0 {
×
187
                return fmt.Errorf("unable to find the code %s to be commented", target)
×
188
        }
189

UNCOV
190
        // Create a buffer to hold the modified content
×
191
        out := new(bytes.Buffer)
×
192
        _, err = out.Write(content[:idx])
×
193
        if err != nil {
×
194
                return err
×
195
        }
196

UNCOV
197
        // Add the comment prefix to each line of the target code
×
198
        scanner := bufio.NewScanner(bytes.NewBufferString(target))
×
199
        for scanner.Scan() {
×
200
                _, err := out.WriteString(prefix + scanner.Text() + "\n")
×
201
                if err != nil {
×
202
                        return err
203
                }
204
        }
UNCOV
205

×
UNCOV
206
        // Write the rest of the file content
×
207
        _, err = out.Write(content[idx+len(target):])
×
208
        if err != nil {
×
209
                return err
210
        }
UNCOV
211

×
212
        // Write the modified content back to the file
213
        return os.WriteFile(filename, out.Bytes(), 0o644)
214
}
UNCOV
215

×
UNCOV
216
// EnsureExistAndReplace check if the content exists and then do the replace
×
217
func EnsureExistAndReplace(input, match, replace string) (string, error) {
×
218
        if !strings.Contains(input, match) {
×
219
                return "", fmt.Errorf("can't find %q", match)
×
220
        }
221
        return strings.Replace(input, match, replace, -1), nil
222
}
UNCOV
223

×
UNCOV
224
// ReplaceInFile replaces all instances of old with new in the file at path.
×
225
func ReplaceInFile(path, oldValue, newValue string) error {
×
226
        info, err := os.Stat(path)
×
227
        if err != nil {
×
228
                return err
229
        }
×
UNCOV
230
        //nolint:gosec // false positive
×
231
        b, err := os.ReadFile(path)
×
232
        if err != nil {
×
233
                return err
×
234
        }
×
235
        if !strings.Contains(string(b), oldValue) {
×
236
                return errors.New("unable to find the content to be replaced")
×
237
        }
×
238
        s := strings.Replace(string(b), oldValue, newValue, -1)
×
239
        err = os.WriteFile(path, []byte(s), info.Mode())
×
240
        if err != nil {
×
241
                return err
×
242
        }
243
        return nil
244
}
245

246
// ReplaceRegexInFile finds all strings that match `match` and replaces them
247
// with `replace` in the file at path.
248
func ReplaceRegexInFile(path, match, replace string) error {
249
        matcher, err := regexp.Compile(match)
×
250
        if err != nil {
×
251
                return err
×
252
        }
×
253
        info, err := os.Stat(path)
×
254
        if err != nil {
×
255
                return err
×
256
        }
×
UNCOV
257
        //nolint:gosec // false positive
×
258
        b, err := os.ReadFile(path)
259
        if err != nil {
×
260
                return err
×
261
        }
×
262
        s := matcher.ReplaceAllString(string(b), replace)
×
263
        if s == string(b) {
×
264
                return errors.New("unable to find the content to be replaced")
×
265
        }
×
266
        err = os.WriteFile(path, []byte(s), info.Mode())
×
267
        if err != nil {
×
268
                return err
×
269
        }
×
270
        return nil
×
UNCOV
271
}
×
272

273
// HasFileContentWith check if given `text` can be found in file
274
func HasFileContentWith(path, text string) (bool, error) {
275
        //nolint:gosec
×
276
        contents, err := os.ReadFile(path)
×
277
        if err != nil {
×
278
                return false, err
×
279
        }
×
UNCOV
280

×
281
        return strings.Contains(string(contents), text), nil
UNCOV
282
}
×
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc