-
Notifications
You must be signed in to change notification settings - Fork 205
Ensure to load image watcher config #1251
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -14,6 +14,13 @@ | |
|
|
||
| package config | ||
|
|
||
| import ( | ||
| "fmt" | ||
| "io/ioutil" | ||
| "os" | ||
| "path/filepath" | ||
| ) | ||
|
|
||
| type ImageWatcherSpec struct { | ||
| Targets []ImageWatcherTarget `json:"targets"` | ||
| } | ||
|
|
@@ -25,12 +32,79 @@ type ImageWatcherTarget struct { | |
| Field string `json:"field"` | ||
| } | ||
|
|
||
| // LoadImageWatcher finds the config files for the image watcher in the .pipe directory first up. | ||
| // And returns parsed config, False is returned as the second returned value if not found. | ||
| // LoadImageWatcher finds the config files for the image watcher in the .pipe | ||
| // directory first up. And returns parsed config after merging the targets. | ||
| // Only one of includes or excludes can be used. | ||
| // False is returned as the second returned value if not found. | ||
| func LoadImageWatcher(repoRoot string, includes, excludes []string) (*ImageWatcherSpec, bool, error) { | ||
| // TODO: Load image watcher config | ||
| // referring to AnalysisTemplateSpec | ||
| return nil, false, nil | ||
| dir := filepath.Join(repoRoot, SharedConfigurationDirName) | ||
| files, err := ioutil.ReadDir(dir) | ||
| if os.IsNotExist(err) { | ||
| return nil, false, nil | ||
| } | ||
| if err != nil { | ||
| return nil, false, fmt.Errorf("failed to read %s: %w", dir, err) | ||
| } | ||
|
|
||
| spec := &ImageWatcherSpec{ | ||
| Targets: make([]ImageWatcherTarget, 0), | ||
| } | ||
| filtered, err := filterImageWatcherFiles(files, includes, excludes) | ||
| if err != nil { | ||
| return nil, false, fmt.Errorf("failed to filter image watcher files at %s: %w", dir, err) | ||
| } | ||
| for _, f := range filtered { | ||
| if f.IsDir() { | ||
| continue | ||
| } | ||
| path := filepath.Join(dir, f.Name()) | ||
| cfg, err := LoadFromYAML(path) | ||
| if err != nil { | ||
| return nil, false, fmt.Errorf("failed to load config file %s: %w", path, err) | ||
| } | ||
| if cfg.Kind == KindImageWatcher { | ||
| spec.Targets = append(spec.Targets, cfg.ImageWatcherSpec.Targets...) | ||
| } | ||
| } | ||
| if len(spec.Targets) == 0 { | ||
| return nil, false, nil | ||
| } | ||
|
|
||
| return spec, true, nil | ||
| } | ||
|
|
||
| // filterImageWatcherFiles filters the given files based on the given Includes and Excludes. | ||
| // Excludes are prioritized if both Excludes and Includes are given. | ||
| func filterImageWatcherFiles(files []os.FileInfo, includes, excludes []string) ([]os.FileInfo, error) { | ||
| if len(includes) == 0 && len(excludes) == 0 { | ||
| return files, nil | ||
| } | ||
|
|
||
| filtered := make([]os.FileInfo, 0, len(files)) | ||
| useWhitelist := len(includes) != 0 && len(excludes) == 0 | ||
| if useWhitelist { | ||
| whiteList := make(map[string]struct{}, len(includes)) | ||
| for _, i := range includes { | ||
| whiteList[i] = struct{}{} | ||
| } | ||
| for _, f := range files { | ||
| if _, ok := whiteList[f.Name()]; ok { | ||
| filtered = append(filtered, f) | ||
| } | ||
| } | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I expected it will be pointed out by you lol
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 😄
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Gotcha 😄 |
||
| return filtered, nil | ||
| } | ||
|
|
||
| blackList := make(map[string]struct{}, len(excludes)) | ||
| for _, e := range excludes { | ||
| blackList[e] = struct{}{} | ||
| } | ||
| for _, f := range files { | ||
| if _, ok := blackList[f.Name()]; !ok { | ||
| filtered = append(filtered, f) | ||
| } | ||
| } | ||
| return filtered, nil | ||
| } | ||
|
|
||
| func (s *ImageWatcherSpec) Validate() error { | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,126 @@ | ||
| // Copyright 2020 The PipeCD Authors. | ||
| // | ||
| // Licensed under the Apache License, Version 2.0 (the "License"); | ||
| // you may not use this file except in compliance with the License. | ||
| // You may obtain a copy of the License at | ||
| // | ||
| // http://www.apache.org/licenses/LICENSE-2.0 | ||
| // | ||
| // Unless required by applicable law or agreed to in writing, software | ||
| // distributed under the License is distributed on an "AS IS" BASIS, | ||
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| // See the License for the specific language governing permissions and | ||
| // limitations under the License. | ||
|
|
||
| package config | ||
|
|
||
| import ( | ||
| "os" | ||
| "testing" | ||
| "time" | ||
|
|
||
| "github.com/stretchr/testify/assert" | ||
| ) | ||
|
|
||
| type fakeFileInfo struct { | ||
| name string | ||
| } | ||
|
|
||
| func (f *fakeFileInfo) Name() string { return f.name } | ||
|
|
||
| // Below methods are required to meet the interface. | ||
| func (f *fakeFileInfo) Size() int64 { return 0 } | ||
| func (f *fakeFileInfo) Mode() os.FileMode { return 0 } | ||
| func (f *fakeFileInfo) ModTime() time.Time { return time.Now() } | ||
| func (f *fakeFileInfo) IsDir() bool { return false } | ||
| func (f *fakeFileInfo) Sys() interface{} { return nil } | ||
|
|
||
| func TestFilterImageWatcherFiles(t *testing.T) { | ||
| testcases := []struct { | ||
| name string | ||
| files []os.FileInfo | ||
| includes []string | ||
| excludes []string | ||
| want []os.FileInfo | ||
| wantErr bool | ||
| }{ | ||
| { | ||
| name: "both includes and excludes aren't given", | ||
| files: []os.FileInfo{ | ||
| &fakeFileInfo{ | ||
| name: "file-1", | ||
| }, | ||
| }, | ||
| want: []os.FileInfo{ | ||
| &fakeFileInfo{ | ||
| name: "file-1", | ||
| }, | ||
| }, | ||
| wantErr: false, | ||
| }, | ||
| { | ||
| name: "both includes and excludes are given", | ||
| files: []os.FileInfo{ | ||
| &fakeFileInfo{ | ||
| name: "file-1", | ||
| }, | ||
| }, | ||
| want: []os.FileInfo{}, | ||
| includes: []string{"file-1"}, | ||
| excludes: []string{"file-1"}, | ||
| wantErr: false, | ||
| }, | ||
| { | ||
| name: "includes given", | ||
| files: []os.FileInfo{ | ||
| &fakeFileInfo{ | ||
| name: "file-1", | ||
| }, | ||
| &fakeFileInfo{ | ||
| name: "file-2", | ||
| }, | ||
| &fakeFileInfo{ | ||
| name: "file-3", | ||
| }, | ||
| }, | ||
| includes: []string{"file-1", "file-3"}, | ||
| want: []os.FileInfo{ | ||
| &fakeFileInfo{ | ||
| name: "file-1", | ||
| }, | ||
| &fakeFileInfo{ | ||
| name: "file-3", | ||
| }, | ||
| }, | ||
| wantErr: false, | ||
| }, | ||
| { | ||
| name: "excludes given", | ||
| files: []os.FileInfo{ | ||
| &fakeFileInfo{ | ||
| name: "file-1", | ||
| }, | ||
| &fakeFileInfo{ | ||
| name: "file-2", | ||
| }, | ||
| &fakeFileInfo{ | ||
| name: "file-3", | ||
| }, | ||
| }, | ||
| excludes: []string{"file-1", "file-3"}, | ||
| want: []os.FileInfo{ | ||
| &fakeFileInfo{ | ||
| name: "file-2", | ||
| }, | ||
| }, | ||
| wantErr: false, | ||
| }, | ||
| } | ||
| for _, tc := range testcases { | ||
| t.Run(tc.name, func(t *testing.T) { | ||
| got, err := filterImageWatcherFiles(tc.files, tc.includes, tc.excludes) | ||
| assert.Equal(t, tc.wantErr, err != nil) | ||
| assert.Equal(t, tc.want, got) | ||
| }) | ||
| } | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think no
.pipedirectory is a normal case. In that case, is piped sending this error to the log system?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Exactly, it should be handled as not found case.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe we should compare with
os.IsNotExist.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Right