diff --git a/go.mod b/go.mod index a2f4f3ac..5f1f67dd 100644 --- a/go.mod +++ b/go.mod @@ -6,7 +6,7 @@ require ( github.com/AlecAivazis/survey/v2 v2.3.7 github.com/MakeNowJust/heredoc/v2 v2.0.1 github.com/OctopusDeploy/go-octodiff v1.0.0 - github.com/OctopusDeploy/go-octopusdeploy/v2 v2.108.1 + github.com/OctopusDeploy/go-octopusdeploy/v2 v2.112.1 github.com/bmatcuk/doublestar/v4 v4.4.0 github.com/briandowns/spinner v1.19.0 github.com/google/uuid v1.3.0 diff --git a/go.sum b/go.sum index 56c25587..267c49f3 100644 --- a/go.sum +++ b/go.sum @@ -46,8 +46,8 @@ github.com/Netflix/go-expect v0.0.0-20220104043353-73e0943537d2 h1:+vx7roKuyA63n github.com/Netflix/go-expect v0.0.0-20220104043353-73e0943537d2/go.mod h1:HBCaDeC1lPdgDeDbhX8XFpy1jqjK0IBG8W5K+xYqA0w= github.com/OctopusDeploy/go-octodiff v1.0.0 h1:U+ORg6azniwwYo+O44giOw6TiD5USk8S4VDhOQ0Ven0= github.com/OctopusDeploy/go-octodiff v1.0.0/go.mod h1:Mze0+EkOWTgTmi8++fyUc6r0aLZT7qD9gX+31t8MmIU= -github.com/OctopusDeploy/go-octopusdeploy/v2 v2.108.1 h1:THcIJGQyhhzSx8/b7ibYnyFlwktF8/U+xwXfC373N1U= -github.com/OctopusDeploy/go-octopusdeploy/v2 v2.108.1/go.mod h1:VkTXDoIPbwGFi5+goo1VSwFNdMVo784cVtJdKIEvfus= +github.com/OctopusDeploy/go-octopusdeploy/v2 v2.112.1 h1:a/UEgCu7F8BbY+95W10aQ5VYhlf5jP/LVigZOH0eu/k= +github.com/OctopusDeploy/go-octopusdeploy/v2 v2.112.1/go.mod h1:VkTXDoIPbwGFi5+goo1VSwFNdMVo784cVtJdKIEvfus= github.com/bmatcuk/doublestar/v4 v4.4.0 h1:LmAwNwhjEbYtyVLzjcP/XeVw4nhuScHGkF/XWXnvIic= github.com/bmatcuk/doublestar/v4 v4.4.0/go.mod h1:xBQ8jztBU6kakFMg+8WGxn0c6z1fTSPVIjEY1Wr7jzc= github.com/briandowns/spinner v1.19.0 h1:s8aq38H+Qju89yhp89b4iIiMzMm8YN3p6vGpwyh/a8E= diff --git a/pkg/cmd/release/create/create.go b/pkg/cmd/release/create/create.go index 9c79f4dc..72d08abb 100644 --- a/pkg/cmd/release/create/create.go +++ b/pkg/cmd/release/create/create.go @@ -393,9 +393,15 @@ func BuildPackageVersionBaselineForChannel(octopus *octopusApiClient.Client, dep for _, rule := range channel.Rules { for _, ap := range rule.ActionPackages { if ap.PackageReference == packageRef.PackageReferenceName && ap.DeploymentAction == packageRef.ActionName { - // this rule applies to our step/packageref combo + // this rule applies to our step/packageref combo. + // VersionRange, Tag/pre-release and VersionTagRegex are always applied together, + // regardless of strategy; VersioningStrategy only changes ordering (publish-date + // vs SemVer), not which versions satisfy the rule. (empty fields are dropped by + // the query's omitempty uri tags) query.PreReleaseTag = rule.Tag query.VersionRange = rule.VersionRange + query.VersionTagRegex = rule.VersionTagRegex + query.VersioningStrategy = rule.VersioningStrategy // the octopus server won't let the same package be targeted by more than one rule, so // once we've found the first matching rule for our step+package, we can stop looping break rulesLoop diff --git a/pkg/cmd/release/create/create_test.go b/pkg/cmd/release/create/create_test.go index 864ae37e..65ee97c7 100644 --- a/pkg/cmd/release/create/create_test.go +++ b/pkg/cmd/release/create/create_test.go @@ -2284,6 +2284,73 @@ func TestReleaseCreate_BuildPackageVersionBaseline(t *testing.T) { }, packageVersions) }) + t.Run("sends all version-rule filters together along with versioningStrategy, regardless of strategy", func(t *testing.T) { + // VersionRange, Tag/pre-release and VersionTagRegex are always applied together; VersioningStrategy + // only changes ordering (publish-date vs SemVer), not which versions satisfy the rule. So even with + // MostRecentlyPublished set, an accompanying VersionRange and Tag must still be sent. + api := testutil.NewMockHttpServer() + processTemplate := &deployments.DeploymentProcessTemplate{ + Packages: []releases.ReleaseTemplatePackage{ + { + ActionName: "Deploy", + FeedID: externalFeedID, + PackageID: "my-app", + PackageReferenceName: "my-app-on-deploy", + IsResolvable: true, + }, + }, + Resource: resources.Resource{}, + } + + channel := fixtures.NewChannel(spaceID, "Channels-1", "Default", "Projects-1") + channel.Rules = []channels.ChannelRule{ + { + VersionRange: "1.0", + Tag: "beta", + VersioningStrategy: "MostRecentlyPublished", + VersionTagRegex: "^feature-", + ActionPackages: []octopusPackages.DeploymentActionPackage{ + {DeploymentAction: "Deploy", PackageReference: "my-app-on-deploy"}, + }, + }, + } + + receiver := testutil.GoBegin2(func() ([]*packages.StepPackageVersion, error) { + defer api.Close() + octopus, _ := octopusApiClient.NewClient(testutil.NewMockHttpClientWithTransport(api), serverUrl, placeholderApiKey, "") + return create.BuildPackageVersionBaselineForChannel(octopus, processTemplate, channel) + }) + + api.ExpectRequest(t, "GET", "/api/").RespondWith(rootResource) + api.ExpectRequest(t, "GET", "/api/spaces").RespondWith(rootResource) + + api.ExpectRequest(t, "GET", "/api/Spaces-1/feeds?ids=Feeds-1001&take=1").RespondWith(&feeds.Feeds{Items: []feeds.IFeed{ + &feeds.FeedResource{Name: "External Nuget", FeedType: feeds.FeedTypeNuGet, Resource: resources.Resource{ + ID: externalFeedID, + Links: map[string]string{ + constants.LinkSearchPackageVersionsTemplate: "/api/Spaces-1/feeds/Feeds-1001/packages/versions{?packageId,take,skip,includePreRelease,versionRange,preReleaseTag,versioningStrategy,versionTagRegex,filter,includeReleaseNotes}", + }}}, + }}) + + // all four filters must be sent; the client emits query params in alphabetical order + api.ExpectRequest(t, "GET", "/api/Spaces-1/feeds/Feeds-1001/packages/versions?packageId=my-app&preReleaseTag=beta&take=1&versionRange=1.0&versionTagRegex=%5Efeature-&versioningStrategy=MostRecentlyPublished").RespondWith(&resources.Resources[*octopusPackages.PackageVersion]{ + Items: []*octopusPackages.PackageVersion{ + {PackageID: "my-app", Version: "feature-login-42"}, + }, + }) + + packageVersions, err := testutil.ReceivePair(receiver) + assert.Nil(t, err) + assert.Equal(t, []*packages.StepPackageVersion{ + { + PackageID: "my-app", + ActionName: "Deploy", + Version: "feature-login-42", + PackageReferenceName: "my-app-on-deploy", + }, + }, packageVersions) + }) + t.Run("still returns a value if the server returns zero available packages", func(t *testing.T) { // note: channel rules can affect which packages the server returns so there might be zero, // but either way the server returns zero items, which is the code path we are testing, so channel rules aren't relevant here