@@ -2,7 +2,9 @@ package lifecycle
22
33import (
44 "encoding/json"
5+ "fmt"
56 artifactoryAuth "github.com/jfrog/jfrog-client-go/artifactory/auth"
7+ "github.com/jfrog/jfrog-client-go/artifactory/services/utils"
68 "github.com/jfrog/jfrog-client-go/http/jfroghttpclient"
79 lifecycle "github.com/jfrog/jfrog-client-go/lifecycle/services"
810 "github.com/stretchr/testify/assert"
@@ -12,6 +14,11 @@ import (
1214 "time"
1315)
1416
17+ const (
18+ rbManifestName = "release-bundle.json.evd"
19+ releaseBundlesV2 = "release-bundles-v2"
20+ )
21+
1522var testRb = lifecycle.ReleaseBundleDetails {
1623 ReleaseBundleName : "bundle-test" ,
1724 ReleaseBundleVersion : "1.2.3" ,
@@ -285,3 +292,120 @@ func TestIsReleaseBundleExistWithProject(t *testing.T) {
285292 assert .NoError (t , err )
286293 assert .False (t , exist )
287294}
295+
296+ func TestReleaseBundleAnnotate (t * testing.T ) {
297+ mockServer , rbService := createMockServer (t , func (w http.ResponseWriter , r * http.Request ) {
298+ if r .RequestURI == "/" + lifecycle .GetReleaseBundleSetTagApi (testRb ) {
299+ w .WriteHeader (http .StatusOK )
300+ _ , err := w .Write ([]byte (`{
301+ {
302+ "repository_key": "release-bundles-v2",
303+ "release_bundle_name": "bundle-test",
304+ "release_bundle_version": "1.2.3",
305+ "release_bundle_tag" : "bundle-tag"
306+ }
307+ }` ))
308+ assert .NoError (t , err )
309+ }
310+ if r .RequestURI == "/artifactory/" + lifecycle .PropertiesBaseApi {
311+ w .WriteHeader (http .StatusOK ) // Status 201
312+ writeMockStatusResponse (t , w , map [string ]interface {}{"message" : "Created" , "status" : "201" })
313+ }
314+ })
315+ defer mockServer .Close ()
316+ properties := "environment=qa335;buildNumber=335"
317+ annotateOperationParams := buildAnnotationOperationParams (testRb , "default" , "bundle-tag" , properties ,
318+ "environment" , mockServer .URL )
319+ err := rbService .AnnotateReleaseBundle (annotateOperationParams )
320+ assert .NoError (t , err )
321+ }
322+
323+ func testAnnotate (t * testing.T , projectKey , tag , properties , delProperties string , expectError bool ) {
324+ mockServer , rbService := createMockServer (t , func (w http.ResponseWriter , r * http.Request ) {
325+ if r .RequestURI == "/" + lifecycle .GetReleaseBundleSetTagApi (testRb ) {
326+ w .WriteHeader (http .StatusOK )
327+ }
328+ if r .RequestURI == "/artifactory/" + lifecycle .PropertiesBaseApi {
329+ w .WriteHeader (http .StatusNoContent ) // Status 204
330+ writeMockStatusResponse (t , w , map [string ]interface {}{"message" : "Created" , "status" : "201" })
331+ }
332+ if r .RequestURI == "/artifactory/" + lifecycle .PropertiesBaseApi {
333+ w .WriteHeader (http .StatusNoContent ) // Status 200
334+ }
335+ })
336+ defer mockServer .Close ()
337+ annotateOperationParams := buildAnnotationOperationParams (testRb , projectKey , tag , properties , delProperties ,
338+ mockServer .URL )
339+ err := rbService .AnnotateReleaseBundle (annotateOperationParams )
340+ if expectError {
341+ assert .Error (t , err )
342+ return
343+ }
344+ assert .NoError (t , err )
345+ }
346+
347+ func TestReleaseBundleAnnotationCases (t * testing.T ) {
348+ testCases := []struct {
349+ name string
350+ projectKey string
351+ tag string
352+ properties string
353+ delProperties string
354+ expectError bool
355+ }{
356+ {"tag, properties, del-prop are not empty, project are empty" , "" , "bundle-tag" , "prop1=1;prop2=2" , "prop1" , false },
357+ {"tag, property, del-prop are not empty, project is default" , "default" , "bundle-tag" , "prop1=1;prop2=2" , "prop1" , false },
358+ {"tag is empty, del-prop is empty" , "default" , "" , "prop1=1;prop2=2" , "" , false },
359+ {"property is empty, del-prop is empty, tag isn't empty, project is default" , "default" , "bundle-tag" , "" , "" , false },
360+ {"property is empty" , "project" , "bundle-tag" , "" , "" , false },
361+ {"property is one pair, tag isn't empty" , "project" , "bundle-tag" , "prop1=1" , "prop1" , false },
362+ {"property is one pair, tag is empty" , "project" , "" , "prop1=1" , "" , false },
363+ }
364+
365+ for _ , test := range testCases {
366+ t .Run (test .name , func (t * testing.T ) {
367+ testAnnotate (t , test .projectKey , test .tag , test .properties , test .delProperties , test .expectError )
368+ })
369+ }
370+ }
371+
372+ func buildAnnotationOperationParams (rbDetails lifecycle.ReleaseBundleDetails , projectKey , bundleTag , properties , delProperties ,
373+ artUrl string ) lifecycle.AnnotateOperationParams {
374+ props , _ := utils .ParseProperties (properties )
375+ annotateOperationParams := lifecycle.AnnotateOperationParams {
376+ RbTag : lifecycle.RbAnnotationTag {
377+ Tag : bundleTag ,
378+ Exist : true ,
379+ },
380+ RbProps : lifecycle.RbAnnotationProps {
381+ Properties : props .ToMap (),
382+ Exist : true ,
383+ },
384+ RbDetails : rbDetails ,
385+ QueryParams : lifecycle.CommonOptionalQueryParams {
386+ ProjectKey : projectKey ,
387+ },
388+ PropertyParams : lifecycle.CommonPropParams {
389+ Path : resolveManifestPath (projectKey , rbDetails .ReleaseBundleName , rbDetails .ReleaseBundleVersion ),
390+ Recursive : false ,
391+ },
392+ RbDelProps : lifecycle.RbDelProps {
393+ Keys : delProperties ,
394+ Exist : true ,
395+ },
396+ ArtifactoryUrl : lifecycle.ArtCommonParams {
397+ Url : artUrl + "/artifactory/" ,
398+ },
399+ }
400+ return annotateOperationParams
401+ }
402+
403+ func resolveManifestPath (projectKey , bundleName , bundleVersion string ) string {
404+ return fmt .Sprintf ("%s/%s/%s/%s" , resolveRepoKey (projectKey ), bundleName , bundleVersion , rbManifestName )
405+ }
406+ func resolveRepoKey (project string ) string {
407+ if project == "" || project == "default" {
408+ return releaseBundlesV2
409+ }
410+ return fmt .Sprintf ("%s-%s" , project , releaseBundlesV2 )
411+ }
0 commit comments