@@ -31,9 +31,14 @@ type DiffIncludePackage struct {
3131 // Upgrade graphs from all channels in the named package containing a version
3232 // from this field are included.
3333 AllChannels DiffIncludeChannel
34+ // The semver range of bundle versions.
35+ // Package range setting is mutually exclusive with channel range/bundles/version
36+ // settings.
37+ Range semver.Range
3438}
3539
36- // DiffIncludeChannel specifies a channel, and optionally bundles and bundle versions to include.
40+ // DiffIncludeChannel specifies a channel, and optionally bundles and bundle versions
41+ // (or version range) to include.
3742type DiffIncludeChannel struct {
3843 // Name of channel.
3944 Name string
@@ -42,13 +47,83 @@ type DiffIncludeChannel struct {
4247 // Bundles are bundle names to include.
4348 // Set this field only if the named bundle has no semantic version metadata.
4449 Bundles []string
50+ // The semver range of bundle versions.
51+ // Range setting is mutually exclusive with Versions and Bundles settings.
52+ Range semver.Range
53+ }
54+
55+ func (dip DiffIncludePackage ) Validate () error {
56+ var errs []error
57+ if dip .Name == "" {
58+ errs = append (errs , fmt .Errorf ("missing package name" ))
59+ }
60+
61+ var isChannelSet bool
62+ for _ , ch := range dip .Channels {
63+ isChannelSet = ch .isChannelSet ()
64+ err := ch .Validate ()
65+ if err != nil {
66+ errs = append (errs , err )
67+ }
68+ }
69+
70+ isChannelSet = dip .AllChannels .isChannelSet ()
71+ if isChannelSet && dip .Range != nil {
72+ errs = append (errs , fmt .Errorf ("package range setting is mutually exclusive with channel versions/bundles/range settings" ))
73+ }
74+
75+ if len (errs ) != 0 {
76+ return fmt .Errorf ("invalid DiffIncludePackage config for package %q:\n %v" , dip .Name , utilerrors .NewAggregate (errs ))
77+ }
78+ return nil
79+ }
80+
81+ // isChannelSet returns true if at least one of Range/Bundles/Versions is set
82+ func (dic DiffIncludeChannel ) isChannelSet () bool {
83+ return dic .Range != nil || len (dic .Versions ) != 0 || len (dic .Bundles ) != 0
84+ }
85+
86+ func (dic DiffIncludeChannel ) Validate () error {
87+ var errs []error
88+ if dic .Name == "" {
89+ errs = append (errs , fmt .Errorf ("missing channel name" ))
90+ }
91+
92+ if dic .Range != nil && (len (dic .Versions ) != 0 || len (dic .Bundles ) != 0 ) {
93+ errs = append (errs , fmt .Errorf ("Channel %q: range and versions/bundles are mutually exclusive" , dic .Name ))
94+ }
95+
96+ if len (errs ) != 0 {
97+ return fmt .Errorf ("invalid DiffIncludeChannel config for channel %q:\n %v" , dic .Name , utilerrors .NewAggregate (errs ))
98+ }
99+ return nil
100+ }
101+
102+ func (i DiffIncluder ) Validate () error {
103+ var errs []error
104+ for _ , pkg := range i .Packages {
105+ err := pkg .Validate ()
106+ if err != nil {
107+ errs = append (errs , err )
108+ }
109+ }
110+
111+ if len (errs ) != 0 {
112+ return fmt .Errorf ("invalid DiffIncluder config:\n %v" , utilerrors .NewAggregate (errs ))
113+ }
114+ return nil
45115}
46116
47117// Run adds all packages and channels in DiffIncluder with matching names
48118// directly, and all versions plus their upgrade graphs to channel heads,
49119// from newModel to outputModel.
50120func (i DiffIncluder ) Run (newModel , outputModel model.Model ) error {
51121 var includeErrs []error
122+ if err := i .Validate (); err != nil {
123+ includeErrs = append (includeErrs , err )
124+ return fmt .Errorf ("invalid DiffIncluder config:\n %v" , utilerrors .NewAggregate (includeErrs ))
125+ }
126+
52127 for _ , ipkg := range i .Packages {
53128 pkgLog := i .Logger .WithField ("package" , ipkg .Name )
54129 includeErrs = append (includeErrs , ipkg .includeNewInOutputModel (newModel , outputModel , pkgLog )... )
@@ -59,7 +134,7 @@ func (i DiffIncluder) Run(newModel, outputModel model.Model) error {
59134 return nil
60135}
61136
62- // includeNewInOutputModel adds all packages, channels, and versions ( bundles)
137+ // includeNewInOutputModel adds all packages, channels, and range (or versions/ bundles)
63138// specified by ipkg that exist in newModel to outputModel. Any package, channel,
64139// or version in ipkg not satisfied by newModel is an error.
65140func (ipkg DiffIncludePackage ) includeNewInOutputModel (newModel , outputModel model.Model , logger * logrus.Entry ) (ierrs []error ) {
@@ -72,26 +147,44 @@ func (ipkg DiffIncludePackage) includeNewInOutputModel(newModel, outputModel mod
72147 pkgLog := logger .WithField ("package" , newPkg .Name )
73148
74149 // No channels or versions were specified, meaning "include the full package".
75- if len (ipkg .Channels ) == 0 && len (ipkg .AllChannels .Versions ) == 0 && len (ipkg .AllChannels .Bundles ) == 0 {
150+ if len (ipkg .Channels ) == 0 && len (ipkg .AllChannels .Versions ) == 0 && len (ipkg .AllChannels .Bundles ) == 0 && ipkg . Range == nil {
76151 outputModel [ipkg .Name ] = newPkg
77152 return nil
78153 }
79154
80155 outputPkg := copyPackageNoChannels (newPkg )
81156 outputModel [outputPkg .Name ] = outputPkg
82-
83- // Add all channels to ipkg.Channels if bundles or versions were specified to include across all channels.
84- // skipMissingBundleForChannels's value for a channel will be true IFF at least one version is specified,
85- // since some other channel may contain that version.
86157 skipMissingBundleForChannels := map [string ]bool {}
87- if len (ipkg .AllChannels .Versions ) != 0 || len (ipkg .AllChannels .Bundles ) != 0 {
88- for newChName := range newPkg .Channels {
89- ipkg .Channels = append (ipkg .Channels , DiffIncludeChannel {
90- Name : newChName ,
91- Versions : ipkg .AllChannels .Versions ,
92- Bundles : ipkg .AllChannels .Bundles ,
93- })
94- skipMissingBundleForChannels [newChName ] = true
158+ if ipkg .Range != nil {
159+ if len (ipkg .Channels ) != 0 {
160+ for _ , ich := range ipkg .Channels {
161+ if ich .Range != nil {
162+ ierrs = append (ierrs , fmt .Errorf ("[package=%q channel=%q] range setting is mutually exclusive between package and channel" , newPkg .Name , ich .Name ))
163+ }
164+ }
165+ } else {
166+ // Add package range setting to all existing channels if there is no
167+ // channel setting in the config
168+ for newChName := range newPkg .Channels {
169+ ipkg .Channels = append (ipkg .Channels , DiffIncludeChannel {
170+ Name : newChName ,
171+ Range : ipkg .Range ,
172+ })
173+ }
174+ }
175+ } else {
176+ // Add all channels to ipkg.Channels if bundles or versions were specified to include across all channels.
177+ // skipMissingBundleForChannels's value for a channel will be true IFF at least one version is specified,
178+ // since some other channel may contain that version.
179+ if len (ipkg .AllChannels .Versions ) != 0 || len (ipkg .AllChannels .Bundles ) != 0 {
180+ for newChName := range newPkg .Channels {
181+ ipkg .Channels = append (ipkg .Channels , DiffIncludeChannel {
182+ Name : newChName ,
183+ Versions : ipkg .AllChannels .Versions ,
184+ Bundles : ipkg .AllChannels .Bundles ,
185+ })
186+ skipMissingBundleForChannels [newChName ] = true
187+ }
95188 }
96189 }
97190
@@ -103,7 +196,13 @@ func (ipkg DiffIncludePackage) includeNewInOutputModel(newModel, outputModel mod
103196 }
104197 chLog := pkgLog .WithField ("channel" , newCh .Name )
105198
106- bundles , err := getBundlesForVersions (newCh , ich .Versions , ich .Bundles , chLog , skipMissingBundleForChannels [newCh .Name ])
199+ var bundles []* model.Bundle
200+ var err error
201+ if ich .Range != nil {
202+ bundles , err = getBundlesForRange (newCh , ich .Range , chLog )
203+ } else {
204+ bundles , err = getBundlesForVersions (newCh , ich .Versions , ich .Bundles , chLog , skipMissingBundleForChannels [newCh .Name ])
205+ }
107206 if err != nil {
108207 ierrs = append (ierrs , fmt .Errorf ("[package=%q channel=%q] %v" , newPkg .Name , newCh .Name , err ))
109208 continue
@@ -173,11 +272,43 @@ func getBundlesForVersions(ch *model.Channel, vers []semver.Version, names []str
173272 return nil , fmt .Errorf ("bundles do not exist in channel: %s" , strings .TrimSpace (sb .String ()))
174273 }
175274
176- // Fill in the upgrade graph between each bundle and head.
177- // Regardless of semver order, this step needs to be performed
178- // for each included bundle because there might be leaf nodes
179- // in the upgrade graph for a particular version not captured
180- // by any other fill due to skips not being honored here.
275+ bundles , err = fillUpgradeGraph (ch , bundles , logger )
276+ if err != nil {
277+ return nil , err
278+ }
279+ return bundles , nil
280+ }
281+
282+ // getBundlesForRange returns all bundles matching the version range in vers
283+ // If the range is nil, return all bundles in the channel
284+ func getBundlesForRange (ch * model.Channel , vers semver.Range , logger * logrus.Entry ) (bundles []* model.Bundle , err error ) {
285+ // Short circuit when an empty range was specified, meaning "include the whole channel"
286+ if vers == nil {
287+ for _ , b := range ch .Bundles {
288+ bundles = append (bundles , b )
289+ }
290+ return bundles , nil
291+ }
292+
293+ for _ , b := range ch .Bundles {
294+ v , err := semver .Parse (b .Version .String ())
295+ if err != nil {
296+ return nil , fmt .Errorf ("unable to parse bunble version: %s" , err .Error ())
297+ }
298+ if vers (v ) {
299+ bundles = append (bundles , b )
300+ }
301+ }
302+
303+ return bundles , nil
304+ }
305+
306+ // fillUpgradeGraph fills in the upgrade graph between each bundle and head.
307+ // Regardless of semver order, this step needs to be performed
308+ // for each included bundle because there might be leaf nodes
309+ // in the upgrade graph for a particular version not captured
310+ // by any other fill due to skips not being honored here.
311+ func fillUpgradeGraph (ch * model.Channel , bundles []* model.Bundle , logger * logrus.Entry ) (bd []* model.Bundle , err error ) {
181312 head , err := ch .Head ()
182313 if err != nil {
183314 return nil , err
@@ -199,10 +330,10 @@ func getBundlesForVersions(ch *model.Channel, vers []semver.Version, names []str
199330 bundleSet [rb .Name ] = rb
200331 }
201332 }
333+
202334 for _ , b := range bundleSet {
203335 bundles = append (bundles , b )
204336 }
205-
206337 return bundles , nil
207338}
208339
0 commit comments