go.chromium.org/luci@v0.0.0-20240309015107-7cdc2e660f33/cv/internal/configs/validation/service.go (about) 1 // Copyright 2018 The LUCI Authors. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package validation 16 17 import ( 18 "google.golang.org/protobuf/encoding/prototext" 19 20 "go.chromium.org/luci/common/data/stringset" 21 "go.chromium.org/luci/common/errors" 22 "go.chromium.org/luci/common/retry/transient" 23 "go.chromium.org/luci/config/validation" 24 25 "go.chromium.org/luci/cv/internal/configs/prjcfg" 26 "go.chromium.org/luci/cv/internal/configs/srvcfg" 27 listenerpb "go.chromium.org/luci/cv/settings/listener" 28 ) 29 30 // validateListenerSettings validates a listener-settings file. 31 func validateListenerSettings(ctx *validation.Context, configSet, path string, content []byte) error { 32 ctx.SetFile(path) 33 cfg := listenerpb.Settings{} 34 if err := prototext.Unmarshal(content, &cfg); err != nil { 35 ctx.Error(err) 36 return nil 37 } 38 if err := cfg.Validate(); err != nil { 39 // TODO(crbug.com/1369189): enter context for the proto field path. 40 ctx.Error(err) 41 return nil 42 } 43 subscribedHosts := stringset.New(0) 44 for i, sub := range cfg.GetGerritSubscriptions() { 45 ctx.Enter("gerrit_subscriptions #%d", i+1) 46 host := sub.GetHost() 47 if !subscribedHosts.Add(host) { 48 ctx.Errorf("subscription already exists for host %q", host) 49 } 50 if sub.GetMessageFormat() == listenerpb.Settings_GerritSubscription_MESSAGE_FORMAT_UNSPECIFIED { 51 ctx.Enter("message_format") 52 ctx.Errorf("must be specified") 53 ctx.Exit() 54 } 55 ctx.Exit() 56 } 57 validateRegexp(ctx, "disabled_project_regexps", cfg.GetDisabledProjectRegexps()) 58 59 // Skip checking subscription configs on error. 60 // The error must be due to an invalid regex in `disabled_project_regexps`. 61 if isListenerEnabled, err := srvcfg.MakeListenerProjectChecker(&cfg); err == nil { 62 watchedHostsByPrj, err := prjcfg.GetAllGerritHosts(ctx.Context) 63 if err != nil { 64 return errors.Annotate(err, "GetAllGerritHosts").Tag(transient.Tag).Err() 65 } 66 for prj, hosts := range watchedHostsByPrj { 67 // Unless it's matched with one of disabled_project_regexps, 68 // all the Gerrit hosts must have a subscription config. 69 if !isListenerEnabled(prj) { 70 continue 71 } 72 73 ctx.Enter("project config %q", prj) 74 for h := range hosts { 75 if !subscribedHosts.Has(h) { 76 ctx.Errorf("watches %q, but there is no gerrit_subscriptions for it", h) 77 } 78 } 79 ctx.Exit() 80 } 81 } 82 return nil 83 }